Align Postgres API timestamp grammar and detail-selector precision
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 32/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- openapi, postgres, rust
- Ambito
- api, backend-api-design, cloud
Direzione di ricerca
Inizia da clickhouse_cloud_openapi.json, nelle dichiarazioni dei timestamp di slowQueryPatterns e metrics indicate, quindi esegui la probe curl/Python in sola lettura fornita su un servizio Postgres popolato. Confronta le forme con secondi interi, millisecondi, offset e round-trip della risposta. Il lavoro è completato quando la grammatica dei timestamp e la semantica del selettore dei dettagli sono definite e il contratto OpenAPI, i valori emessi e il comportamento della CLI sono allineati.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Blocked on upstream — 2026-09-18
The owner confirmed this needs an upstream API/team change or authoritative contract and has raised the group with the team. Apply/retain the blocked label. This is outside the current CLI implementation queue.
Clear next step: Define accepted timestamp precision and whether the slow-query detail timestamp is an exact execution selector or a time window; make returned execution timestamps round-trip. The list-window normalization is already implemented in #938 / #967.
Keep this issue open. Add the upstream ticket or owner response when available; neither a ticket ID nor an individual assignee has been supplied in this discussion. After the upstream answer/fix, revalidate and scope any required library/CLI follow-up. Do not treat a local workaround or previous partial fix as completion of the backend issue.
Earlier scope and evidence (preserved)
Focused scope — 2026-09-15
Deferred until the direction below is resolved.
Retain the upstream grammar/response-roundtrip contract issue. A separate CLI list-window workaround is split below; detail timestamps must not be truncated blindly.
Acceptance criteria
Backend defines accepted precision and whether detail timestamp is an exact selector or reference window; emitted response timestamps round-trip.
Direction needed
Need upstream timestamp grammar and detail-selector semantics.
Split-out work
- #938 — Normalize Postgres slow-query list window timestamps (ready).
The focused scope above supersedes implementation suggestions and prior pass-specific deferrals below. Completed work and rejected assumptions remain recorded as history.
Original report and earlier audit history
Postgres timestamp parameters reject documented RFC 3339 values and response round-trips
Blocked on: Cloud API/OpenAPI owners aligning timestamp grammar and precision, and defining the detail timestamp selector.
Problem
The Postgres metrics and slow-query APIs document their timestamp inputs as RFC 3339 date-time strings, but the live API rejects conforming whole-second timestamps and equivalent numeric-offset timestamps. The slow-query detail API also rejects an execution timestamp returned by that same API when the response contains more than three fractional-second digits.
This blocks the CLI from faithfully passing through the documented API contract. The current PR stack can work around some cases by rewriting inputs to UTC with exactly three fractional digits, but doing that for the detail endpoint would discard response precision before the meaning of the timestamp selector is established.
Fresh read-only probes were run against an existing ClickHouse Cloud Postgres service on 2026-09-08 from 20:52 to 20:55 UTC. No service or configuration was changed, and no query text is included below.
Current published contract
The live OpenAPI document was retrieved from https://api.clickhouse.cloud/v1 at 2026-09-08T19:50:35.348403+00:00 (response Date: Tue, 08 Sep 2026 19:49:37 GMT).
- OpenAPI version:
3.1.2 - API info version:
1.0 - SHA-256:
c4811d18b26701aa61794b1d6ea1fa1b375493776bdac2c2033383849ba047d9 - The retrieved document is structurally identical to the spec vendored at clickhousectl commit
4c17bc55.
Relevant JSON pointers and declarations:
| JSON pointer | Declaration |
|---|---|
/paths/~1v1~1organizations~1{organizationId}~1postgres~1{postgresId}~1slowQueryPatterns/get/parameters/2 |
Required from_date; “Inclusive start of the time window (RFC 3339 date-time).”; type: string, format: date-time |
/paths/~1v1~1organizations~1{organizationId}~1postgres~1{postgresId}~1slowQueryPatterns/get/parameters/3 |
Required to_date; “Exclusive end of the time window (RFC 3339 date-time).”; type: string, format: date-time |
/paths/~1v1~1organizations~1{organizationId}~1postgres~1{postgresId}~1slowQueryPatterns~1{queryId}/get/parameters/7 |
Optional timestamp; “Timestamp of a specific execution (RFC 3339).”; type: string, format: date-time |
/components/schemas/PostgresQueryExecution/properties/timestamp |
Required response field; “Execution timestamp (RFC 3339).”; type: string, format: date-time |
/paths/~1v1~1organizations~1{organizationId}~1postgres~1{postgresId}~1metrics/get/parameters/2 |
Required from_date; RFC 3339 string with date-time format |
/paths/~1v1~1organizations~1{organizationId}~1postgres~1{postgresId}~1metrics/get/parameters/3 |
Required to_date; RFC 3339 string with date-time format |
The same declarations can be seen at slow-query list lines 14727–14743, slow-query detail lines 15001–15006, the response timestamp at lines 33264–33269, and metrics lines 14581–14596.
The OpenAPI format registry defines date-time by RFC 3339. RFC 3339 section 5.6 permits an optional fractional part of one or more digits and either Z or a numeric UTC offset in the timezone production. Therefore all of these inputs conform to the documented syntax:
2026-09-08T18:30:00Z2026-09-08T18:30:00.000Z2026-09-08T19:30:00.000+01:002026-09-08T19:53:58.9183Z
The spec supplies no pattern, example, fixed precision, or UTC-only restriction. OpenAPI formats can be treated as annotations by tooling, but the endpoint descriptions also explicitly promise RFC 3339, and the detail endpoint cannot accept its own documented response value.
Fresh direct-HTTP results
The paired list and metrics requests used identical time windows; only timestamp spelling changed.
| Endpoint | Input | HTTP | Sanitized response |
|---|---|---|---|
| Slow-query list | from_date=2026-09-08T18:30:00Z, to_date=2026-09-08T19:30:00Z |
400 | {"status":400,"error":"BAD_REQUEST: '2026-09-08T18:30:00Z'"} |
| Slow-query list | Same instants with .000Z |
200 | Envelope status=200; result is an array with one item |
| Slow-query list | Same instants as numeric offsets (19:30:00.000+01:00 to 20:30:00.000+01:00) |
400 | {"status":400,"error":"BAD_REQUEST: '2026-09-08T19:30:00.000+01:00'"} |
| Slow-query detail | No timestamp |
200 | Ten recent executions; first response timestamp was 2026-09-08T19:53:58.9183Z |
| Slow-query detail | Exact timestamp returned above, .9183Z |
400 | {"status":400,"error":"BAD_REQUEST: '2026-09-08T19:53:58.9183Z'"} |
| Slow-query detail | Same timestamp shortened to .918Z |
200 | Ten recent executions; response still included 2026-09-08T19:53:58.9183Z |
| Metrics | from_date=2026-09-08T18:30:00Z, to_date=2026-09-08T19:30:00Z |
400 | {"status":400,"error":"BAD_REQUEST: '2026-09-08T18:30:00Z'"} |
| Metrics | Same instants with .000Z, bucket_size_seconds=300 |
200 | Envelope status=200; result.metrics contained 11 metric series |
The detail result shows two problems at the contract boundary:
- The response serializer emits four fractional digits, while the request parser rejects that exact value.
- A millisecond-shortened value is accepted, but the response contains ten recent executions. It is therefore unclear whether
timestampis an exact execution selector, as its description suggests, or a cursor/reference time.
Reproduction
Choose an existing Postgres service with slow-query data. The dates below are the exact captured window; for a later rerun, replace them with a recent window while preserving the equivalent instants across Z, .000Z, and +01:00 forms. All calls are read-only.
This script keeps credentials out of command-line arguments and files. It builds curl's Basic authorization header from environment variables in memory, passes the curl config over stdin, URL-encodes query values, stores response bodies in a mode-0600 temporary file, and emits only sanitized fields.
set -eu
set +x
: "${CLICKHOUSE_CLOUD_API_KEY:?set CLICKHOUSE_CLOUD_API_KEY}"
: "${CLICKHOUSE_CLOUD_API_SECRET:?set CLICKHOUSE_CLOUD_API_SECRET}"
: "${ORGANIZATION_ID:?set ORGANIZATION_ID}"
: "${POSTGRES_ID:?set POSTGRES_ID}"
API_ROOT="${CLICKHOUSE_CLOUD_API_URL:-https://api.clickhouse.cloud/v1}"
POSTGRES_URL="${API_ROOT}/organizations/${ORGANIZATION_ID}/postgres/${POSTGRES_ID}"
umask 077
BODY="$(mktemp)"
trap 'rm -f "$BODY"' EXIT
auth_config() {
python3 - <<'PY'
import base64
import os
raw = (os.environ["CLICKHOUSE_CLOUD_API_KEY"] + ":" +
os.environ["CLICKHOUSE_CLOUD_API_SECRET"]).encode()
token = base64.b64encode(raw).decode("ascii")
print(f'header = "Authorization: Basic {token}"')
print("silent")
print("show-error")
PY
}
request() {
auth_config | curl --config - --get --output "$BODY" \
--write-out '%{http_code}' "$@"
}
# Documented whole-second RFC 3339 form: observed HTTP 400.
CODE="$(request "${POSTGRES_URL}/slowQueryPatterns" \
--data-urlencode 'from_date=2026-09-08T18:30:00Z' \
--data-urlencode 'to_date=2026-09-08T19:30:00Z' \
--data-urlencode 'limit=1')"
printf 'HTTP %s\n' "$CODE"
jq '{status,error}' "$BODY"
# Identical window with exactly milliseconds: observed HTTP 200.
CODE="$(request "${POSTGRES_URL}/slowQueryPatterns" \
--data-urlencode 'from_date=2026-09-08T18:30:00.000Z' \
--data-urlencode 'to_date=2026-09-08T19:30:00.000Z' \
--data-urlencode 'limit=1')"
printf 'HTTP %s\n' "$CODE"
jq '{status,result_type:(.result|type),result_count:(.result|length)}' "$BODY"
# Equivalent instants with an RFC 3339 numeric offset: observed HTTP 400.
CODE="$(request "${POSTGRES_URL}/slowQueryPatterns" \
--data-urlencode 'from_date=2026-09-08T19:30:00.000+01:00' \
--data-urlencode 'to_date=2026-09-08T20:30:00.000+01:00' \
--data-urlencode 'limit=1')"
printf 'HTTP %s\n' "$CODE"
jq '{status,error}' "$BODY"
# Metrics shows the same whole-second rejection.
CODE="$(request "${POSTGRES_URL}/metrics" \
--data-urlencode 'from_date=2026-09-08T18:30:00Z' \
--data-urlencode 'to_date=2026-09-08T19:30:00Z' \
--data-urlencode 'bucket_size_seconds=300')"
printf 'HTTP %s\n' "$CODE"
jq '{status,error}' "$BODY"
# Metrics comparison: identical interval with milliseconds, observed HTTP 200.
CODE="$(request "${POSTGRES_URL}/metrics" \
--data-urlencode 'from_date=2026-09-08T18:30:00.000Z' \
--data-urlencode 'to_date=2026-09-08T19:30:00.000Z' \
--data-urlencode 'bucket_size_seconds=300')"
printf 'HTTP %s\n' "$CODE"
jq '{status,metric_count:(.result.metrics|length)}' "$BODY"
For the response round-trip, append the following block to the same script; it reuses the helper and temporary file above. Supply a pattern ID and its required database/user/operation filters from a populated list result. Keep those identifiers local and do not print queryText; extract only the first response timestamp:
: "${QUERY_PATTERN_ID:?set QUERY_PATTERN_ID}"
: "${DB_NAME:?set DB_NAME}"
: "${DB_USER:?set DB_USER}"
: "${DB_OPERATION:?set DB_OPERATION}"
DETAIL_URL="${POSTGRES_URL}/slowQueryPatterns/${QUERY_PATTERN_ID}"
CODE="$(request "$DETAIL_URL" \
--data-urlencode "db_name=${DB_NAME}" \
--data-urlencode "db_user=${DB_USER}" \
--data-urlencode "db_operation=${DB_OPERATION}")"
printf 'HTTP %s\n' "$CODE"
EXECUTION_TIMESTAMP="$(jq -r '.result.recentExecutions[0].timestamp' "$BODY")"
printf 'timestamp=%s\n' "$EXECUTION_TIMESTAMP"
# Pass the response timestamp back without modification.
CODE="$(request "$DETAIL_URL" \
--data-urlencode "db_name=${DB_NAME}" \
--data-urlencode "db_user=${DB_USER}" \
--data-urlencode "db_operation=${DB_OPERATION}" \
--data-urlencode "timestamp=${EXECUTION_TIMESTAMP}")"
printf 'HTTP %s\n' "$CODE"
jq '{status,error}' "$BODY"
In the fresh probe, the first detail call returned timestamp=2026-09-08T19:53:58.9183Z; passing it back unchanged returned HTTP 400 with the body shown in the table.
Expected contract
One of these contract-level resolutions is needed:
- Accept every timestamp form currently documented as RFC 3339, including whole seconds, fractional seconds of arbitrary precision, numeric offsets, and timestamps emitted by the API itself; or
- If the API intentionally accepts only UTC with exactly millisecond precision, document and encode that narrower grammar explicitly, return response timestamps in the same grammar, and define how clients should handle precision loss.
For the detail endpoint, also define whether timestamp selects one exact execution or establishes a reference point/window. If it is exact, an accepted request should identify the selected execution and the server must define matching behavior when stored precision exceeds accepted request precision.
Upstream questions and unblock criteria
- Is the fixed
yyyy-MM-dd'T'HH:mm:ss.SSS'Z'parser intentional for all Postgres date parameters? - Should whole-second and numeric-offset RFC 3339 inputs be accepted, or should the OpenAPI contract be narrowed?
- What is the supported fractional precision, and why can detail responses currently emit precision that detail requests reject?
- Does detail
timestampselect an exact execution, act as a cursor, or only influence the recent-execution window?
The CLI is unblocked from pass-through behavior when the live implementation and OpenAPI document agree on accepted timestamp grammar and precision, response timestamps round-trip into the corresponding request, and detail selector semantics are documented and covered by API contract tests.
Relationship to existing clickhousectl issues
- clickhousectl #761 tracks the CLI-facing metrics failure. The PR stack works around it by normalizing metrics input to UTC with exactly three fractional digits and rejecting nonzero sub-millisecond precision. The fresh HTTP pair above confirms the upstream behavior still exists; this issue tracks the remaining API/spec contract rather than relabeling #761.
- clickhousectl #758 tracks fractional duration values being deserialized as integers. That client fix and the remaining OpenAPI duration-schema mismatch are separate from timestamp parsing and should not be conflated with this issue.
The remaining upstream duration-schema correction is tracked separately in #796.
- Lingua principale
- Rust
- Stelle
- 80
- Fork
- 9
- Merge medio
- 4g 13h
- PR unite (30g)
- 59
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di ClickHouse/clickhousectl
-
openapi-drift
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
ClickHouse/clickhousectl#1144 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Stop resolving the latest clickhousectl version through the GitHub APIForse già presa @sdairs l’ha presa 5 giorni fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 53/100
ClickHouse/clickhousectl#1142 ·
I maintainer di solito rispondono entro 1 giorno
-
Cloud access request negotiation: role discovery, OAuth org selection and approval flowForse già presa @balanza l’ha presa 5 giorni fa. Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
ClickHouse/clickhousectl#1131 ·
I maintainer di solito rispondono entro 1 giorno
-
Local Postgres: use the pg_clickhouse image and enable its extensionsForse già presa @sdairs l’ha presa 12 giorni fa. Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 55/100
ClickHouse/clickhousectl#1096 ·
I maintainer di solito rispondono entro 1 giorno
-
bug local
Difficoltà 3/5 1-2 giorni Idoneità per principianti 78/100
ClickHouse/clickhousectl#1077 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di ClickHouse/clickhousectl
Issue simili
-
Settings: the AI & Intelligence page cannot be scrolled (its Flickable has no viewport height)Apertaarea/desktop-shell P1-high
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
yantrikos/yantrik-os#998 ·
I maintainer di solito rispondono entro 1 giorno
-
bug P2
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
plrigaux/sysd-manager#85 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
dsx-ai-factory/infra-controller#8341 ·
I maintainer di solito rispondono entro 1 giorno
-
documentation
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
I maintainer di solito rispondono entro 1 giorno