Skip to content

Commit beef643

Browse files
committed
Non-deprecated support for planning SQL without DDL
1 parent 720bdb0 commit beef643

File tree

3 files changed

+39
-43
lines changed

3 files changed

+39
-43
lines changed

datafusion/core/src/execution/context.rs

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -245,26 +245,26 @@ impl SessionContext {
245245
self.state.read().config.clone()
246246
}
247247

248-
/// Creates a [`DataFrame`] that will execute a SQL query.
248+
/// Creates a [`DataFrame`] that executes a SQL query supported by
249+
/// DataFusion, including DDL such as (such as `CREATE TABLE`).
249250
///
250-
/// This method is `async` because queries of type `CREATE EXTERNAL TABLE`
251-
/// might require the schema to be inferred.
251+
/// You can use [`Self::plan_sql`] and
252+
/// [`Self::create_physical_plan`] directly if you need read only
253+
/// query support (no way to create external tables, for example)
254+
///
255+
/// This method is `async` because queries of type `CREATE
256+
/// EXTERNAL TABLE` might require the schema to be inferred.
252257
pub async fn sql(&self, sql: &str) -> Result<DataFrame> {
253-
let mut statements = DFParser::parse_sql(sql)?;
254-
if statements.len() != 1 {
255-
return Err(DataFusionError::NotImplemented(
256-
"The context currently only supports a single SQL statement".to_string(),
257-
));
258-
}
259-
260-
// create a query planner
261-
let plan = {
262-
// TODO: Move catalog off SessionState onto SessionContext
263-
let state = self.state.read();
264-
let query_planner = SqlToRel::new(&*state);
265-
query_planner.statement_to_plan(statements.pop_front().unwrap())?
266-
};
258+
let plan = self.plan_sql(sql)?;
259+
self.plan_to_dataframe(plan).await
260+
}
267261

262+
/// Creates a [`DataFrame`] that will execute the specified
263+
/// LogicalPlan, including DDL such as (such as `CREATE TABLE`)
264+
///
265+
/// This method is `async` because queries of type `CREATE EXTERNAL TABLE`
266+
/// might require the schema to be inferred by performing I/O.
267+
pub async fn plan_to_dataframe(&self, plan: LogicalPlan) -> Result<DataFrame> {
268268
match plan {
269269
LogicalPlan::CreateExternalTable(cmd) => {
270270
self.create_external_table(&cmd).await
@@ -559,11 +559,9 @@ impl SessionContext {
559559
}
560560
Ok(false)
561561
}
562-
/// Creates a logical plan.
563-
///
564-
/// This function is intended for internal use and should not be called directly.
565-
#[deprecated(note = "Use SessionContext::sql which snapshots the SessionState")]
566-
pub fn create_logical_plan(&self, sql: &str) -> Result<LogicalPlan> {
562+
563+
/// Creates a [`LogicalPlan`] from a SQL query.
564+
pub fn plan_sql(&self, sql: &str) -> Result<LogicalPlan> {
567565
let mut statements = DFParser::parse_sql(sql)?;
568566

569567
if statements.len() != 1 {
@@ -1004,7 +1002,7 @@ impl SessionContext {
10041002
self.state.read().optimize(plan)
10051003
}
10061004

1007-
/// Creates a physical plan from a logical plan.
1005+
/// Creates a [`ExecutionPlan`] physical plan from a [`LogicalPlan`].
10081006
pub async fn create_physical_plan(
10091007
&self,
10101008
logical_plan: &LogicalPlan,

datafusion/core/src/physical_plan/planner.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,15 +1097,15 @@ impl DefaultPhysicalPlanner {
10971097
// TABLE" -- it must be handled at a higher level (so
10981098
// that the appropriate table can be registered with
10991099
// the context)
1100-
Err(DataFusionError::Internal(
1100+
Err(DataFusionError::Plan(
11011101
"Unsupported logical plan: CreateExternalTable".to_string(),
11021102
))
11031103
}
11041104
LogicalPlan::Prepare(_) => {
11051105
// There is no default plan for "PREPARE" -- it must be
11061106
// handled at a higher level (so that the appropriate
11071107
// statement can be prepared)
1108-
Err(DataFusionError::Internal(
1108+
Err(DataFusionError::Plan(
11091109
"Unsupported logical plan: Prepare".to_string(),
11101110
))
11111111
}
@@ -1114,7 +1114,7 @@ impl DefaultPhysicalPlanner {
11141114
// It must be handled at a higher level (so
11151115
// that the schema can be registered with
11161116
// the context)
1117-
Err(DataFusionError::Internal(
1117+
Err(DataFusionError::Plan(
11181118
"Unsupported logical plan: CreateCatalogSchema".to_string(),
11191119
))
11201120
}
@@ -1123,7 +1123,7 @@ impl DefaultPhysicalPlanner {
11231123
// It must be handled at a higher level (so
11241124
// that the schema can be registered with
11251125
// the context)
1126-
Err(DataFusionError::Internal(
1126+
Err(DataFusionError::Plan(
11271127
"Unsupported logical plan: CreateCatalog".to_string(),
11281128
))
11291129
}
@@ -1132,7 +1132,7 @@ impl DefaultPhysicalPlanner {
11321132
// It must be handled at a higher level (so
11331133
// that the schema can be registered with
11341134
// the context)
1135-
Err(DataFusionError::Internal(
1135+
Err(DataFusionError::Plan(
11361136
"Unsupported logical plan: CreateMemoryTable".to_string(),
11371137
))
11381138
}
@@ -1141,7 +1141,7 @@ impl DefaultPhysicalPlanner {
11411141
// It must be handled at a higher level (so
11421142
// that the schema can be registered with
11431143
// the context)
1144-
Err(DataFusionError::Internal(
1144+
Err(DataFusionError::Plan(
11451145
"Unsupported logical plan: DropTable".to_string(),
11461146
))
11471147
}
@@ -1150,7 +1150,7 @@ impl DefaultPhysicalPlanner {
11501150
// It must be handled at a higher level (so
11511151
// that the schema can be registered with
11521152
// the context)
1153-
Err(DataFusionError::Internal(
1153+
Err(DataFusionError::Plan(
11541154
"Unsupported logical plan: DropView".to_string(),
11551155
))
11561156
}
@@ -1159,16 +1159,16 @@ impl DefaultPhysicalPlanner {
11591159
// It must be handled at a higher level (so
11601160
// that the schema can be registered with
11611161
// the context)
1162-
Err(DataFusionError::Internal(
1162+
Err(DataFusionError::Plan(
11631163
"Unsupported logical plan: CreateView".to_string(),
11641164
))
11651165
}
11661166
LogicalPlan::SetVariable(_) => {
1167-
Err(DataFusionError::Internal(
1167+
Err(DataFusionError::Plan(
11681168
"Unsupported logical plan: SetVariable must be root of the plan".to_string(),
11691169
))
11701170
}
1171-
LogicalPlan::Explain(_) => Err(DataFusionError::Internal(
1171+
LogicalPlan::Explain(_) => Err(DataFusionError::Plan(
11721172
"Unsupported logical plan: Explain must be root of the plan".to_string(),
11731173
)),
11741174
LogicalPlan::Analyze(a) => {

datafusion/core/tests/sql/errors.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,39 +135,37 @@ async fn invalid_qualified_table_references() -> Result<()> {
135135
}
136136

137137
#[tokio::test]
138-
#[allow(deprecated)] // TODO: Remove this test once create_logical_plan removed
138+
/// This test demonstrates it is posible to run SQL queries in DataFusion without
139+
/// any DDL Support (such as CREATE TABLE / CREATE VIEW, ETC).
139140
async fn unsupported_sql_returns_error() -> Result<()> {
140141
let ctx = SessionContext::new();
141142
register_aggregate_csv(&ctx).await?;
142143
// create view
143144
let sql = "create view test_view as select * from aggregate_test_100";
144-
let plan = ctx.create_logical_plan(sql);
145+
let plan = ctx.plan_sql(sql);
145146
let physical_plan = ctx.create_physical_plan(&plan.unwrap()).await;
146147
assert!(physical_plan.is_err());
147148
assert_eq!(
148149
format!("{}", physical_plan.unwrap_err()),
149-
"Internal error: Unsupported logical plan: CreateView. \
150-
This was likely caused by a bug in DataFusion's code and we would welcome that you file an bug report in our issue tracker"
150+
"Error during planning: Unsupported logical plan: CreateView"
151151
);
152152
// // drop view
153153
let sql = "drop view test_view";
154-
let plan = ctx.create_logical_plan(sql);
154+
let plan = ctx.plan_sql(sql);
155155
let physical_plan = ctx.create_physical_plan(&plan.unwrap()).await;
156156
assert!(physical_plan.is_err());
157157
assert_eq!(
158158
format!("{}", physical_plan.unwrap_err()),
159-
"Internal error: Unsupported logical plan: DropView. \
160-
This was likely caused by a bug in DataFusion's code and we would welcome that you file an bug report in our issue tracker"
159+
"Error during planning: Unsupported logical plan: DropView"
161160
);
162161
// // drop table
163162
let sql = "drop table aggregate_test_100";
164-
let plan = ctx.create_logical_plan(sql);
163+
let plan = ctx.plan_sql(sql);
165164
let physical_plan = ctx.create_physical_plan(&plan.unwrap()).await;
166165
assert!(physical_plan.is_err());
167166
assert_eq!(
168167
format!("{}", physical_plan.unwrap_err()),
169-
"Internal error: Unsupported logical plan: DropTable. \
170-
This was likely caused by a bug in DataFusion's code and we would welcome that you file an bug report in our issue tracker"
168+
"Error during planning: Unsupported logical plan: DropTable"
171169
);
172170
Ok(())
173171
}

0 commit comments

Comments
 (0)