use pgwire::api::results::{FieldFormat, Response};
use pgwire::error::{ErrorInfo, PgWireError, PgWireResult};
use nodedb_physical::physical_plan::{ExchangeMode, ExchangeOp, PhysicalPlan, QueryOp};
use nodedb_physical::physical_task::{PhysicalTask, PostSetOp};
use crate::control::server::response_shape::schema::OutputSchema;
use super::super::super::types::error_to_sqlstate;
use super::super::core::NodeDbPgHandler;
use super::super::plan::PlanKind;
use super::super::stream_response;
impl NodeDbPgHandler {
pub(super) async fn maybe_stream_select(
&self,
task: &PhysicalTask,
plan_kind: PlanKind,
post_set_op: PostSetOp,
addr: &std::net::SocketAddr,
projection: Option<&OutputSchema>,
result_formats: &[FieldFormat],
) -> PgWireResult<Option<Response>> {
if post_set_op != PostSetOp::None
|| !matches!(plan_kind, PlanKind::MultiRow)
|| self.sessions.transaction_state(addr)
== crate::control::server::shared::session::TransactionState::InBlock
{
return Ok(None);
}
let PhysicalPlan::Query(QueryOp::Exchange(ExchangeOp {
child,
mode: ExchangeMode::Gather {
as_aggregate: false,
},
})) = &task.plan
else {
return Ok(None);
};
if !child.is_streamable_unordered_scan() {
return Ok(None);
}
let limit = child.streamable_scan_limit();
let child_plan = (**child).clone();
let state = std::sync::Arc::clone(&self.state);
let stream = if let Some(gw) = state.gateway.get() {
let ctx = crate::control::gateway::core::QueryContext {
tenant_id: task.tenant_id,
trace_id: crate::types::TraceId::ZERO,
database_id: task.database_id,
txn_id: None,
};
gw.execute_stream(&ctx, child_plan).await
} else {
crate::control::server::exchange::gather::gather_all_cores_stream(
&state,
task.tenant_id,
task.database_id,
child_plan,
crate::types::TraceId::ZERO,
task.txn_id,
)
}
.map_err(|e| {
let (severity, code, message) = error_to_sqlstate(&e);
PgWireError::UserError(Box::new(ErrorInfo::new(
severity.to_owned(),
code.to_owned(),
message,
)))
})?;
let response = match projection {
Some(s) if !s.is_star && !s.columns.is_empty() => {
stream_response::streaming_shaped_response(stream, limit, s.clone(), result_formats)
}
Some(s) if s.is_star => stream_response::streaming_star_response(stream, limit).await,
_ => stream_response::streaming_multirow_response(stream, limit),
};
Ok(Some(response))
}
}