#### Description
- Every user-controlled field name that reaches generated SQL goes
through the new `pkg/clickhousesql` package (`Identifier`,
`StringLiteral`, `Literal`, `LikePattern`): map reads and `mapContains`,
JSON sub-column paths and the JSON body access plan, labels, fingerprint
labels, materialized column names, select aliases, group-by and order-by
references, the legacy string-body JSONPath, and the raw SQL in the
trace funnel, trace detail and infra monitoring modules. Filter
expressions built from request or telemetry values use
`querybuilder.FilterStringLiteral`. The same package now also renders
dashboard variable values in the querier, LIKE patterns in the metadata
store and label lists in the PromQL transpiler, which each had their own
escaping.
- A `$` followed by a digit, `{` or `?` is written as `\x24`, which
ClickHouse decodes in identifiers and literals. Those are the forms the
tools react to: go-sqlbuilder resolves `$0` in a compiled fragment to
its own WHERE clause and recurses until the stack overflows, and
clickhouse-go rejects a query mixing `$<digits>` with `?` arguments. Any
other `$` stays literal, so materialized column names keep their `$$`
and render exactly as before; a key like `http.2xx` becomes ``
`attribute_string_http$\x242xx` `` instead of failing in the driver.
- Compiled sqlbuilder fragments (Select, GroupBy, OrderBy, raw Where
text) are wrapped with `sqlbuilder.Escape`; the metrics builder escapes
its compiled time-series subquery, which is compiled a second time when
joined.
- The raw statement validator (`ErrIfStatementIsNotValid`,
`LogIfStatementIsNotValid`) moves from
`pkg/querybuilder/clickhouse_sql.go` to
`pkg/clickhousesql/statement.go`. Its `Code*` identifiers drop the
`ClickHouseSQL` prefix; the code strings are unchanged.
- Unit tests round-trip the helpers over hostile names and drive them
through the modules' raw SQL;
`tests/integration/tests/queriercommon/08_field_name_quoting.py` and
`querier_json_body/07_field_name_quoting.py` query such names through
the logs, traces and metrics builders against a real ClickHouse.
#### Additional Information
- `docs/contributing/go/clickhousesql.md` documents the quoting
functions, where `sqlbuilder.Escape` belongs, the `$` rule and the
statement validator; `.claude/rules/go-contrib.md` points at it.
- `pkg/clickhousesql` is a leaf package so `telemetrytypes` (JSON access
plan) and `querybuilder` share one implementation without a cycle.
- For names without special characters the generated SQL is byte
identical.
- Not covered here: the legacy v3/v4 query_range builders and the
`pkg/query-service/utils` quoting helpers (`QuoteEscapedString`,
`QuoteEscapedStringForContains`, `ClickHouseFormattedValue`,
`AddBackTickToFormatTag`), the collector's `JSONSubColumnIndexExpr`, and
aggregation arguments naming a key that contains a backtick (rejected by
the SQL parser, a 500 as before).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
A numeric coercion yields seconds since epoch, so max(timestamp) came back
as 1758113657.04 and the third-party APIs "Last Seen" rendered as January
1970. Both rules key on the physical column type, since no FieldDataType
denotes a timestamp.
- a time column is never coerced: it reaches the aggregate in its native
type and the driver returns a time.Time
- a bare `timestamp` resolves to the intrinsic column alone; a same-named
numeric attribute no longer joins the candidate union, where the mixed
branches failed with "no supertype for DateTime64, Float64"
- the exists guard leaves the String bucket: `timestamp <> ''` becomes a
typed epoch-zero comparison, verified equivalent on ClickHouse 25.5
including a non-UTC server timezone
- max/min/quantile/count keep working; sum/avg and the rate_* variants now
fail at the database instead of returning a rescaled number, pinned by
integration tests until they are rejected up front
- tests/fixtures/traces.py wrote kind_string as the enum member name
("SPAN_KIND_CLIENT"), so any feature filtering on it matched nothing; it
now maps the six kinds to the exporter's form ("Client")
- Last Seen assertions pin the encoding and the exact instant, rather than
accepting either an RFC 3339 string or epoch millis
- drop the /overview/domain integration tests and the fixture surface that
served only that route; the endpoint is no longer used
A span/log query that aggregates or filters a numeric intrinsic column
(e.g. duration_nano) failed with ClickHouse NO_COMMON_TYPE (386) when a
same-named, type-consistent attribute existed in the metadata: field-key
resolution unioned the intrinsic column with the attribute into a multiIf/OR
whose branches had incompatible types (UInt64 intrinsic vs Float64 attribute).
This broke /api/v1/span_percentile on affected tenants.
- fallback_expr: DataTypeCollisionHandledFieldName now handles the unspecified
data type in the projection/aggregation path (operator Unknown), coercing the
column so collision multiIf branches share a supertype. Comparison contexts
are left bare so the column index stays usable.
- telemetrytraces/condition_builder: run collision handling for duration_nano
(so a same-named string attribute is cast in comparisons) and coerce numeric
duration values to int64, keeping the intrinsic comparison bare/index-friendly
while preserving the duration-string QoL parsing.
- tests: add a type-consistent "collision" trace_noise variant; cover it in the
percentile aggregation test and add a duration_nano QoL filter regression test.
* fix: convert key not found to warnings
* fix(logs): has-family body-only errors, not-found warnings, and condition-builder cleanup
- has/hasAny/hasAll/hasToken on a non-body key now return "supports only body
JSON search" (both modes); a not-found body path warns and queries the
underlying data instead of 400 (JSON mode)
- capture the two has-family 500s (hasToken separator/whitespace needle;
hasAny/hasAll quoted int >= 2^32) as regression tests
- use telemetrytypes.NewTelemetryFieldKey for derived keys (fresh identity-only
keys, no stale resolved metadata) instead of struct copies of the field key
- rename ConditionForKeys -> ConditionFor and inline conditionsForKeys into it
across the builders; rename private conditionFor -> conditionForResolvedKey
- move the trace_noise fixture from queriertraces/conftest.py to fixtures/traces.py
* fix: convert trace_noise fixture to util
* chore: mark required and nullable in json tag, renamed methods, and added more functionality
* fix: unit test
* fix: cast clickhouse exceptions
* fix: go mod tidy
* fix: telemetrystore now returns explicit base errors
* fix: typo
* fix: added all changes
* fix: added nil check
* fix: update test files
* fix: addressed comments
* fix: change errors and suggestions to be non-nullable
* feat: extend error responses with new error struct
* fix: enriched error for dashboard api
* fix: merge issues
* fix: reverted dashboards changes and add for cloud integrations
* fix: delete file
* fix: add back file
* fix: added a helper
* fix: removed invlaid referencess
* fix: generate openapi
* fix: keeping additional along with suggestion
* Revert "fix: keeping additional along with suggestion"
This reverts commit be30e2ffd2.
* fix: added suggestions per additonal error
* fix: generate openapi
* fix: remove valid references
* fix: removeg valid references for select and group by and only did you mean is kept
* fix: unit test
* fix: use binding for deconding for both ee and community
* fix: trim down suggestions methods
* fix: added renamed methods and moved stuff around
* fix: typo
* fix: removed json decoder
* fix: added empty check
* fix: retain addtional
* fix: reverted re-structing of file
* chore: add json enabled as feature flag for FE
* fix: still using global bool
* feat: flagger integration in flow
* fix: flagger threaded into tests
* test: removed nil checks
* fix: minor changes
* chore: rename field
* chore: remove querybuilder helper
* fix: unit tests
* fix: correct env var
* fix: lint fix
* fix: lint
* chore: replace flag
* fix: handle empty not() expression
* fix: handle more cases
* fix: short circuit conditions and updated unit tests
* fix: revert commented code
* fix: added more unit tests
* fix: added integration tests
* fix: make py-lint and make py-fmt
* fix: moved from traces to logs for testing full text search
* fix: simplify code
* fix: added more unit tests
* fix: addressed comments
* fix: update comment
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
* fix: update unit test
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
* fix: update unit test
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
* fix: instead of using true, using a skip literal
* fix: unit test
* fix: update integration test
* fix: update unit for relevance
* fix: lint error
* fix: added a new literal for error condition, added more unit tests
* fix: merge issues
* fix: inline comments
* fix: update unit tests merging from main
* fix: make py-fmt and make py-lint
* fix: type handling
---------
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
* fix: let clickhouse handle string to number conversion
* fix: ignore casting if it's a comparison operator for number key
* fix: add integration tests
* fix: update comments
* fix: convert only if it's actually not a integrer with comparison operator
* fix: force convert to float when number
* fix: integration tests
* fix: correct the comment
* fix: update comment
---------
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
* feat(access-control): embed openfga in signoz
* feat(authz): rename access control to authz
* feat(authz): fix codeowners and go mod tidy
* feat(authz): fix lint
* feat(authz): update go version and move convertor to instrumentation
* feat(authz): some more lint issues
* feat(authz): some more lint issues
* feat(authz): some more lint issues
* feat(authz): fix more lint issues
* feat(authz): make logger converter interface
* fix: use lower and convert re2 to string in fulltext
* fix: minor error change
* fix: address comments
---------
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>