Merge pull request #1602 from influxdata/ntran/pushdown_explain

refactor: macro and tests for explains
pull/24376/head
kodiakhq[bot] 2021-06-01 22:29:12 +00:00 committed by GitHub
commit fdb6c98c8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 342 additions and 49 deletions

View File

@ -145,6 +145,7 @@ impl IOxExecutionContext {
/// Prepare a SQL statement for execution. This assumes that any /// Prepare a SQL statement for execution. This assumes that any
/// tables referenced in the SQL have been registered with this context /// tables referenced in the SQL have been registered with this context
pub fn prepare_sql(&mut self, sql: &str) -> Result<Arc<dyn ExecutionPlan>> { pub fn prepare_sql(&mut self, sql: &str) -> Result<Arc<dyn ExecutionPlan>> {
debug!(text=%sql, "SQL");
let logical_plan = self.inner.sql(sql)?.to_logical_plan(); let logical_plan = self.inner.sql(sql)?.to_logical_plan();
self.prepare_plan(&logical_plan) self.prepare_plan(&logical_plan)
} }

View File

@ -13,6 +13,7 @@ use datafusion::{
physical_plan::ExecutionPlan, physical_plan::ExecutionPlan,
}; };
use internal_types::schema::{builder::SchemaMerger, Schema}; use internal_types::schema::{builder::SchemaMerger, Schema};
use observability_deps::tracing::debug;
use crate::{predicate::PredicateBuilder, util::project_schema, PartitionChunk}; use crate::{predicate::PredicateBuilder, util::project_schema, PartitionChunk};
@ -198,6 +199,8 @@ impl<C: PartitionChunk + 'static> TableProvider for ChunkTableProvider<C> {
filters: &[Expr], filters: &[Expr],
_limit: Option<usize>, _limit: Option<usize>,
) -> std::result::Result<Arc<dyn ExecutionPlan>, DataFusionError> { ) -> std::result::Result<Arc<dyn ExecutionPlan>, DataFusionError> {
debug!("Input Filters to Scan: {:#?}", filters);
// Note that `filters` don't actually need to be evaluated in // Note that `filters` don't actually need to be evaluated in
// the scan for the plans to be correct, they are an extra // the scan for the plans to be correct, they are an extra
// optimization for providers which can offer them // optimization for providers which can offer them

View File

@ -287,6 +287,8 @@ impl PartitionChunk for DbChunk {
// Predicate is not required to be applied for correctness. We only pushed it down // Predicate is not required to be applied for correctness. We only pushed it down
// when possible for performance gain // when possible for performance gain
debug!("Input Predicate to read_filter: {:#?}", predicate);
match &self.state { match &self.state {
State::MutableBuffer { chunk, .. } => { State::MutableBuffer { chunk, .. } => {
let batch = chunk let batch = chunk

View File

@ -7,7 +7,7 @@
use super::scenarios::*; use super::scenarios::*;
use arrow::record_batch::RecordBatch; use arrow::record_batch::RecordBatch;
use arrow_util::assert_batches_sorted_eq; use arrow_util::{assert_batches_eq, assert_batches_sorted_eq};
use query::frontend::sql::SqlQueryPlanner; use query::frontend::sql::SqlQueryPlanner;
use std::sync::Arc; use std::sync::Arc;
@ -40,6 +40,35 @@ macro_rules! run_sql_test_case {
}; };
} }
/// runs table_names(predicate) and compares it to the expected
/// output
macro_rules! run_sql_explain_test_case {
($DB_SETUP:expr, $SQL:expr, $EXPECTED_LINES:expr) => {
test_helpers::maybe_start_logging();
let sql = $SQL.to_string();
for scenario in $DB_SETUP.make().await {
let DbScenario {
scenario_name, db, ..
} = scenario;
let db = Arc::new(db);
println!("Running scenario '{}'", scenario_name);
println!("SQL: '{:#?}'", sql);
let planner = SqlQueryPlanner::default();
let executor = db.executor();
let physical_plan = planner
.query(db, &sql, executor.as_ref())
.expect("built plan successfully");
let results: Vec<RecordBatch> =
executor.collect(physical_plan).await.expect("Running plan");
assert_batches_eq!($EXPECTED_LINES, &results);
}
};
}
#[tokio::test] #[tokio::test]
async fn sql_select_from_cpu() { async fn sql_select_from_cpu() {
let expected = vec![ let expected = vec![
@ -409,10 +438,8 @@ async fn sql_select_with_schema_merge_subset() {
} }
#[tokio::test] #[tokio::test]
async fn sql_predicate_pushdown() { async fn sql_predicate_pushdown_correctness() {
// Test 1: Select everything // Test 1: Select everything
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+-----------+", "+-------+--------+-------------------------------+-----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -432,17 +459,7 @@ async fn sql_predicate_pushdown() {
&expected &expected
); );
// TODO: Make push-down predicates shown in explain verbose. Ticket #1538 - actively working on this
// Check the plan
// run_sql_test_case!(
// TwoMeasurementsPredicatePushDown {},
// "EXPLAIN VERBOSE SELECT * from restaurant",
// &expected
// );
// Test 2: One push-down expression: count > 200 // Test 2: One push-down expression: count > 200
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+-----------+", "+-------+--------+-------------------------------+-----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -461,16 +478,7 @@ async fn sql_predicate_pushdown() {
&expected &expected
); );
// Check the plan
// run_sql_test_case!(
// TwoMeasurementsPredicatePushDown {},
// "EXPLAIN VERBOSE SELECT * from restaurant where count > 200",
// &expected
// );
// Test 3: Two push-down expression: count > 200 and town != 'tewsbury' // Test 3: Two push-down expression: count > 200 and town != 'tewsbury'
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+-----------+", "+-------+--------+-------------------------------+-----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -488,17 +496,8 @@ async fn sql_predicate_pushdown() {
&expected &expected
); );
// Check the plan
// run_sql_test_case!(
// TwoMeasurementsPredicatePushDown {},
// "EXPLAIN VERBOSE SELECT * from restaurant where count > 200 and town != 'tewsbury'",
// &expected
// );
// Test 4: Still two push-down expression: count > 200 and town != 'tewsbury' // Test 4: Still two push-down expression: count > 200 and town != 'tewsbury'
// even though the results are different // even though the results are different
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+-----------+", "+-------+--------+-------------------------------+-----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -516,8 +515,6 @@ async fn sql_predicate_pushdown() {
); );
// Test 5: three push-down expression: count > 200 and town != 'tewsbury' and count < 40000 // Test 5: three push-down expression: count > 200 and town != 'tewsbury' and count < 40000
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+-----------+", "+-------+--------+-------------------------------+-----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -534,8 +531,6 @@ async fn sql_predicate_pushdown() {
); );
// Test 6: two push-down expression: count > 200 and count < 40000 // Test 6: two push-down expression: count > 200 and count < 40000
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+-----------+", "+-------+--------+-------------------------------+-----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -554,8 +549,6 @@ async fn sql_predicate_pushdown() {
); );
// Test 7: two push-down expression on float: system > 4.0 and system < 7.0 // Test 7: two push-down expression on float: system > 4.0 and system < 7.0
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+-----------+", "+-------+--------+-------------------------------+-----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -575,8 +568,6 @@ async fn sql_predicate_pushdown() {
); );
// Test 8: two push-down expression on float: system > 5.0 and system < 7.0 // Test 8: two push-down expression on float: system > 5.0 and system < 7.0
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+----------+", "+-------+--------+-------------------------------+----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -593,8 +584,6 @@ async fn sql_predicate_pushdown() {
); );
// Test 9: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0 // Test 9: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+----------+", "+-------+--------+-------------------------------+----------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -611,8 +600,6 @@ async fn sql_predicate_pushdown() {
// Test 10: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0 // Test 10: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0
// even though there are more expressions,(count = 632 or town = 'reading'), in the filter // even though there are more expressions,(count = 632 or town = 'reading'), in the filter
//
// Check correctness
let expected = vec![ let expected = vec![
"+-------+--------+-------------------------------+---------+", "+-------+--------+-------------------------------+---------+",
"| count | system | time | town |", "| count | system | time | town |",
@ -626,11 +613,8 @@ async fn sql_predicate_pushdown() {
&expected &expected
); );
// Test 11: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0 // Test 11: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0 and
// After DF ticket, https://github.com/apache/arrow-datafusion/issues/383 is done, // time > to_timestamp('1970-01-01T00:00:00.000000120+00:00') rewritten to time GT INT(130)
// there will be more pushed-down predicate time > to_timestamp('1970-01-01T00:00:00.000000120+00:00')
//
// Check correctness
let expected = vec!["++", "++"]; let expected = vec!["++", "++"];
run_sql_test_case!( run_sql_test_case!(
TwoMeasurementsPredicatePushDown {}, TwoMeasurementsPredicatePushDown {},
@ -671,3 +655,306 @@ async fn sql_predicate_pushdown() {
&expected &expected
); );
} }
#[tokio::test]
async fn sql_predicate_pushdown_explain() {
// Test 1: Select everything
let expected = vec![
"+-----------------------------------------+--------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+--------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+--------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant",
&expected
);
// Test 2: One push-down expression: count > 200
// TODO: Make push-down predicates shown in explain verbose. Ticket #1538
let expected = vec![
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: CAST(count AS Int64) > 200 |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where count > 200",
&expected
);
// Check the plan
let expected = vec![
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: CAST(count AS Int64) > 200 |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where count > 200",
&expected
);
// Test 3: Two push-down expression: count > 200 and town != 'tewsbury'
let expected = vec![
"+-----------------------------------------+-----------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+-----------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: CAST(count AS Int64) > 200 AND CAST(town AS Utf8) != tewsbury |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+-----------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where count > 200 and town != 'tewsbury'",
&expected
);
// Test 4: Still two push-down expression: count > 200 and town != 'tewsbury'
// even though the results are different
let expected = vec![
"+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") And #system Eq Int64(5) Or #town Eq Utf8(\"lawrence\") |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") And #system Eq Int64(5) Or #town Eq Utf8(\"lawrence\") |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") And #system Eq Int64(5) Or #town Eq Utf8(\"lawrence\") |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: CAST(count AS Int64) > 200 AND CAST(town AS Utf8) != tewsbury AND system = CAST(5 AS Float64) OR CAST(town AS Utf8) = lawrence |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where count > 200 and town != 'tewsbury' and (system =5 or town = 'lawrence')",
&expected
);
// Test 5: three push-down expression: count > 200 and town != 'tewsbury' and count < 40000
let expected = vec![
"+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") And #system Eq Int64(5) Or #town Eq Utf8(\"lawrence\") And #count Lt Int64(40000) |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") And #system Eq Int64(5) Or #town Eq Utf8(\"lawrence\") And #count Lt Int64(40000) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #town NotEq Utf8(\"tewsbury\") And #system Eq Int64(5) Or #town Eq Utf8(\"lawrence\") And #count Lt Int64(40000) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: CAST(count AS Int64) > 200 AND CAST(town AS Utf8) != tewsbury AND system = CAST(5 AS Float64) OR CAST(town AS Utf8) = lawrence AND CAST(count AS Int64) < 40000 |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where count > 200 and town != 'tewsbury' and (system =5 or town = 'lawrence') and count < 40000",
&expected
);
// Test 6: two push-down expression: count > 200 and count < 40000
let expected = vec![
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #count Lt Int64(40000) |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #count Lt Int64(40000) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #count Gt Int64(200) And #count Lt Int64(40000) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: CAST(count AS Int64) > 200 AND CAST(count AS Int64) < 40000 |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where count > 200 and count < 40000",
&expected
);
// Test 7: two push-down expression on float: system > 4.0 and system < 7.0
let expected = vec![
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(4) And #system Lt Float64(7) |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(4) And #system Lt Float64(7) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(4) And #system Lt Float64(7) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: system > 4 AND system < 7 |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where system > 4.0 and system < 7.0",
&expected
);
// Test 8: two push-down expression on float: system > 5.0 and system < 7.0
let expected = vec![
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And #system Lt Float64(7) |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And #system Lt Float64(7) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And #system Lt Float64(7) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: system > 5 AND system < 7 |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+----------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where system > 5.0 and system < 7.0",
&expected
);
// Test 9: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0
let expected = vec![
"+-----------------------------------------+--------------------------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+--------------------------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And #town NotEq Utf8(\"tewsbury\") And Float64(7) Gt #system |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And #town NotEq Utf8(\"tewsbury\") And Float64(7) Gt #system |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And #town NotEq Utf8(\"tewsbury\") And Float64(7) Gt #system |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: system > 5 AND CAST(town AS Utf8) != tewsbury AND 7 > system |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+--------------------------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where system > 5.0 and town != 'tewsbury' and 7.0 > system",
&expected
);
// Test 10: three push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0
// even though there are more expressions,(count = 632 or town = 'reading'), in the filter
let expected = vec![
"+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And Utf8(\"tewsbury\") NotEq #town And #system Lt Float64(7) And #count Eq Int64(632) Or #town Eq Utf8(\"reading\") |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And Utf8(\"tewsbury\") NotEq #town And #system Lt Float64(7) And #count Eq Int64(632) Or #town Eq Utf8(\"reading\") |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: #system Gt Float64(5) And Utf8(\"tewsbury\") NotEq #town And #system Lt Float64(7) And #count Eq Int64(632) Or #town Eq Utf8(\"reading\") |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: system > 5 AND tewsbury != CAST(town AS Utf8) AND system < 7 AND CAST(count AS Int64) = 632 OR CAST(town AS Utf8) = reading |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where system > 5.0 and 'tewsbury' != town and system < 7.0 and (count = 632 or town = 'reading')",
&expected
);
// Test 11: four push-down expression: system > 5.0 and town != 'tewsbury' and system < 7.0 and
// time > to_timestamp('1970-01-01T00:00:00.000000120+00:00') rewritten to time GT INT(130)
let expected = vec![
"+-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+",
"| plan_type | plan |",
"+-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+",
"| logical_plan | Projection: #count, #system, #time, #town |",
"| | Filter: Float64(5) Lt #system And #town NotEq Utf8(\"tewsbury\") And #system Lt Float64(7) And #count Eq Int64(632) Or #town Eq Utf8(\"reading\") And #time Gt totimestamp(Utf8(\"1970-01-01T00:00:00.000000130+00:00\")) |",
"| | TableScan: restaurant projection=None |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: Float64(5) Lt #system And #town NotEq Utf8(\"tewsbury\") And #system Lt Float64(7) And #count Eq Int64(632) Or #town Eq Utf8(\"reading\") And #time Gt totimestamp(Utf8(\"1970-01-01T00:00:00.000000130+00:00\")) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| logical_plan after projection_push_down | Projection: #count, #system, #time, #town |",
"| | Filter: Float64(5) Lt #system And #town NotEq Utf8(\"tewsbury\") And #system Lt Float64(7) And #count Eq Int64(632) Or #town Eq Utf8(\"reading\") And #time Gt totimestamp(Utf8(\"1970-01-01T00:00:00.000000130+00:00\")) |",
"| | TableScan: restaurant projection=Some([0, 1, 2, 3]) |",
"| physical_plan | ProjectionExec: expr=[count, system, time, town] |",
"| | FilterExec: 5 < system AND CAST(town AS Utf8) != tewsbury AND system < 7 AND CAST(count AS Int64) = 632 OR CAST(town AS Utf8) = reading AND time > totimestamp(1970-01-01T00:00:00.000000130+00:00) |",
"| | IOxReadFilterNode: table_name=restaurant, chunks=1 predicate=Predicate |",
"+-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+",
];
run_sql_explain_test_case!(
TwoMeasurementsPredicatePushDown {},
"EXPLAIN VERBOSE SELECT * from restaurant where 5.0 < system and town != 'tewsbury' and system < 7.0 and (count = 632 or town = 'reading') and time > to_timestamp('1970-01-01T00:00:00.000000130+00:00')",
&expected
);
}