iiuniversitet.ruЦентр обучения нейросетямОткрыть каталог

SQL-запросы к Amazon Redshift

Выполняет SQL в Amazon Redshift, следит за статусом запроса, листает результаты и показывает базы, схемы и таблицы.

СкиллAnthropicClaudeApache-2.0Нужен терминалПроверка не требуется
Что делает
Выполняет SQL в Amazon Redshift, следит за статусом запроса, листает результаты и показывает базы, схемы и таблицы.
Когда брать
Когда нужно сделать запрос к Redshift (кластер или Serverless), узнать, какие таблицы есть в схеме, или проверить статус запроса.
Пример запроса
Покажи топ-20 событий по числу записей в таблице public.events с начала года.
Нужно подключить
терминал, доступ к Amazon Redshift

Входит в плагин redshift. В Cowork и Claude Code можно поставить плагин целиком.

Как включить

  1. Скачайте архив и распакуйте его.
  2. Положите папку redshift-api в ~/.claude/skills/.
  3. Откройте Claude Code и опишите задачу своими словами: Claude подхватит скилл по описанию.

Текст

---
name: redshift-api
description: Выполняй SQL-запросы в Amazon Redshift — отправляй команды, проверяй статус, листай результаты и просматривай базы данных, схемы и таблицы. Используй этот скилл всякий раз, когда пользователь хочет сделать запрос к Redshift (кластер с выделенными ресурсами или Serverless), спрашивает «какие таблицы есть в этой схеме», хочет проверить статус запроса либо упоминает `redshift-data`, идентификатор кластера Redshift или имя рабочей группы (workgroup), либо адрес `redshift-data.{region}.amazonaws.com`. Всегда начинай с этого скилла, когда работаешь с этим сервисом: его готовые скрипты и рецепты — самый быстрый путь.
---

В Amazon Redshift Data API каждый вызов — это POST на https://redshift-data.<region>.amazonaws.com/ с Content-Type: application/x-amz-json-1.1 и X-Amz-Target: RedshiftData.<Action> — путей в стиле REST здесь нет. API полностью асинхронный: отправляешь команду, получаешь Id, опрашиваешь DescribeStatement, пока команда не завершится, затем листаешь результаты через GetStatementResult — scripts/rs_query.sh (операция 1) проходит весь этот цикл за тебя. Те же вызовы работают и с кластерами с выделенными ресурсами, и с Serverless; отличается только поле с целью подключения.

Настройка запросов

Аутентификацию обеспечивает среда выполнения — запросы к этому API подписываются учётными данными, настроенными для рабочего пространства, так что настраивать ничего не нужно. Не пытайся получить ключи AWS или подписывать запросы самостоятельно. Постоянная ошибка AccessDeniedException означает, что для этого рабочего пространства учётные данные не настроены — сообщи об этом, а не разбирайся с авторизацией.

Две настройки реальны и обязательны:

1. Регион — он входит в имя хоста эндпоинта:

export AWS_DEFAULT_REGION="us-east-1"        # the region your cluster / workgroup is in

2. Цель подключения — к какому кластеру или рабочей группе и к какой базе данных подключается Data API. Выбери один вариант и положи соответствующие поля JSON в RS_TARGET; рецепты ниже подмешивают его в тело каждого запроса:

  • Serverless — передай WorkgroupName. Настроенная учётная запись сопоставляется с пользователем базы данных. Самый простой вариант.
  • Выделенный кластер, временные учётные данные — передай ClusterIdentifier и DbUser. Data API сам получает учётные данные базы данных.
  • Выделенный кластер или Serverless, Secrets Manager — передай SecretArn, указывающий на секрет с логином в базу данных.

Задай подходящий вариант один раз:

export RS_DATABASE="dev"
# Serverless:
export RS_TARGET='{"WorkgroupName": "my-workgroup"}'
# — or provisioned + temp creds:
# export RS_TARGET='{"ClusterIdentifier": "my-cluster", "DbUser": "my_user"}'
# — or either + Secrets Manager:
# export RS_TARGET='{"ClusterIdentifier": "my-cluster", "SecretArn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:rs-creds-AbCdEf"}'

Используемая ниже вспомогательная функция. Одна функция оборачивает эндпоинт, заголовки и имя действия. Заголовок Authorization — заглушка: среда выполнения заменяет её настоящей подписью.

rsapi() {
  local action="$1"
  curl -sS "https://redshift-data.${AWS_DEFAULT_REGION}.amazonaws.com/" \
    -H "Content-Type: application/x-amz-json-1.1" \
    -H "X-Amz-Target: RedshiftData.${action}" \
    -H "Authorization: placeholder" \
    -d "${2:?rsapi needs a JSON body as the second argument}"
}

Проверка подключения — выведи список баз данных. Ответ 200 с массивом Databases подтверждает, что рабочее пространство подключено, а цель подключения указана верно. Если произойдёт ошибка, в ней будет названо, на каком уровне сбой.

rsapi ListDatabases "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" \
  '$t + {Database: $db}')" | jq .

Основные операции

Любое действие, которое подключается к базе данных, принимает одно и то же тело с подмешанной целью — $t + {Database: $db, ...}. Ошибки приходят в виде {"__type": "<Exception>", "message": "..."} вместо ожидаемой структуры; если в ответе на любой вызов нет верхнеуровневого поля (Id, Status, Records и т. д.), значит, получена оболочка с ошибкой — выведи её и остановись.

1. Выполнить запрос (scripts/rs_query.sh)

Выполняй SQL через входящий в комплект скрипт (путь указан относительно папки этого скилла): он отправляет команду через ExecuteStatement, опрашивает DescribeStatement до конечного состояния, листает GetStatementResult по NextToken и расшифровывает типизированные объекты ячеек с одним ключом.

scripts/rs_query.sh \
  'SELECT event_name, COUNT(*) AS n FROM public.events
   WHERE event_date >= :start GROUP BY 1 ORDER BY 2 DESC LIMIT 20' \
  --param start=2024-01-01 --name top-events
  • SQL — это один аргумент (или стандартный ввод). Параметры подключения берутся из AWS_DEFAULT_REGION / RS_TARGET / RS_DATABASE, см. выше; --database переопределяет базу данных.
  • --param NAME=VALUE (можно повторять) подставляет значения в заполнители :NAME — значения всегда строки; приведением типов занимается база данных. --name задаёт StatementName, чтобы запрос был виден в ListStatements.
  • --max-rows N ограничивает число получаемых строк (по умолчанию 10000, 0 = все); --json выдаёт по одному JSON-объекту на строку вместо TSV с заголовком. Id команды, статус, длительность и число строк выводятся в stderr.
  • Коды завершения: 0 — успех, 1 — отправка не удалась или SQL завершился как FAILED/ABORTED (собственное сообщение API выводится в stderr), 2 — скрипт перестал ждать через --max-wait секунд (по умолчанию 600) — id команды выводится в stderr; продолжи по нему операцией 2.

Если скрипт выдаёт ошибку, прочитай его: это обычные curl + jq, — и разбирайся по references/api.md. Для BatchExecuteStatement и результатов подкоманд, повторного использования сессии (SessionKeepAliveSeconds / SessionId), ResultFormat: CSV, отмены или просмотра каталога используй действия ниже.

2. Продолжить команду по id (DescribeStatement → GetStatementResult)

Если скрипт завершился с кодом 2 (тайм-аут) или у тебя есть id команды из другого источника, опроси и получи результат напрямую:

rsapi DescribeStatement "$(jq -n --arg id "$ID" '{Id: $id}')" \
  | jq '{Status, Duration, ResultRows, HasResultSet, Error}'
rsapi GetStatementResult "$(jq -n --arg id "$ID" '{Id: $id}')" \
  | jq -r '.Records[]? | [.[] | if .isNull then null else to_entries[0].value end] | @tsv'
  • Status ∈ SUBMITTED, PICKED, STARTED, FINISHED, FAILED, ABORTED. Строки есть только у FINISHED с HasResultSet: true; FAILED несёт SQL-ошибку в .Error. Duration указывается в наносекундах.
  • Ячейки результата — типизированные объекты с одним ключом (см. подвох в разделе «Обработка ошибок»); названия и типы столбцов находятся в .ColumnMetadata на первой странице. Следующие страницы листаются по NextToken — параметра размера страницы нет; DescribeStatement.ResultRows сразу показывает общее число строк.

3. Отменить выполняющуюся команду (CancelStatement)

rsapi CancelStatement "$(jq -n --arg id "$ID" '{Id: $id}')" | jq .
# {"Status": true} on success — best-effort, check DescribeStatement to confirm.

4. Выполнить несколько команд одним вызовом (BatchExecuteStatement)

Все команды выполняются в одной транзакции — либо фиксируются все, либо откатываются все.

rsapi BatchExecuteStatement "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" '$t + {
    Database: $db,
    Sqls: ["CREATE TEMP TABLE tmp AS SELECT 1 AS x", "SELECT * FROM tmp"]
  }')" | jq '{Id}'

DescribeStatement для родительского Id возвращает массив SubStatements[]. У каждой подкоманды свой Id (родительский ID с суффиксом :1, :2 и т. д.), Status и HasResultSet — результаты каждой подкоманды получай отдельным вызовом GetStatementResult.

5. Список недавних команд (ListStatements)

rsapi ListStatements '{"MaxResults": 20, "Status": "ALL"}' \
  | jq '.Statements[] | {Id, StatementName, Status, QueryString: (.QueryString[0:80]), CreatedAt}'

Фильтр Status: SUBMITTED, PICKED, STARTED, FINISHED, FAILED, ABORTED, ALL — если его опустить, в списке будут только завершённые команды. MaxResults — от 0 до 100. RoleLevel по умолчанию равен true (включает команды всех, кто использует ту же роль IAM); поставь false, чтобы видеть только команды этой сессии.

6. Просмотр каталога (ListDatabases / ListSchemas / ListTables / DescribeTable)

Все четыре принимают тело с подмешанной целью. Шаблоны используют подстановочные знаки SQL LIKE (%, _).

  • **ListDatabases** — Databases[] (строки)
  • **ListSchemas** — SchemaPattern (необязательный) — Schemas[] (строки)
  • **ListTables** — SchemaPattern, TablePattern — Tables[] {schema, name, type} — type ∈ TABLE/VIEW/SYSTEM TABLE/GLOBAL TEMPORARY/LOCAL TEMPORARY/ALIAS/SYNONYM
  • **DescribeTable** — Schema, Table — ColumnList[] {name, typeName, nullable, length, precision}
rsapi ListTables "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" \
  '$t + {Database: $db, SchemaPattern: "public", TablePattern: "ev%"}')" | jq '.Tables'

Имена полей JSON пишутся в PascalCase (WorkgroupName, а не workgroup-name). Все четыре действия постраничные (NextToken). Структуру тела каждого действия см. в references/api.md.

Постраничная выдача

GetStatementResult, ListStatements, ListDatabases, ListSchemas, ListTables и DescribeTable работают по одной схеме: если данных больше, в ответе есть NextToken; передай его обратно как NextToken в теле следующего запроса. Останавливайся, когда его нет.

Лимиты запросов

  • Активные команды — до 500 активных (SUBMITTED/STARTED) на кластер или рабочую группу. Лишние отправки завершаются ошибкой ActiveStatementsExceededException.
  • Размер результата — 500 МБ на команду (после gzip) и 64 КБ на строку. Более крупные результаты вызывают ошибку; добавь LIMIT или используй UNLOAD ... TO 's3://...'.
  • Хранение результата — 24 часа; после этого GetStatementResult возвращает ResourceNotFoundException.
  • Длительность команды — не более 24 часов. Строка запроса — не более 100 КБ.
  • Частота вызовов API — фиксированные, не настраиваемые квоты TPS на аккаунт и регион: DescribeStatement 100, ExecuteStatement 30, GetStatementResult 20, BatchExecuteStatement 20, и только 3 TPS для CancelStatement, ListStatements, ListDatabases, ListSchemas, ListTables, DescribeTable. При превышении любой из них возвращается ThrottlingException (HTTP 400) — делай паузу и не опрашивай в тесном цикле.

Обработка ошибок

Ошибки приходят в виде {"__type": "<Exception>", "message": "..."} (HTTP 400/403/500). Различать их помогает поле __type.

  • **ValidationException (400)** — неверные параметры. Частые причины: переданы и ClusterIdentifier, и WorkgroupName либо ни один из них; нет Database; неверный регистр названия поля.
  • **ActiveStatementsExceededException (400)** — слишком много команд в работе. ListStatements с {"Status":"STARTED"} покажет, что выполняется.
  • **ActiveSessionsExceededException (400)** — открыто более 500 сессий. Перестань передавать SessionKeepAliveSeconds или дождись, пока простаивающие сессии истекут.
  • **ExecuteStatementException (500)** — отправка сорвалась до того, как команду увидела база данных: неверное имя кластера или рабочей группы, кластер недоступен, неверный DbUser. Проверь RS_TARGET.
  • **ResourceNotFoundException (400)** — ID команды неизвестен или ей больше 24 часов.
  • **BatchExecuteStatementException (500)** — одна из команд пакета не выполнилась; вся транзакция откатена. Посмотри SubStatements[].Error.
  • **DatabaseConnectionException / QueryTimeoutException** — вызов каталога не смог подключиться к базе данных или превысил время ожидания. Проверь, что цель работает; повтори.
  • **AccessDeniedException (403)** — учётным данным нужно право redshift-data:* на ARN кластера или рабочей группы, а также, в зависимости от режима подключения, redshift:GetClusterCredentials / redshift-serverless:GetCredentials / secretsmanager:GetSecretValue. Сообщи, какого права не хватает.
  • **InternalServerException (500)** — ExecuteStatement не идемпотентен, если не передать ClientToken — перед повтором записи проверь ListStatements.
  • **Status: FAILED в DescribeStatement** — SQL завершился ошибкой после отправки. Сообщение SQL смотри в .Error.

Два подвоха:

  • **Ответ 200 на ExecuteStatement ≠ запрос выполнился успешно.** SQL-ошибки проявляются позже, как Status: FAILED в DescribeStatement. Всегда опрашивай статус, прежде чем получать результаты.
  • Значения ячеек — типизированные объекты с одним ключом, а не голые значения. longValue — это число JSON, isNull: true — отдельная форма. Простое чтение .value ничего не вернёт, а цепочка jq // по типизированным ключам ломается на false/0. Используй to_entries[0].value.

Подробнее

В references/api.md — полный каталог: структура запроса и ответа каждого действия в PascalCase для «сырого» HTTP, формат привязки SqlParameter, поля ColumnMetadata, SubStatementData для пакетов, повторное использование сессии (SessionKeepAliveSeconds / SessionId) и таблица квот. Читай его, когда нужно действие, которого нет выше, или точная структура тела для «сырого» HTTP.

Перевод: iiuniversitet. Оригинал: https://github.com/anthropics/claude-tag-plugins/tree/main/redshift/skills/redshift-api, лицензия Apache-2.0. Изменения: перевод на русский язык.

Оригинал на английском
---
name: redshift-api
description: Run SQL against Amazon Redshift — submit statements, poll status, page through results, and browse databases/schemas/tables. Use this whenever the user wants to query Redshift (provisioned cluster or Serverless), ask "what tables are in this schema", check a query's status, or mentions `redshift-data`, a Redshift cluster identifier / workgroup name, or a `redshift-data.{region}.amazonaws.com` endpoint. Always start from this skill when interacting with this service — its bundled scripts and recipes are the fastest path.
---

In the Amazon Redshift Data API, every call is a `POST` to `https://redshift-data.<region>.amazonaws.com/` with
`Content-Type: application/x-amz-json-1.1` and `X-Amz-Target: RedshiftData.<Action>` — there are no
REST-style paths. The API is fully asynchronous: submit a statement, get back an `Id`, poll
`DescribeStatement` until done, then page results with `GetStatementResult` —
`scripts/rs_query.sh` (operation 1) drives that loop for you. The same calls work against
provisioned clusters and Serverless; only the connection-target field differs.

## Request setup

Authentication is handled by the runtime — requests to this API are signed with credentials
configured for the workspace, so there is nothing to set up. Do not try to obtain AWS keys or sign
requests yourself. A persistent `AccessDeniedException` means the credential isn't configured for
this workspace — report that instead of debugging auth.

Two pieces of configuration are real and required:

**1. Region** — it's part of the endpoint hostname:

```bash
export AWS_DEFAULT_REGION="us-east-1"        # the region your cluster / workgroup is in
```

**2. Connection target** — which cluster/workgroup and database the Data API connects to. Pick one
and put the matching JSON fields in `RS_TARGET`; the recipes below merge it into each request body:

- **Serverless** — pass `WorkgroupName`. The configured identity is mapped to a database user.
  Simplest.
- **Provisioned, temporary credentials** — pass `ClusterIdentifier` and `DbUser`. The Data API
  resolves database credentials under the hood.
- **Provisioned or Serverless, Secrets Manager** — pass `SecretArn` pointing to a secret that holds
  the database login.

Set whichever applies once:

```bash
export RS_DATABASE="dev"
# Serverless:
export RS_TARGET='{"WorkgroupName": "my-workgroup"}'
# — or provisioned + temp creds:
# export RS_TARGET='{"ClusterIdentifier": "my-cluster", "DbUser": "my_user"}'
# — or either + Secrets Manager:
# export RS_TARGET='{"ClusterIdentifier": "my-cluster", "SecretArn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:rs-creds-AbCdEf"}'
```

**The helper used below.** One function wraps the endpoint, the headers, and the action name. The
`Authorization` header is a placeholder — the runtime replaces it with a real signature.

```bash
rsapi() {
  local action="$1"
  curl -sS "https://redshift-data.${AWS_DEFAULT_REGION}.amazonaws.com/" \
    -H "Content-Type: application/x-amz-json-1.1" \
    -H "X-Amz-Target: RedshiftData.${action}" \
    -H "Authorization: placeholder" \
    -d "${2:?rsapi needs a JSON body as the second argument}"
}
```

**Sanity check** — list databases. A `200` with a `Databases` array confirms the workspace is wired
up and the connection target is right. An error names which layer failed.

```bash
rsapi ListDatabases "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" \
  '$t + {Database: $db}')" | jq .
```

## Core operations

Every action that connects to the database takes the same merged target body —
`$t + {Database: $db, ...}`. Errors come back as `{"__type": "<Exception>", "message": "..."}`
instead of the expected shape; on any call, an absent top-level field (`Id`, `Status`, `Records`, …)
means you got the error envelope — print it and stop.

### 1. Run a query (`scripts/rs_query.sh`)

Run SQL through the bundled script (path is relative to this skill's directory): it submits with
`ExecuteStatement`, polls `DescribeStatement` to a terminal state, pages `GetStatementResult` on
`NextToken`, and decodes the typed one-key cell objects.

```bash
scripts/rs_query.sh \
  'SELECT event_name, COUNT(*) AS n FROM public.events
   WHERE event_date >= :start GROUP BY 1 ORDER BY 2 DESC LIMIT 20' \
  --param start=2024-01-01 --name top-events
```

- SQL is one argument (or stdin). Instance specifics come from `AWS_DEFAULT_REGION` / `RS_TARGET` /
  `RS_DATABASE` above; `--database` overrides the database.
- `--param NAME=VALUE` (repeatable) binds `:NAME` placeholders — values are always strings; the
  database casts them. `--name` sets `StatementName` so the query shows up in `ListStatements`.
- `--max-rows N` caps fetched rows (default 10000, `0` = everything); `--json` emits one JSON object
  per row instead of TSV with a header. Statement id, status, duration, and row counts go to stderr.
- Exit codes: `0` success, `1` submit failed or SQL `FAILED`/`ABORTED` (the API's own message on
  stderr), `2` gave up waiting after `--max-wait` seconds (default 600) — the statement id is on
  stderr; resume it with operation 2.

If the script errors, read it — it's plain `curl` + `jq` — and debug against `references/api.md`.
For `BatchExecuteStatement` and sub-statement results, session reuse (`SessionKeepAliveSeconds` /
`SessionId`), `ResultFormat: CSV`, cancelling, or catalog browsing, use the actions below.

### 2. Resume a statement by id (`DescribeStatement` → `GetStatementResult`)

When the script exits 2 (timeout) or you have a statement id from elsewhere, poll and fetch
directly:

```bash
rsapi DescribeStatement "$(jq -n --arg id "$ID" '{Id: $id}')" \
  | jq '{Status, Duration, ResultRows, HasResultSet, Error}'
rsapi GetStatementResult "$(jq -n --arg id "$ID" '{Id: $id}')" \
  | jq -r '.Records[]? | [.[] | if .isNull then null else to_entries[0].value end] | @tsv'
```

- `Status` ∈ `SUBMITTED`, `PICKED`, `STARTED`, `FINISHED`, `FAILED`, `ABORTED`. Only `FINISHED`
  with `HasResultSet: true` has rows; `FAILED` carries the SQL error in `.Error`. `Duration` is
  **nanoseconds**.
- Result cells are typed one-key objects (see the gotcha under Error handling); column names/types
  are in `.ColumnMetadata` on the first page. Further pages follow `NextToken` — no page-size knob;
  `DescribeStatement.ResultRows` is the total up front.

### 3. Cancel a running statement (`CancelStatement`)

```bash
rsapi CancelStatement "$(jq -n --arg id "$ID" '{Id: $id}')" | jq .
# {"Status": true} on success — best-effort, check DescribeStatement to confirm.
```

### 4. Run multiple statements in one call (`BatchExecuteStatement`)

All statements run in one transaction — all commit or all roll back.

```bash
rsapi BatchExecuteStatement "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" '$t + {
    Database: $db,
    Sqls: ["CREATE TEMP TABLE tmp AS SELECT 1 AS x", "SELECT * FROM tmp"]
  }')" | jq '{Id}'
```

`DescribeStatement` on the parent `Id` returns a `SubStatements[]` array. Each sub-statement has its
own `Id` (the parent ID with a `:1`, `:2`, … suffix), `Status`, and `HasResultSet` — fetch each
sub-statement's results with its own `GetStatementResult` call.

### 5. List recent statements (`ListStatements`)

```bash
rsapi ListStatements '{"MaxResults": 20, "Status": "ALL"}' \
  | jq '.Statements[] | {Id, StatementName, Status, QueryString: (.QueryString[0:80]), CreatedAt}'
```

`Status` filter: `SUBMITTED`, `PICKED`, `STARTED`, `FINISHED`, `FAILED`, `ABORTED`, `ALL` — **only
finished statements are listed if you omit it**. `MaxResults` 0–100. `RoleLevel` defaults to `true`
(includes statements from anyone assuming the same IAM role); set `false` to see only this session's.

### 6. Browse the catalog (`ListDatabases` / `ListSchemas` / `ListTables` / `DescribeTable`)

All four take the merged target body. Patterns use SQL `LIKE` wildcards (`%`, `_`).

- **`ListDatabases`** — `Databases[]` (strings)
- **`ListSchemas`** — `SchemaPattern` (optional) — `Schemas[]` (strings)
- **`ListTables`** — `SchemaPattern`, `TablePattern` — `Tables[] {schema, name, type}` — `type` ∈ `TABLE`/`VIEW`/`SYSTEM TABLE`/`GLOBAL TEMPORARY`/`LOCAL TEMPORARY`/`ALIAS`/`SYNONYM`
- **`DescribeTable`** — `Schema`, `Table` — `ColumnList[] {name, typeName, nullable, length, precision}`

```bash
rsapi ListTables "$(jq -n --argjson t "$RS_TARGET" --arg db "$RS_DATABASE" \
  '$t + {Database: $db, SchemaPattern: "public", TablePattern: "ev%"}')" | jq '.Tables'
```

JSON field names are PascalCase (`WorkgroupName`, not `workgroup-name`). All four are paginated
(`NextToken`). See `references/api.md` for every action's body shape.

## Pagination

`GetStatementResult`, `ListStatements`, `ListDatabases`, `ListSchemas`, `ListTables`, and
`DescribeTable` all use the same scheme: the response carries `NextToken` when there's more; pass it
back as `NextToken` in the next request body. Stop when it's absent.

## Rate limits

- **Active statements** — up to 500 active (`SUBMITTED`/`STARTED`) per cluster or workgroup. Excess
  submits fail with `ActiveStatementsExceededException`.
- **Result size** — 500 MB per statement (after gzip) and 64 KB per row. Larger results fail; add a
  `LIMIT` or use `UNLOAD ... TO 's3://...'`.
- **Result retention** — 24 hours; after that `GetStatementResult` returns
  `ResourceNotFoundException`.
- **Statement duration** — 24 hours max. **Query string** — 100 KB max.
- **API rate** — fixed, non-adjustable TPS quotas per account/region: `DescribeStatement` 100,
  `ExecuteStatement` 30, `GetStatementResult` 20, `BatchExecuteStatement` 20, and only **3 TPS** for
  `CancelStatement`, `ListStatements`, `ListDatabases`, `ListSchemas`, `ListTables`, `DescribeTable`.
  Exceeding one returns `ThrottlingException` (HTTP 400) — back off and don't poll in a hot loop.

## Error handling

Errors return as `{"__type": "<Exception>", "message": "..."}` (HTTP 400/403/500). The `__type`
field is the discriminator.

- **`ValidationException` (400)** — Bad parameters. Common: passing both `ClusterIdentifier` and `WorkgroupName`, or neither; missing `Database`; wrong field casing.
- **`ActiveStatementsExceededException` (400)** — Too many in flight. `ListStatements` `{"Status":"STARTED"}` shows what's running.
- **`ActiveSessionsExceededException` (400)** — >500 open sessions. Stop passing `SessionKeepAliveSeconds` or wait for idle ones to expire.
- **`ExecuteStatementException` (500)** — Submission failed before the DB saw it — wrong cluster/workgroup name, unreachable cluster, bad `DbUser`. Check `RS_TARGET`.
- **`ResourceNotFoundException` (400)** — Statement ID unknown or > 24 h old.
- **`BatchExecuteStatementException` (500)** — One statement in the batch failed; whole transaction rolled back. Check `SubStatements[].Error`.
- **`DatabaseConnectionException` / `QueryTimeoutException`** — A catalog call couldn't reach the database or timed out. Check the target is up; retry.
- **`AccessDeniedException` (403)** — Credential needs `redshift-data:*` on the cluster/workgroup ARN plus, depending on connection mode, `redshift:GetClusterCredentials` / `redshift-serverless:GetCredentials` / `secretsmanager:GetSecretValue`. Report which is missing.
- **`InternalServerException` (500)** — `ExecuteStatement` is **not idempotent** unless you pass a `ClientToken` — check `ListStatements` before retrying a write.
- **`Status: FAILED` on `DescribeStatement`** — SQL failed after submission. Read `.Error` for the SQL message.

Two gotchas:

- **`ExecuteStatement` returning 200 ≠ the query succeeded.** SQL errors only surface later as
  `Status: FAILED` on `DescribeStatement`. Always poll before fetching results.
- **Cell values are typed one-key objects**, not bare values. `longValue` is a JSON number,
  `isNull: true` is a distinct shape. A naive `.value` read returns nothing, and chaining jq `//`
  across the typed keys breaks on `false`/`0`. Use `to_entries[0].value`.

## Going deeper

`references/api.md` has the complete catalog — every action's request/response shape in PascalCase
for raw HTTP, the `SqlParameter` binding format, the `ColumnMetadata` fields, `SubStatementData` for
batches, session reuse (`SessionKeepAliveSeconds` / `SessionId`), and the quota table. Read it when
you need an action not covered above or the exact raw-HTTP body shape.

Источник: anthropics/claude-tag-plugins / redshift / redshift-api ↗. Ссылка проверена 2026-10-10.