Skip to content

PromQL: Unary operator and simple functions#97510

Merged
nikitamikhaylov merged 11 commits intoClickHouse:masterfrom
vitlibar:promql-unary-operator-and-simple-functions
Feb 27, 2026
Merged

PromQL: Unary operator and simple functions#97510
nikitamikhaylov merged 11 commits intoClickHouse:masterfrom
vitlibar:promql-unary-operator-and-simple-functions

Conversation

@vitlibar
Copy link
Member

@vitlibar vitlibar commented Feb 20, 2026

Changelog category (leave one):

  • Not for changelog (changelog entry is not required)

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

PromQL: Unary operator and simple functions

Add support for unary operators + and - and also for simple functions taking one argument: vector(), scalar(), abs(), sin(), day_of_week(), etc.

Part of #89356

@clickhouse-gh
Copy link
Contributor

clickhouse-gh bot commented Feb 20, 2026

Workflow [PR], commit [e2bf850]

Summary:

@clickhouse-gh clickhouse-gh bot added the pr-not-for-changelog This PR should not be mentioned in the changelog label Feb 20, 2026
@vitlibar vitlibar added comp-promql Issues related to the PromQL support and TimeSeries table engine. and removed pr-not-for-changelog This PR should not be mentioned in the changelog labels Feb 20, 2026
@vitlibar vitlibar force-pushed the promql-unary-operator-and-simple-functions branch from c78b0c0 to 0bdb3dd Compare February 20, 2026 17:46
@clickhouse-gh clickhouse-gh bot added the pr-not-for-changelog This PR should not be mentioned in the changelog label Feb 20, 2026
@vitlibar vitlibar force-pushed the promql-unary-operator-and-simple-functions branch from 0bdb3dd to 01be3b2 Compare February 20, 2026 17:57
@vitlibar vitlibar requested a review from Copilot February 20, 2026 17:57
@vitlibar vitlibar marked this pull request as draft February 20, 2026 17:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands ClickHouse’s PromQL support by adding unary operators (+/-) and several “simple” single-argument functions (conversion, math, and date/time), together with new integration tests and some internal refactoring in the PromQL→SQL converter to support these features.

Changes:

  • Add unary operator handling and a central function dispatcher (applyFunction) to route PromQL functions to specific implementations.
  • Implement support for time(), pi(), vector(), scalar(), multiple math functions (e.g. abs, sin, sqrt, …) and date/time functions (e.g. day_of_week, month, year, …).
  • Update integration tests and adjust evaluation-range / SQL finalization behavior (including +Inf formatting in the HTTP API).

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/integration/test_prometheus_protocols/test_evaluation.py Adds test data and coverage for unary operators and new functions.
src/Storages/TimeSeries/PrometheusQueryToSQL/fromSelector.cpp Removes empty-range short-circuit; uses node range for selector bounds.
src/Storages/TimeSeries/PrometheusQueryToSQL/fromFunctionTime.h / .cpp Implements time() conversion to scalar / scalar-grid SQL.
src/Storages/TimeSeries/PrometheusQueryToSQL/fromFunctionPi.h / .cpp Implements pi() as a constant scalar.
src/Storages/TimeSeries/PrometheusQueryToSQL/finalizeSQL.cpp Removes EMPTY handling, materializes empty tags, and tightens null handling for values[1].
src/Storages/TimeSeries/PrometheusQueryToSQL/dropMetricName.cpp Removes EMPTY store-method handling from metric-name dropping.
src/Storages/TimeSeries/PrometheusQueryToSQL/applyUnaryOperator.h / .cpp Adds unary + / - support for scalars and instant vectors.
src/Storages/TimeSeries/PrometheusQueryToSQL/applyOffset.cpp Removes EMPTY handling paths.
src/Storages/TimeSeries/PrometheusQueryToSQL/applyMathSimpleFunction.h / .cpp Adds a set of per-sample math functions for instant vectors.
src/Storages/TimeSeries/PrometheusQueryToSQL/applyFunctionVector.h / .cpp Implements vector() scalar→instant-vector conversion.
src/Storages/TimeSeries/PrometheusQueryToSQL/applyFunctionScalar.h / .cpp Implements scalar() instant-vector→scalar conversion (with aggregation when needed).
src/Storages/TimeSeries/PrometheusQueryToSQL/applyFunctionOverRange.h / .cpp Refines function detection to string_view and adds a PQT::Function* overload.
src/Storages/TimeSeries/PrometheusQueryToSQL/applyFunction.h / .cpp Adds a central PromQL function dispatcher used by the converter.
src/Storages/TimeSeries/PrometheusQueryToSQL/applyDateTimeFunction.h / .cpp Adds date/time functions mapping to ClickHouse datetime extractors.
src/Storages/TimeSeries/PrometheusQueryToSQL/SQLQueryPiece.h Removes StoreMethod::EMPTY and adjusts default member initializers.
src/Storages/TimeSeries/PrometheusQueryToSQL/NodeEvaluationRangeGetter.cpp Changes subquery range computation to avoid empty inner ranges.
src/Storages/TimeSeries/PrometheusQueryToSQL/Converter.cpp Routes function nodes through applyFunction and adds unary-operator node handling.
src/Storages/TimeSeries/PrometheusHTTPProtocolAPI.cpp Fixes scalar +Inf rendering to match Prometheus (+Inf / -Inf).

@vitlibar vitlibar changed the title PromQL: Unary operator and simple functions [WIP] PromQL: Unary operator and simple functions Feb 21, 2026
@vitlibar vitlibar force-pushed the promql-unary-operator-and-simple-functions branch 3 times, most recently from 3de0470 to c2b8d10 Compare February 23, 2026 00:02
@vitlibar vitlibar force-pushed the promql-unary-operator-and-simple-functions branch 3 times, most recently from 6034d80 to c691f7d Compare February 23, 2026 17:04
@vitlibar vitlibar force-pushed the promql-unary-operator-and-simple-functions branch from c691f7d to e2bf850 Compare February 23, 2026 17:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated no new comments.

@vitlibar vitlibar changed the title [WIP] PromQL: Unary operator and simple functions PromQL: Unary operator and simple functions Feb 23, 2026
@vitlibar vitlibar marked this pull request as ready for review February 23, 2026 18:23
Comment on lines +50 to +54
if (operator_name == "+")
return res;

/// We support only '+' and '-' as unary operators.
chassert(operator_name == "-");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unary operators are supported now

Comment on lines +26 to +42
if (isFunctionVector(function_name))
return applyFunctionVector(function_node, std::move(arguments), context);

if (isFunctionScalar(function_name))
return applyFunctionScalar(function_node, std::move(arguments), context);

if (isFunctionTime(function_name))
return fromFunctionTime(function_node, std::move(arguments), context);

if (isDateTimeFunction(function_name))
return applyDateTimeFunction(function_node, std::move(arguments), context);

if (isMathSimpleFunction(function_name))
return applyMathSimpleFunction(function_node, std::move(arguments), context);

if (isFunctionPi(function_name))
return fromFunctionPi(function_node, std::move(arguments), context);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to some over-range functions a bunch of simple functions has been added here: vector(), scalar(), almost all date/time functions (day_of_week(), etc.), almost all math function (abs(), sin(), pi(), etc.).

@vitlibar
Copy link
Member Author

Ready for review

}
}

using EvaluateWithConstArgumentFunc = Float64 (*)(Float64);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting why do we need to evaluate constant arguments separately? We will have 2 different pathes for evaluating constant expressions then.

}


SQLQueryPiece applyUnaryOperator(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do unary operators have a different implementation? We can treat them as simple math functions similarly how ClickHouse does it with negate.

Copy link
Member Author

@vitlibar vitlibar Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unary operators in PromQL can be applied to scalars, e.g.

-5
-time()

or instant vectors, e.g.

-vector(1)
-up

And simple math functions can be applied to instant vectors only, so for example sin(vector(1)) works whereas sin(1) doesn't work.

Also unary operator as a different type of node in PrometheusQueryTree makes some code easier, for example when we transform it to string we need to consider precedences of operators.

@@ -26,6 +26,10 @@ enum class StoreMethod
/// Can be used only with type ResultType::STRING.
CONST_STRING,

/// A single scalar is stored in one row and one column named `value` (floating-point).
/// Can be used with types ResultType::SCALAR, ResultType::INSTANT_VECTOR, ResultType::RANGE_VECTOR.
SINGLE_SCALAR,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need CONST_SCALAR and a SINGLE_SCALAR? Maybe we can only leave the latter one?

Copy link
Member Author

@vitlibar vitlibar Feb 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CONST_SCALAR is a kind of optimization.

For example, promql query 5 is currently translated to

SELECT toDateTime64(<current_timestamp>, 3) AS timestamp, toFloat64(5.) AS value

and if we get rid of CONST_SCALAR the same promql query will be translated to

WITH
    prometheus_query_step_1 AS (
        SELECT toFloat64(5.) AS value
    ),
SELECT toDateTime64(<current_time>, 3) AS timestamp, toFloat64(value) AS value FROM prometheus_query_step_1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can keep CONST_SCALAR but use it for scalar literals only, like 5 or -5 and not for results of math functions like abs(vector(-5)) - in order to have only one path of evaluation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@nikitamikhaylov nikitamikhaylov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. A few questions arose, but we can merge.

@nikitamikhaylov nikitamikhaylov added this pull request to the merge queue Feb 27, 2026
Merged via the queue into ClickHouse:master with commit 567a99a Feb 27, 2026
152 checks passed
@robot-ch-test-poll2 robot-ch-test-poll2 added the pr-synced-to-cloud The PR is synced to the cloud repo label Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp-promql Issues related to the PromQL support and TimeSeries table engine. pr-not-for-changelog This PR should not be mentioned in the changelog pr-synced-to-cloud The PR is synced to the cloud repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants