use rudb_catalog::{Catalog, Database, Schema, Table};
use rudb_common::{LogicalType, Result, Value};
use rudb_functions::{
DUCKDB, canonical, column_fields, database_fields, numeric_facts, schema_fields, table_fields,
type_oid,
};
use rudb_parse::quoted;
use rudb_plan::{Plan, Slice};
use crate::metadata::{Metadata, text};
pub(crate) fn databasenames(
catalog: &Catalog,
plan: &Plan,
index: u32,
columns: Slice,
) -> Result<Metadata> {
let mut rows = Vec::with_capacity(catalog.databases().len());
for database in catalog.databases() {
rows.push(vec![
text(database.name()),
Value::BigInt(database.oid()),
Value::Null,
Value::Null,
empty(),
Value::Boolean(false),
text(DUCKDB),
Value::Boolean(false),
Value::Boolean(false),
Value::Null,
empty(),
]);
}
Metadata::new("duckdb_databases", &database_fields(), &rows, plan, index, columns)
}
pub(crate) fn schemanames(
catalog: &Catalog,
plan: &Plan,
index: u32,
columns: Slice,
) -> Result<Metadata> {
let mut rows = Vec::new();
for database in catalog.databases() {
for schema in database.schemas() {
rows.push(vec![
Value::BigInt(schema.oid()),
text(database.name()),
Value::BigInt(database.oid()),
text(schema.name()),
Value::Null,
empty(),
Value::Boolean(true),
Value::Null,
Value::Null,
Value::Null,
]);
}
}
Metadata::new("duckdb_schemas", &schema_fields(), &rows, plan, index, columns)
}
pub(crate) fn tablenames(
catalog: &Catalog,
plan: &Plan,
index: u32,
columns: Slice,
) -> Result<Metadata> {
let mut rows = Vec::new();
for (database, schema, table) in entries(catalog) {
let count = i64::try_from(table.columns().len()).unwrap_or(i64::MAX);
rows.push(vec![
text(database.name()),
Value::BigInt(database.oid()),
text(schema.name()),
Value::BigInt(schema.oid()),
text(&table.name().table),
Value::BigInt(table.oid()),
Value::Null,
empty(),
Value::Boolean(false),
Value::Boolean(false),
Value::Boolean(false),
Value::BigInt(i64::try_from(table.rows().len()).unwrap_or(i64::MAX)),
Value::BigInt(count),
Value::BigInt(0),
Value::BigInt(0),
text(&create_table(table)),
]);
}
Metadata::new("duckdb_tables", &table_fields(), &rows, plan, index, columns)
}
pub(crate) fn columnnames(
catalog: &Catalog,
plan: &Plan,
index: u32,
columns: Slice,
) -> Result<Metadata> {
let mut rows = Vec::new();
for (database, schema, table) in entries(catalog) {
for (at, column) in table.columns().iter().enumerate() {
let (precision, radix, scale) = numeric_facts(&column.ty);
rows.push(vec![
text(database.name()),
Value::BigInt(database.oid()),
text(schema.name()),
Value::BigInt(schema.oid()),
text(&table.name().table),
Value::BigInt(table.oid()),
text(&column.name),
Value::Integer(i32::try_from(at + 1).unwrap_or(i32::MAX)),
Value::Null,
Value::Boolean(false),
Value::Null,
Value::Boolean(!column.not_null),
text(&column.ty.to_string()),
type_oid(&canonical(&column.ty)).map_or(Value::Null, Value::BigInt),
Value::Null,
precision.map_or(Value::Null, Value::Integer),
radix.map_or(Value::Null, Value::Integer),
scale.map_or(Value::Null, Value::Integer),
empty(),
Value::Boolean(false),
Value::Null,
]);
}
}
Metadata::new("duckdb_columns", &column_fields(), &rows, plan, index, columns)
}
fn entries(catalog: &Catalog) -> impl Iterator<Item = (&Database, &Schema, &Table)> {
catalog.databases().iter().flat_map(|database| {
database.schemas().iter().flat_map(move |schema| {
schema.tables().iter().map(move |table| (database, schema, table))
})
})
}
fn create_table(table: &Table) -> String {
let columns: Vec<String> = table
.columns()
.iter()
.map(|column| {
let null = if column.not_null { " NOT NULL" } else { "" };
format!("{} {}{null}", quoted(&column.name), column.ty)
})
.collect();
format!("CREATE TABLE {}({});", quoted(&table.name().table), columns.join(", "))
}
fn empty() -> Value {
Value::map(LogicalType::Varchar, LogicalType::Varchar, Vec::new())
}