How PromQL Integration Works Alongside SQL in GreptimeDB: Architecture Deep Dive
GreptimeDB unifies PromQL integration with SQL by parsing both languages into a shared QueryStatement enum, translating PromQL metrics queries into DataFusion logical plans via a specialized PromPlanner, and executing both on the same vectorized engine.
GreptimeDB is an open-source time-series database built on Apache DataFusion that offers native PromQL integration alongside standard SQL. Unlike systems that treat PromQL as an external wrapper, GreptimeDB embeds PromQL directly into its query pipeline, allowing both languages to share the same catalog, optimizer, and execution runtime. This article examines the source code in greptimeteam/greptimedb to explain how the database achieves seamless dual-language support through a unified logical planning layer.
The Unified Query Statement Architecture
At the entry point of every query, GreptimeDB uses the QueryLanguageParser (src/query/src/parser.rs) to normalize both SQL and PromQL into a single internal representation. This design eliminates the need for separate query engines and ensures consistent handling of authentication, resource limits, and session context.
The QueryStatement Enum
The parser returns a QueryStatement enum that abstracts the language differences:
QueryStatement::Sql(Statement)– Contains a DataFusion AST for standard SQL queriesQueryStatement::Promql(EvalStmt, Option<String>)– Contains a PromQL AST (promql_parser::parser::EvalStmt) for metric queries
This unification happens in QueryLanguageParser::parse_sql and QueryLanguageParser::parse_promql, which HTTP/gRPC handlers call when receiving requests at endpoints like /v1/promql (src/servers/src/http/prometheus.rs).
Logical Planning for Dual Languages
Once parsed, both statement types flow into the DfLogicalPlanner (src/query/src/planner.rs). The planner inspects the QueryStatement variant and routes PromQL queries to a specialized translator while handling SQL through the standard DataFusion path.
Planning Pipeline Branching
Inside DfLogicalPlanner::plan, a match statement distinguishes the execution paths:
- SQL Path: Calls
DfLogicalPlanner::plan_sql(lines 287–299) to build logical plans using the standard DataFusion planner - PromQL Path: Delegates to
PromPlanner::stmt_to_plan(src/query/src/promql/planner.rs) for metric-specific translation
Both paths ultimately produce DataFusion LogicalPlan objects, ensuring that optimization rules and physical planning work identically regardless of the input language.
PromPlanner Implementation Details
The PromPlanner (src/query/src/promql/planner.rs) implements the core translation logic from PromQL AST nodes to DataFusion relational operators. Key steps include:
- Context Creation:
PromPlannerContext::from_eval_stmtextracts start/end timestamps and step intervals from the PromQL query (lines 65–71) - Metric Resolution: Resolves the metric name from the
__name__label matcher usingcatalog::table_source::DfTableSourceProvider - Table Scan Generation: Produces
TableScannodes that reference the underlying metric tables
Translating PromQL to DataFusion Operators
The PromQL-to-DataFusion translation handles metric-specific semantics through specialized expression mapping and custom logical extensions.
Label Matcher Conversion
PromQL label matchers (Matcher, Matchers) translate into DataFusion filter expressions via PromPlanner::matchers_to_expr (lines 4031–4045). The conversion produces standard DataFusion expressions such as:
col(label).eq(literal)for equality matchersregexp_match(col(label), pattern)for regex matchers
These expressions become standard Filter nodes in the logical plan, allowing DataFusion's predicate push-down optimizations to apply to PromQL queries.
PromQL-Specific Functions
Functions unique to PromQL—such as rate, histogram_quantile, absent, and resets—map to custom logical plan extensions in the promql::extension_plan module (src/query/src/promql/extension_plan/*.rs). These include:
SeriesDivide– Handles time-series alignment and step boundariesHistogramFold– Processes histogram bucket calculationsInstantManipulate– Manages lookback windows and timestamp alignment
These extensions compile into the same physical operators as standard SQL functions, enabling cross-language optimization.
Hybrid TQL: Embedding PromQL Inside SQL
GreptimeDB supports TQL (Time-series Query Language), a hybrid syntax that embeds PromQL expressions within SQL WITH clauses. This allows analysts to combine PromQL's metric aggregation with SQL's joining and windowing capabilities.
TQL Parsing and Planning
The hybrid parser in src/sql/src/parsers/with_tql_parser.rs extracts PromQL snippets from TQL EVAL statements. For example:
WITH t AS (TQL EVAL (0, 600, '10s') sum(rate(cpu_usage[1m])))
SELECT service, avg(val) FROM t GROUP BY service
The parser extracts the PromQL part and processes it through QueryLanguageParser::parse_promql, while the surrounding SQL flows through the standard parser. The DfLogicalPlanner::plan_query_with_hybrid_ctes method (lines 350–384) coordinates planning by:
- Detecting hybrid CTEs via
has_hybrid_ctes - Routing PromQL sub-queries through
PromPlanner - Assembling the final logical plan with SQL CTE references pointing to PromQL-derived sub-plans
Shared Execution Runtime
After logical planning, both SQL and PromQL queries converge on the same execution path. The DataFusion physical planner generates vectorized execution plans that run on a shared thread pool. This means:
- Memory management uses identical allocation pools for both languages
- Push-down optimizations apply to filter predicates regardless of whether they originated in SQL
WHEREclauses or PromQL label matchers - Caching layers store results from both query types using the same eviction policies
The execution uniformity ensures that hybrid queries—where SQL joins the results of PromQL aggregations—operate without data serialization barriers or context switches between engines.
Summary
GreptimeDB implements PromQL integration through a layered architecture that preserves language-specific semantics while sharing underlying infrastructure:
- Unified parsing via
QueryLanguageParserproduces aQueryStatementenum supporting both SQL and PromQL variants - Specialized planning through
PromPlannertranslates PromQL AST nodes into standard DataFusion logical operators - Metric-specific extensions in
promql::extension_planimplement functions likerateandhistogram_quantileas compatible logical nodes - Hybrid TQL support enables PromQL embedding within SQL CTEs via
with_tql_parser.rs - Shared execution on the DataFusion engine provides consistent performance characteristics across both query languages
Frequently Asked Questions
Can I mix PromQL and SQL in the same query?
Yes. GreptimeDB supports TQL (Time-series Query Language), which allows you to embed PromQL expressions inside SQL WITH clauses using the TQL EVAL syntax. The hybrid parser extracts the PromQL portion, processes it through PromPlanner, and integrates the resulting sub-plan with the surrounding SQL query, enabling joins and aggregations across both languages.
How does GreptimeDB handle PromQL functions like rate or histogram_quantile?
These functions map to custom logical plan extensions in the promql::extension_plan module (src/query/src/promql/extension_plan/*.rs). The PromPlanner translates PromQL function calls into specialized operators such as SeriesDivide and HistogramFold, which DataFusion treats as standard logical nodes during optimization and physical planning.
What execution engine runs PromQL queries?
PromQL queries execute on the same DataFusion vectorized engine that processes SQL. After PromPlanner converts PromQL AST into a LogicalPlan, the standard DataFusion physical planner takes over. This shared runtime enables consistent memory management, predicate push-down, and caching across both query languages.
Where is the PromQL parsing logic located in the codebase?
The entry point for PromQL parsing is QueryLanguageParser::parse_promql in src/query/src/parser.rs. This method parses the PromQL string into an EvalStmt from the promql_parser crate, wrapping it in the QueryStatement::Promql enum variant for downstream processing by the logical planner.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →