ClickHouse / ClickHouse/ClickHouse

Quota KEYED BY normalized_query_hash: MAX errors limit never enforced

Open
#100,780 0 comments 0 reactions 1 assignee Claimed by @alexey-milovidov View on GitHub
bug comp-query-execution comp-rbac
Dominant language
C++
Stars
49.9k
Forks
9k
Avg merge
21h 32m
Merged PRs (30d)
515

Description

### Summary

When a quota is configured with `KEYED BY normalized_query_hash`, the `MAX errors` limit is silently never enforced — queries keep erroring indefinitely without ever receiving `QUOTA_EXCEEDED`.

This was introduced by PR #99586 ("Quota by normalized query hash").

### Root Cause

PR #99586 added per-hash interval checks via `usedForNormalizedQuery(hash, ERRORS, 0, true)` in `executeQuery.cpp`. However, the two places that **increment** the error counter were not updated:

- `logExceptionBeforeStart` (line ~858): `quota->used(QuotaType::ERRORS, 1, false)` — routes to **shared** session intervals
- Exception callback (line ~1965): `my_quota->used(QuotaType::ERRORS, 1, false)` — routes to **shared** session intervals

Both increment the shared session intervals, but `usedForNormalizedQuery` reads from the **per-hash** intervals. The per-hash ERRORS counter is therefore always 0, so `MAX errors` is never reached.

### Reproduction

```sql
-- Setup
CREATE USER u_errbug IDENTIFIED WITH no_password;
GRANT SELECT ON *.* TO u_errbug;
CREATE QUOTA q_errbug
KEYED BY normalized_query_hash
FOR INTERVAL 1 hour MAX errors = 2
TO u_errbug;

-- Run 5+ erroring queries as u_errbug (must use FROM to avoid system.one bypass)
-- Expected: QUOTA_EXCEEDED after 2 errors
-- Actual: all queries return FUNCTION_THROW_IF_VALUE_IS_NON_ZERO, quota never exceeded
SELECT throwIf(1, 'err') FROM numbers(1); -- query 1
SELECT throwIf(1, 'err') FROM numbers(1); -- query 2
SELECT throwIf(1, 'err') FROM numbers(1); -- query 3
SELECT throwIf(1, 'err') FROM numbers(1); -- query 4
SELECT throwIf(1, 'err') FROM numbers(1); -- query 5
```

### Expected Behavior

After 2 erroring queries with the same normalized hash, subsequent queries with that hash should receive `QUOTA_EXCEEDED`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.