Skip to content

Commit 08e1d4e

Browse files
committed
Address remaining CodeRabbit review feedback (rounds 2-3)
- Guard against empty array filter values producing invalid IN () SQL; short-circuit to match-nothing condition instead - Use +0 instead of (int) cast for query result values to preserve fractional aggregates (e.g. avg returns floats) - Add retry with exponential backoff to insert(), matching the existing read-path retry in query(), so transient network errors or 5xx/429 responses don't silently drop entire batches https://claude.ai/code/session_01UCN4sKD3Zkdbimn3QgTHSB
1 parent 790eaa9 commit 08e1d4e

1 file changed

Lines changed: 44 additions & 20 deletions

File tree

src/Usage/Adapter/ClickHouse.php

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,11 @@ private function buildFilters(array $filters, array &$params, int &$paramCounter
614614
$escaped = $this->esc($key);
615615

616616
if (is_array($value)) {
617+
if (empty($value)) {
618+
// Empty IN() is invalid SQL; match nothing
619+
$conditions[] = '0';
620+
continue;
621+
}
617622
$inParts = [];
618623
foreach ($value as $v) {
619624
$pn = 'p_' . $paramCounter++;
@@ -695,9 +700,9 @@ private function parseRows(string $result): array
695700
$row['tags'] = json_decode($row['tags'], true) ?? [];
696701
}
697702

698-
// Cast numeric fields
703+
// Cast numeric fields (use +0 to preserve decimals from avg/float aggregates)
699704
if (isset($row['value'])) {
700-
$row['value'] = (int) $row['value'];
705+
$row['value'] = $row['value'] + 0;
701706
}
702707
if (isset($row['count'])) {
703708
$row['count'] = (int) $row['count'];
@@ -802,10 +807,6 @@ private function insert(string $table, array $rows): void
802807
$queryParams = ['query' => "INSERT INTO {$escaped} FORMAT JSONEachRow"];
803808
$url = "{$scheme}://{$this->host}:{$this->port}/?" . http_build_query($queryParams);
804809

805-
$this->client->addHeader('X-ClickHouse-Database', $this->database);
806-
$this->client->addHeader('Content-Type', 'application/x-ndjson');
807-
$this->client->addHeader('Connection', 'keep-alive');
808-
809810
$jsonRows = array_map(function ($row) {
810811
$encoded = json_encode($row);
811812
if ($encoded === false) {
@@ -816,22 +817,45 @@ private function insert(string $table, array $rows): void
816817

817818
$body = implode("\n", $jsonRows);
818819

819-
try {
820-
$response = $this->client->fetch(
821-
url: $url,
822-
method: Client::METHOD_POST,
823-
body: $body,
824-
);
825-
826-
$httpCode = $response->getStatusCode();
827-
if ($httpCode !== 200) {
828-
$responseBody = $response->getBody();
829-
$responseBody = is_string($responseBody) ? $responseBody : '';
830-
throw new Exception("ClickHouse insert HTTP {$httpCode}: {$responseBody}");
820+
$attempt = 0;
821+
$lastException = null;
822+
823+
while ($attempt <= $this->maxRetries) {
824+
try {
825+
$this->client->addHeader('X-ClickHouse-Database', $this->database);
826+
$this->client->addHeader('Content-Type', 'application/x-ndjson');
827+
$this->client->addHeader('Connection', 'keep-alive');
828+
829+
try {
830+
$response = $this->client->fetch(
831+
url: $url,
832+
method: Client::METHOD_POST,
833+
body: $body,
834+
);
835+
} finally {
836+
$this->client->removeHeader('Content-Type');
837+
}
838+
839+
$httpCode = $response->getStatusCode();
840+
if ($httpCode !== 200) {
841+
$responseBody = $response->getBody();
842+
$responseBody = is_string($responseBody) ? $responseBody : '';
843+
throw new Exception("ClickHouse insert HTTP {$httpCode}: {$responseBody}");
844+
}
845+
846+
return;
847+
} catch (Exception $e) {
848+
$lastException = $e;
849+
if ($attempt < $this->maxRetries && $this->isRetryable($e)) {
850+
$attempt++;
851+
usleep($this->retryDelay * (2 ** ($attempt - 1)) * 1000);
852+
continue;
853+
}
854+
throw $e;
831855
}
832-
} finally {
833-
$this->client->removeHeader('Content-Type');
834856
}
857+
858+
throw $lastException ?? new Exception('Unknown insert error');
835859
}
836860

837861
// ─── Internal: Utilities ─────────────────────────────────────────

0 commit comments

Comments
 (0)