Created
November 2, 2025 22:16
-
-
Save kavirajk/102b90118dfca1e4eb52cc9ae9a79c04 to your computer and use it in GitHub Desktop.
Demo Zero Chunk bug with ClickHouse server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "bytes" | |
| "fmt" | |
| "io" | |
| "net/http" | |
| "os" | |
| "strings" | |
| "time" | |
| ) | |
| // This demonstrates how the client WOULD work if ClickHouse properly | |
| // terminated chunked encoding with 0\r\n\r\n | |
| func main() { | |
| url := "http://localhost:8123/?database=default&wait_end_of_query=0&max_threads=1" | |
| query := "SELECT throwIf(number=3, 'there is a exception') FROM system.numbers SETTINGS max_block_size=1 FORMAT Native" | |
| client := &http.Client{ | |
| Timeout: 120 * time.Second, | |
| } | |
| req, err := http.NewRequest("POST", url, strings.NewReader(query)) | |
| if err != nil { | |
| fmt.Fprintf(os.Stderr, "Error creating request: %v\n", err) | |
| os.Exit(1) | |
| } | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| fmt.Fprintf(os.Stderr, "Error making request: %v\n", err) | |
| os.Exit(1) | |
| } | |
| defer resp.Body.Close() | |
| // With proper chunked encoding, this would work! | |
| body, err := io.ReadAll(resp.Body) | |
| if err != nil { | |
| // Currently fails here with: unexpected EOF | |
| // Would work if ClickHouse sent 0\r\n\r\n terminator | |
| fmt.Fprintf(os.Stderr, "❌ Error reading body: %v\n", err) | |
| fmt.Fprintf(os.Stderr, " This happens because ClickHouse doesn't send proper chunk terminator!\n") | |
| fmt.Fprintf(os.Stderr, " Captured %d bytes before error\n", len(body)) | |
| os.Exit(1) | |
| } | |
| // If we got here, chunked encoding was proper | |
| fmt.Printf("✅ Successfully read complete response (%d bytes)\n", len(body)) | |
| // Save to file | |
| os.WriteFile("response.native", body, 0644) | |
| // Check for exception in the body | |
| if bytes.Contains(body, []byte("__exception__")) { | |
| fmt.Println("\n⚠️ Query completed with exception (streamed in body)") | |
| // Extract exception details | |
| exceptionStart := bytes.Index(body, []byte("__exception__")) | |
| if exceptionStart >= 0 { | |
| exceptionData := body[exceptionStart:] | |
| // Find the error code | |
| if codeIdx := bytes.Index(exceptionData, []byte("Code: ")); codeIdx >= 0 { | |
| errorLine := exceptionData[codeIdx:] | |
| endLine := bytes.Index(errorLine, []byte("\n")) | |
| if endLine > 0 { | |
| fmt.Printf("Exception: %s\n", errorLine[:endLine]) | |
| } | |
| } | |
| } | |
| os.Exit(1) | |
| } | |
| // Success - no exception | |
| fmt.Println("\n✅ Query completed successfully") | |
| fmt.Println("Data contains valid results") | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment