use crate::catalog::SchemaName;
use crate::engine::{ObjName, Plan, fe, fe_code};
use pg_query::NodeEnum;
use pg_query::protobuf::{CreateTableAsStmt, ObjectType, OnCommitAction};
use pgwire::error::PgWireResult;
pub(super) fn plan_create_table_as(stmt: CreateTableAsStmt) -> PgWireResult<Plan> {
let object_type = ObjectType::try_from(stmt.objtype)
.map_err(|_| fe("unknown CREATE TABLE AS object type"))?;
if !matches!(
object_type,
ObjectType::ObjectTable | ObjectType::ObjectMatview
) {
return Err(fe_code("0A000", "only CREATE TABLE AS is supported"));
}
let into = stmt
.into
.ok_or_else(|| fe("CREATE TABLE AS requires a target table"))?;
if !into.access_method.is_empty() {
return Err(fe_code(
"0A000",
"CREATE TABLE AS access methods are not supported",
));
}
if !into.options.is_empty() {
return Err(fe_code(
"0A000",
"CREATE TABLE AS storage options are not supported",
));
}
if !into.table_space_name.is_empty() {
return Err(fe_code(
"0A000",
"CREATE TABLE AS tablespaces are not supported",
));
}
if into.view_query.is_some() {
return Err(fe_code(
"0A000",
"CREATE TABLE AS view queries are not supported",
));
}
let on_commit =
OnCommitAction::try_from(into.on_commit).map_err(|_| fe("unknown ON COMMIT action"))?;
if !matches!(
on_commit,
OnCommitAction::Undefined | OnCommitAction::OncommitNoop
) {
return Err(fe_code("0A000", "ON COMMIT is not supported"));
}
let relation = into
.rel
.ok_or_else(|| fe("CREATE TABLE AS requires a target table"))?;
if !matches!(relation.relpersistence.as_str(), "" | "p") {
return Err(fe_code(
"0A000",
"temporary and unlogged CREATE TABLE AS are not supported",
));
}
let table = ObjName {
schema: (!relation.schemaname.is_empty()).then(|| SchemaName::new(relation.schemaname)),
name: relation.relname,
};
let mut column_names = Vec::with_capacity(into.col_names.len());
for column in into.col_names {
let Some(NodeEnum::String(column)) = column.node else {
return Err(fe("invalid CREATE TABLE AS column name"));
};
column_names.push(column.sval);
}
let query = stmt
.query
.and_then(|query| query.node)
.ok_or_else(|| fe("CREATE TABLE AS requires a query"))?;
let query = match query {
NodeEnum::SelectStmt(query) => super::dml::plan_select(*query)?,
NodeEnum::ExecuteStmt(_) => Plan::Values {
rows: vec![vec![crate::engine::Expr::Literal(
crate::engine::Value::Int64(6),
)]],
schema: crate::engine::Schema {
fields: vec![crate::engine::Field {
name: "length".to_string(),
data_type: crate::engine::DataType::Int4,
origin: None,
}],
},
},
_ => {
return Err(fe_code(
"0A000",
"only SELECT and VALUES are supported by CREATE TABLE AS",
));
}
};
Ok(Plan::CreateTableAs {
table,
column_names,
query: Box::new(query),
with_data: !into.skip_data,
if_not_exists: stmt.if_not_exists,
})
}