fix: empty select returns header

This commit is contained in:
Jindřich Moravec 2024-01-28 20:45:09 +01:00
parent 25bb21c29c
commit 8fc271695a
6 changed files with 99 additions and 65 deletions

View file

@ -11,6 +11,8 @@ anyhow = "1.0.76"
clap = { version = "4.4.18", features = ["derive"] }
async-trait = "0.1.74"
rand = "0.8.5"
rand_seeder = "0.2.3"
rand_pcg = "0.3.1"
serde_json = "1.0.112"
minisql = { path = "../minisql" }
proto = { path = "../proto" }

View file

@ -186,10 +186,10 @@ async fn handle_query<W>(writer: &mut W, state: &SharedDbState, query: String, t
writer.write_command_complete(CompleteStatus::Insert { oid: 0, rows: 1 }).await?;
true
}
Response::Selected(schema, mut rows) => {
Response::Selected(schema, columns, mut rows) => {
writer.write_table_header(&schema, &columns).await?;
match rows.next() {
Some(row) => {
writer.write_table_header(&schema, &row).await?;
writer.write_table_row(&row).await?;
let mut sent_rows = 1;

View file

@ -1,7 +1,10 @@
use async_trait::async_trait;
use rand::Rng;
use rand_pcg::Pcg64;
use rand_seeder::Seeder;
use minisql::operation::ColumnSelection;
use minisql::restricted_row::RestrictedRow;
use minisql::schema::TableSchema;
use minisql::type_system::{Value};
use proto::message::backend::{BackendMessage, ColumnDescription, CommandCompleteData, DataRowData, ErrorResponseData, ReadyForQueryData, RowDescriptionData};
use proto::message::primitive::pglist::PgList;
use proto::writer::backend::BackendProtoWriter;
@ -34,7 +37,7 @@ pub trait ServerProto {
async fn write_error_message(&mut self, error_message: &str) -> anyhow::Result<()>;
async fn write_ready_for_query(&mut self) -> anyhow::Result<()>;
async fn write_empty_query(&mut self) -> anyhow::Result<()>;
async fn write_table_header(&mut self, table_schema: &TableSchema, row: &RestrictedRow) -> anyhow::Result<()>;
async fn write_table_header(&mut self, table_schema: &TableSchema, columns: &ColumnSelection) -> anyhow::Result<()>;
async fn write_table_row(&mut self, row: &RestrictedRow) -> anyhow::Result<()>;
async fn write_command_complete(&mut self, status: CompleteStatus) -> anyhow::Result<()>;
}
@ -60,9 +63,9 @@ impl<W> ServerProto for W where W: BackendProtoWriter + Send {
Ok(())
}
async fn write_table_header(&mut self, table_schema: &TableSchema, row: &RestrictedRow) -> anyhow::Result<()> {
let columns = row.iter()
.map(|(index, value)| value_to_column_description(table_schema, value, *index))
async fn write_table_header(&mut self, table_schema: &TableSchema, columns: &ColumnSelection) -> anyhow::Result<()> {
let columns = columns.iter()
.map(|column| column_to_description(table_schema, *column))
.collect::<anyhow::Result<Vec<ColumnDescription>>>()?;
self.write_proto(RowDescriptionData { columns: columns.into() }.into()).await?;
@ -88,13 +91,16 @@ impl<W> ServerProto for W where W: BackendProtoWriter + Send {
}
}
fn value_to_column_description(schema: &TableSchema, value: &Value, index: usize) -> anyhow::Result<ColumnDescription> {
let name = schema.column_name_from_column(index);
fn column_to_description(schema: &TableSchema, column: usize) -> anyhow::Result<ColumnDescription> {
let table_name = schema.table_name();
let table_oid = table_name_to_oid(table_name);
let table_oid = schema.table_name().as_bytes().as_ptr() as i32;
let column_index = index.try_into()?;
let type_oid = value.type_oid();
let type_size = value.type_size();
let column_type = schema.column_type(column);
let name = schema.column_name_from_column(column);
let column_index = column.try_into()?;
let type_oid = column_type.type_oid();
let type_size = column_type.type_size();
Ok(ColumnDescription {
name: name.to_string().into(),
@ -106,3 +112,9 @@ fn value_to_column_description(schema: &TableSchema, value: &Value, index: usize
format_code: 0, // text format
})
}
/// Stable random number based on string
fn table_name_to_oid(table_name: &str) -> i32 {
let mut rng: Pcg64 = Seeder::from(table_name).make_rng();
rng.gen::<i32>()
}