uqa_storage/sqlite/catalog/
stats.rs1use super::{params, Catalog, ColumnStatsInput, ColumnStatsRow, Result, SQLiteError};
10
11impl Catalog {
12 pub fn save_column_stats(&self, stats: ColumnStatsInput<'_>) -> Result<()> {
17 self.conn.with(|c| {
18 c.execute(
19 "INSERT OR REPLACE INTO _column_stats
20 (table_name, column_name, distinct_count, null_count,
21 min_value, max_value, row_count,
22 histogram, mcv_values, mcv_frequencies)
23 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
24 params![
25 stats.table_name,
26 stats.column_name,
27 stats.distinct_count,
28 stats.null_count,
29 stats.min_value,
30 stats.max_value,
31 stats.row_count,
32 stats.histogram_json,
33 stats.mcv_values_json,
34 stats.mcv_frequencies_json,
35 ],
36 )?;
37 Ok(())
38 })
39 }
40
41 pub fn replace_column_stats(
42 &self,
43 table_name: &str,
44 stats: &[ColumnStatsInput<'_>],
45 ) -> Result<()> {
46 if let Some(row) = stats.iter().find(|row| row.table_name != table_name) {
47 return Err(SQLiteError::StorageBackend(format!(
48 "column stats row for table `{}` cannot be stored in snapshot `{table_name}`",
49 row.table_name
50 )));
51 }
52 self.conn.with_mut(|connection| {
53 let transaction = connection.savepoint()?;
54 transaction.execute(
55 "DELETE FROM _column_stats WHERE table_name = ?1",
56 params![table_name],
57 )?;
58 {
59 let mut statement = transaction.prepare(
60 "INSERT INTO _column_stats
61 (table_name, column_name, distinct_count, null_count,
62 min_value, max_value, row_count,
63 histogram, mcv_values, mcv_frequencies)
64 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
65 )?;
66 for row in stats {
67 statement.execute(params![
68 row.table_name,
69 row.column_name,
70 row.distinct_count,
71 row.null_count,
72 row.min_value,
73 row.max_value,
74 row.row_count,
75 row.histogram_json,
76 row.mcv_values_json,
77 row.mcv_frequencies_json,
78 ])?;
79 }
80 }
81 transaction.commit()?;
82 Ok(())
83 })
84 }
85
86 pub fn load_column_stats(&self, table_name: &str) -> Result<Vec<ColumnStatsRow>> {
87 self.conn.with(|c| {
88 let mut stmt = c.prepare(
89 "SELECT column_name, distinct_count, null_count,
90 min_value, max_value, row_count,
91 histogram, mcv_values, mcv_frequencies
92 FROM _column_stats
93 WHERE table_name = ?1
94 ORDER BY column_name",
95 )?;
96 let rows = stmt.query_map(params![table_name], |r| {
97 Ok(ColumnStatsRow {
98 column_name: r.get::<_, String>(0)?,
99 distinct_count: r.get::<_, i64>(1)?,
100 null_count: r.get::<_, i64>(2)?,
101 min_value: r.get::<_, Option<String>>(3)?,
102 max_value: r.get::<_, Option<String>>(4)?,
103 row_count: r.get::<_, i64>(5)?,
104 histogram_json: r.get::<_, String>(6)?,
105 mcv_values_json: r.get::<_, String>(7)?,
106 mcv_frequencies_json: r.get::<_, String>(8)?,
107 })
108 })?;
109 let mut out = Vec::new();
110 for row in rows {
111 out.push(row?);
112 }
113 Ok(out)
114 })
115 }
116
117 pub fn delete_column_stats(&self, table_name: &str) -> Result<()> {
118 self.conn.with(|c| {
119 c.execute(
120 "DELETE FROM _column_stats WHERE table_name = ?1",
121 params![table_name],
122 )?;
123 Ok(())
124 })
125 }
126}