MCPcopy Create free account
hub / github.com/apache/datafusion / frontend

Function frontend

datafusion-examples/examples/sql_ops/frontend.rs:48–124  ·  view source on GitHub ↗

This example shows how to use DataFusion's SQL planner to parse SQL text and build `LogicalPlan`s without executing them. For example, if you need a SQL planner and optimizer like Apache Calcite, but do not want a Java runtime dependency for some reason, you could use DataFusion as a SQL frontend. Normally, users interact with DataFusion via SessionContext. However, using SessionContext requires

()

Source from the content-addressed store, hash-verified

46/// In this example, we demonstrate how to use the lower level APIs directly,
47/// which only requires the `datafusion-sql` dependency.
48pub fn frontend() -> Result<()> {
49 // First, we parse the SQL string. Note that we use the DataFusion
50 // Parser, which wraps the `sqlparser-rs` SQL parser and adds DataFusion
51 // specific syntax such as `CREATE EXTERNAL TABLE`
52 let dialect = PostgreSqlDialect {};
53 let sql = "SELECT name FROM person WHERE age BETWEEN 21 AND 32";
54 let statements = Parser::parse_sql(&dialect, sql)?;
55
56 // Now, use DataFusion's SQL planner, called `SqlToRel` to create a
57 // `LogicalPlan` from the parsed statement
58 //
59 // To invoke SqlToRel we must provide it schema and function information
60 // via an object that implements the `ContextProvider` trait
61 let context_provider = MyContextProvider::default();
62 let sql_to_rel = SqlToRel::new(&context_provider);
63 let logical_plan = sql_to_rel.sql_statement_to_plan(statements[0].clone())?;
64
65 // Here is the logical plan that was generated:
66 assert_eq!(
67 logical_plan.display_indent().to_string(),
68 "Projection: person.name\
69 \n Filter: person.age BETWEEN Int64(21) AND Int64(32)\
70 \n TableScan: person"
71 );
72
73 // The initial LogicalPlan is a mechanical translation from the parsed SQL
74 // and often can not run without the Analyzer passes.
75 //
76 // In this example, `person.age` is actually a different data type (Int8)
77 // than the values to which it is compared to which are Int64. Most
78 // execution engines, including DataFusion's, will fail if you provide such
79 // a plan.
80 //
81 // To prepare it to run, we must apply type coercion to align types, and
82 // check for other semantic errors. In DataFusion this is done by a
83 // component called the Analyzer.
84 let config = OptimizerContext::default().with_skip_failing_rules(false);
85 let analyzed_plan = Analyzer::new().execute_and_check(
86 logical_plan,
87 &config.options(),
88 observe_analyzer,
89 )?;
90 // Note that the Analyzer has added a CAST to the plan to align the types
91 assert_eq!(
92 analyzed_plan.display_indent().to_string(),
93 "Projection: person.name\
94 \n Filter: CAST(person.age AS Int64) BETWEEN Int64(21) AND Int64(32)\
95 \n TableScan: person",
96 );
97
98 // As we can see, the Analyzer added a CAST so the types are the same
99 // (Int64). However, this plan is not as efficient as it could be, as it
100 // will require casting *each row* of the input to UInt64 before comparison
101 // to 21 and 32. To optimize this query's performance, it is better to cast
102 // the constants once at plan time to UInt8.
103 //
104 // Query optimization is handled in DataFusion by a component called the
105 // Optimizer, which we now invoke

Callers 1

runMethod · 0.85

Calls 7

newFunction · 0.85
sql_statement_to_planMethod · 0.80
execute_and_checkMethod · 0.80
cloneMethod · 0.45
optionsMethod · 0.45
optimizeMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…