feat: add the merged tag set for the `Select` query
parent
f7a8850f62
commit
0dd1826e3c
|
@ -1,7 +1,6 @@
|
||||||
//! Defines data structures which represent an InfluxQL
|
//! Defines data structures which represent an InfluxQL
|
||||||
//! statement after it has been processed
|
//! statement after it has been processed
|
||||||
|
|
||||||
use crate::plan::field::field_by_name;
|
|
||||||
use crate::plan::rewriter::ProjectionType;
|
use crate::plan::rewriter::ProjectionType;
|
||||||
use crate::plan::{error, SchemaProvider};
|
use crate::plan::{error, SchemaProvider};
|
||||||
use datafusion::common::Result;
|
use datafusion::common::Result;
|
||||||
|
@ -48,6 +47,10 @@ pub(super) struct Select {
|
||||||
/// The GROUP BY clause of the selection.
|
/// The GROUP BY clause of the selection.
|
||||||
pub(super) group_by: Option<GroupByClause>,
|
pub(super) group_by: Option<GroupByClause>,
|
||||||
|
|
||||||
|
/// The set of possible tags for the selection, by combining
|
||||||
|
/// the tag sets of all inputs via the `FROM` clause.
|
||||||
|
pub(super) tag_set: TagSet,
|
||||||
|
|
||||||
/// The [fill] clause specifies the fill behaviour for the selection. If the value is [`None`],
|
/// The [fill] clause specifies the fill behaviour for the selection. If the value is [`None`],
|
||||||
/// it is the same behavior as `fill(null)`.
|
/// it is the same behavior as `fill(null)`.
|
||||||
///
|
///
|
||||||
|
@ -138,12 +141,14 @@ pub(super) enum DataSourceSchema<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DataSourceSchema<'a> {
|
impl<'a> DataSourceSchema<'a> {
|
||||||
pub(super) fn field_type_by_name(&self, name: &str) -> Option<InfluxColumnType> {
|
/// Returns `true` if the specified name is a tag field or a projection of a tag field if
|
||||||
|
/// the `DataSource` is a subquery.
|
||||||
|
pub(super) fn is_tag_field(&self, name: &str) -> bool {
|
||||||
match self {
|
match self {
|
||||||
DataSourceSchema::Table(s) => s.field_type_by_name(name),
|
DataSourceSchema::Table(s) => {
|
||||||
DataSourceSchema::Subquery(q) => {
|
matches!(s.field_type_by_name(name), Some(InfluxColumnType::Tag))
|
||||||
field_by_name(&q.fields, name).and_then(|f| f.data_type)
|
|
||||||
}
|
}
|
||||||
|
DataSourceSchema::Subquery(q) => q.tag_set.contains(name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ fn map_select(s: &dyn SchemaProvider, stmt: &SelectStatement) -> Result<Select>
|
||||||
|
|
||||||
let from = expand_from(s, stmt)?;
|
let from = expand_from(s, stmt)?;
|
||||||
let (fields, group_by) = expand_projection(s, stmt, &from)?;
|
let (fields, group_by) = expand_projection(s, stmt, &from)?;
|
||||||
|
let tag_set = select_tag_set(s, &from);
|
||||||
|
|
||||||
let SelectStatementInfo { projection_type } =
|
let SelectStatementInfo { projection_type } =
|
||||||
select_statement_info(&fields, &group_by, stmt.fill)?;
|
select_statement_info(&fields, &group_by, stmt.fill)?;
|
||||||
|
@ -79,6 +80,7 @@ fn map_select(s: &dyn SchemaProvider, stmt: &SelectStatement) -> Result<Select>
|
||||||
from,
|
from,
|
||||||
condition: stmt.condition.clone(),
|
condition: stmt.condition.clone(),
|
||||||
group_by,
|
group_by,
|
||||||
|
tag_set,
|
||||||
fill: stmt.fill,
|
fill: stmt.fill,
|
||||||
order_by: stmt.order_by,
|
order_by: stmt.order_by,
|
||||||
limit: stmt.limit,
|
limit: stmt.limit,
|
||||||
|
@ -236,6 +238,24 @@ fn from_drop_empty(s: &dyn SchemaProvider, stmt: &mut Select) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine the combined tag set for the specified `from`.
|
||||||
|
fn select_tag_set(s: &dyn SchemaProvider, from: &[DataSource]) -> TagSet {
|
||||||
|
let mut tag_set = TagSet::new();
|
||||||
|
|
||||||
|
for ds in from {
|
||||||
|
match ds {
|
||||||
|
DataSource::Table(table_name) => {
|
||||||
|
if let Some(table) = s.table_schema(table_name) {
|
||||||
|
tag_set.extend(table.tags_iter().map(|f| f.name().to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataSource::Subquery(q) => tag_set.extend(q.tag_set.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag_set
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine the merged fields and tags of the `FROM` clause.
|
/// Determine the merged fields and tags of the `FROM` clause.
|
||||||
fn from_field_and_dimensions(
|
fn from_field_and_dimensions(
|
||||||
s: &dyn SchemaProvider,
|
s: &dyn SchemaProvider,
|
||||||
|
@ -1712,6 +1732,7 @@ mod test {
|
||||||
|
|
||||||
mod rewrite_statement {
|
mod rewrite_statement {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::plan::ir::TagSet;
|
||||||
use datafusion::common::Result;
|
use datafusion::common::Result;
|
||||||
use influxdb_influxql_parser::select::SelectStatement;
|
use influxdb_influxql_parser::select::SelectStatement;
|
||||||
use schema::{InfluxColumnType, InfluxFieldType};
|
use schema::{InfluxColumnType, InfluxFieldType};
|
||||||
|
@ -1765,6 +1786,31 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Validate the tag_set field of a [`Select]`
|
||||||
|
#[test]
|
||||||
|
fn tag_set_schema() {
|
||||||
|
let namespace = MockSchemaProvider::default();
|
||||||
|
|
||||||
|
macro_rules! assert_tag_set {
|
||||||
|
($Q:ident, $($TAG:literal),*) => {
|
||||||
|
assert_eq!($Q.select.tag_set, TagSet::from([$($TAG.to_owned(),)*]))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let stmt = parse_select("SELECT usage_system FROM cpu");
|
||||||
|
let q = rewrite_statement(&namespace, &stmt).unwrap();
|
||||||
|
assert_tag_set!(q, "cpu", "host", "region");
|
||||||
|
|
||||||
|
let stmt = parse_select("SELECT usage_system FROM cpu, disk");
|
||||||
|
let q = rewrite_statement(&namespace, &stmt).unwrap();
|
||||||
|
assert_tag_set!(q, "cpu", "host", "region", "device");
|
||||||
|
|
||||||
|
let stmt =
|
||||||
|
parse_select("SELECT usage_system FROM (select * from cpu), (select * from disk)");
|
||||||
|
let q = rewrite_statement(&namespace, &stmt).unwrap();
|
||||||
|
assert_tag_set!(q, "cpu", "host", "region", "device");
|
||||||
|
}
|
||||||
|
|
||||||
/// Validating types for simple projections
|
/// Validating types for simple projections
|
||||||
#[test]
|
#[test]
|
||||||
fn projection_simple() {
|
fn projection_simple() {
|
||||||
|
|
Loading…
Reference in New Issue