blob: 4a9e5d55ce0559b7642c3a4e1be2389c3aa77767 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::logical_plan::producer;
use datafusion::common::DataFusionError;
use datafusion::error::Result;
use datafusion::prelude::*;
use prost::Message;
use std::path::Path;
use substrait::proto::Plan;
use tokio::{
fs::OpenOptions,
io::{AsyncReadExt, AsyncWriteExt},
};
/// Plans a sql and serializes the generated logical plan to bytes.
/// The bytes are then written into a file at `path`.
///
/// Returns an error if the file already exists.
pub async fn serialize(
sql: &str,
ctx: &SessionContext,
path: impl AsRef<Path>,
) -> Result<()> {
let protobuf_out = serialize_bytes(sql, ctx).await?;
let mut file = OpenOptions::new()
.write(true)
.create_new(true)
.open(path)
.await?;
file.write_all(&protobuf_out).await?;
Ok(())
}
/// Plans a sql and serializes the generated logical plan to bytes.
pub async fn serialize_bytes(sql: &str, ctx: &SessionContext) -> Result<Vec<u8>> {
let df = ctx.sql(sql).await?;
let plan = df.into_optimized_plan()?;
let proto = producer::to_substrait_plan(&plan, &ctx.state())?;
let mut protobuf_out = Vec::<u8>::new();
proto
.encode(&mut protobuf_out)
.map_err(|e| DataFusionError::Substrait(format!("Failed to encode plan: {e}")))?;
Ok(protobuf_out)
}
/// Reads the file at `path` and deserializes a plan from the bytes.
pub async fn deserialize(path: impl AsRef<Path>) -> Result<Box<Plan>> {
let mut protobuf_in = Vec::<u8>::new();
let mut file = OpenOptions::new().read(true).open(path).await?;
file.read_to_end(&mut protobuf_in).await?;
deserialize_bytes(protobuf_in).await
}
/// Deserializes a plan from the bytes.
pub async fn deserialize_bytes(proto_bytes: Vec<u8>) -> Result<Box<Plan>> {
Ok(Box::new(Message::decode(&*proto_bytes).map_err(|e| {
DataFusionError::Substrait(format!("Failed to decode plan: {e}"))
})?))
}