|
| 1 | +//! Every current receipt against the parser, whether or not a catalogued case cites it (decision D141). |
| 2 | +
|
| 3 | +use std::collections::{BTreeMap, BTreeSet}; |
| 4 | + |
| 5 | +use crate::check::_helpers::receipts::snowflake_syntax; |
| 6 | +use crate::check::models::{CaseResult, LocalVerdict, SnowflakeSyntax}; |
| 7 | +use crate::formats::models::{Receipt, SyntaxCoverage}; |
| 8 | + |
| 9 | +/// Whether the parser's verdict contradicts what Snowflake's parser did with the same statement. |
| 10 | +fn contradicts(snowflake: SnowflakeSyntax, local: &LocalVerdict) -> bool { |
| 11 | + match snowflake { |
| 12 | + SnowflakeSyntax::Parsed => !matches!(local, LocalVerdict::Accepted { .. }), |
| 13 | + SnowflakeSyntax::Refused => matches!(local, LocalVerdict::Accepted { .. }), |
| 14 | + } |
| 15 | +} |
| 16 | + |
| 17 | +/// The receipt case ids the parser contradicts by SQL, setup and session, and those without SQL. |
| 18 | +pub(crate) fn receipt_contradictions( |
| 19 | + coverage: &SyntaxCoverage, |
| 20 | + cases: &BTreeMap<&str, CaseResult>, |
| 21 | + parse: &dyn Fn(&str) -> LocalVerdict, |
| 22 | +) -> (BTreeSet<String>, BTreeSet<String>) { |
| 23 | + let mut statements: BTreeMap<(&str, &str, &str), Vec<&Receipt>> = BTreeMap::new(); |
| 24 | + for receipt in &coverage.receipts { |
| 25 | + statements |
| 26 | + .entry(( |
| 27 | + receipt.sql_sha256.as_str(), |
| 28 | + receipt.setup_sha256.as_str(), |
| 29 | + receipt.session_sha256.as_str(), |
| 30 | + )) |
| 31 | + .or_default() |
| 32 | + .push(receipt); |
| 33 | + } |
| 34 | + let mut judged: BTreeMap<&str, LocalVerdict> = cases |
| 35 | + .values() |
| 36 | + .map(|case| (case.sql_sha256.as_str(), case.local.clone())) |
| 37 | + .collect(); |
| 38 | + let case_sql: BTreeMap<&str, &str> = coverage |
| 39 | + .cases |
| 40 | + .values() |
| 41 | + .flatten() |
| 42 | + .map(|case| (case.sql_sha256.as_str(), case.sql.as_str())) |
| 43 | + .collect(); |
| 44 | + let mut contradicted: BTreeSet<String> = BTreeSet::new(); |
| 45 | + let mut unjudged: BTreeSet<String> = BTreeSet::new(); |
| 46 | + for ((sql_sha256, _, _), receipts) in &statements { |
| 47 | + let Some(snowflake) = snowflake_syntax(receipts) else { |
| 48 | + continue; |
| 49 | + }; |
| 50 | + let sql: Option<&str> = case_sql |
| 51 | + .get(sql_sha256) |
| 52 | + .copied() |
| 53 | + .or_else(|| coverage.receipt_sql.get(*sql_sha256).map(String::as_str)); |
| 54 | + let Some(sql) = sql else { |
| 55 | + unjudged.extend(receipts.iter().map(|receipt| receipt.case_id.clone())); |
| 56 | + continue; |
| 57 | + }; |
| 58 | + let local: &LocalVerdict = judged.entry(sql_sha256).or_insert_with(|| parse(sql)); |
| 59 | + if contradicts(snowflake, local) { |
| 60 | + contradicted.extend(receipts.iter().map(|receipt| receipt.case_id.clone())); |
| 61 | + } |
| 62 | + } |
| 63 | + (contradicted, unjudged) |
| 64 | +} |
0 commit comments