From 28e790d0b9ce1b81c788677ba05bb108b0c595c7 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Fri, 6 Nov 2026 14:25:14 +0000 Subject: [PATCH 1/3] Bind the translation figure to its obligations (D272) Load coverage/translation/obligations/.toml fail-closed, with held and unmeasured obligations and retired-obligations.toml. A form matches only when every required obligation is met by all its cited cases; held and unmeasured obligations are never met and are reported in their own buckets, with the recorded cases no obligation cites. --- coverage/translation/README.md | 29 +- .../src/cli/_helpers/results_command.rs | 15 +- .../src/results/_helpers/diff.rs | 10 +- .../src/results/_helpers/files.rs | 6 +- .../src/results/_helpers/forms.rs | 23 +- .../src/results/_helpers/mod.rs | 1 + .../src/results/_helpers/obligations.rs | 250 ++++++++++++ .../src/results/_helpers/report.rs | 59 ++- .../src/results/constants.rs | 20 + .../src/results/main/diff_results.rs | 18 +- .../src/results/main/load_results_files.rs | 4 +- .../src/results/main/measure_results.rs | 11 +- .../src/results/main/results_baseline.rs | 1 + .../src/results/models.rs | 106 ++++++ .../src/results/tests.rs | 2 + .../src/results/tests/helpers.rs | 40 ++ .../src/results/tests/test_obligations.rs | 357 ++++++++++++++++++ .../src/results/tests/test_types.rs | 40 +- 18 files changed, 967 insertions(+), 25 deletions(-) create mode 100644 crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs create mode 100644 crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs diff --git a/coverage/translation/README.md b/coverage/translation/README.md index 763a62bd9..86db93c06 100644 --- a/coverage/translation/README.md +++ b/coverage/translation/README.md @@ -15,6 +15,17 @@ separately from syntax coverage, and every figure comes from the checker. - `not-translatable.toml`: forms with no meaningful DuckDB translation, in groups, each with its reason. A group leaves the denominator only once the auditor signs it off in `reviews/auditor-results.toml`, which binds its reason and forms by SHA-256. +- `obligations/.toml`: what each form must be shown to do (decision D272). Each + `[[obligation]]` has `id` (`
.t`), `form`, `kind` (`type_combination`, + `null_argument`, `boundary` with a `subkind`, `error_parity`), `target`, `note`, `catches`, + `reading`, `cases` (references `cases/translation//.toml#`) and `required`. + Two shapes have no case: + - held: `required = true`, `cases = []`, `held = ""`, for a case held back (a parse gap, + a case waiting on another PR or a receipt). It is never met, so its form cannot match. + - unmeasured: `required = false`, `cases = []`, `reason = ""`, for a documented + alternative no case can measure. It is never met and does not block its form. +- `retired-obligations.toml`: withdrawn obligation ids, each `[[retired]]` with `id`, `form`, + `reason` and `replaced_by` (live obligation ids). A retired id is never reused. - `results-baseline.json`: every statement's outcome and every form's state, as the checker last measured them. @@ -41,10 +52,16 @@ forms when it names none. Any other statement counts for every form it links to. | `not_translatable` | Listed in a signed-off group. Outside the denominator. | | `differs` | Any linked statement differs. | | `refused` | Any linked statement is refused for it, raised a guard for it, or cannot be judged. | -| `matching` | Otherwise, at least one linked statement returns Snowflake's rows. | +| `unmet_obligations` | Otherwise, a linked statement returns Snowflake's rows, but a required obligation is unmet or held. | +| `matching` | Otherwise, at least one linked statement returns Snowflake's rows, and every required obligation is met. | | `syntax_only` | Otherwise, linked statements exist but none returns compared rows: only types or matching errors. | | `unmeasured` | No recorded statement links to it. | +An obligation is `met` when it cites at least one case and every cited case is `matching` or +`matching_error`; otherwise it is `unmet`, or `held` or `unmeasured` by its shape. The report lists +each obligation's state, the `held` and `unmeasured` obligations with their reasons, and the +`uncited_cases`: recorded translation cases no obligation cites, which can make no form match. + ## Figures - Forms: `matching` forms out of all catalogued forms less the signed-off not-translatable ones. @@ -63,10 +80,16 @@ syntax-coverage results target/translation-statements.json --report target/trans syntax-coverage results target/translation-statements.json --write-baseline ``` -The check fails on a construct that neither links nor names no form, a link to a form the catalogue +The check fails on an obligation file it cannot read whole: an unknown key, a form the catalogue +does not hold or that is absent from its source, an id that is not the form's or is declared or +retired twice, a case outside its family's folder, cited twice or not recorded, a boundary without +a known subkind, a required obligation with neither cases nor a `held` reason, a blank reason, and +a retired id that is reused or replaced by an id that is not a live obligation. It also fails on a +construct that neither links nor names no form, a link to a form the catalogue does not hold, a signed-off not-translatable form with a matching statement, and any difference from `results-baseline.json`. Against the target branch's baseline it prints the diff and fails if a -statement or form drops out of matching, or becomes `differs`. +statement or form drops out of matching, a met obligation stops being met, or anything becomes +`differs`. The report's worklist lists differences first, then refusals by how many forms each keeps from matching, then forms that need a recorded result. diff --git a/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs b/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs index 790ec42d9..3b3adda35 100644 --- a/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs +++ b/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs @@ -44,13 +44,14 @@ fn percent(part: usize, whole: usize) -> String { fn tally_line(name: &str, tally: &FormTally) -> String { format!( - "{name}: {} of {} translatable forms match ({}); {} syntax only, {} refused, {} differ, \ - {} unmeasured; {} of {} catalogued forms not translatable", + "{name}: {} of {} translatable forms match ({}); {} syntax only, {} refused, {} with unmet \ + obligations, {} differ, {} unmeasured; {} of {} catalogued forms not translatable", tally.matching, tally.translatable, percent(tally.matching, tally.translatable), tally.syntax_only, tally.refused, + tally.unmet_obligations, tally.differs, tally.unmeasured, tally.not_translatable, @@ -92,6 +93,16 @@ fn report_lines(report: &ResultsReport) -> Vec { .collect::>() .join(", ") ), + format!( + "obligations: {} declared, {} met, {} unmet, {} held, {} unmeasured; a form matches only \ + when every required obligation is met; {} recorded translation cases cite none", + report.obligations.declared, + report.obligations.met, + report.obligations.unmet, + report.obligations.held, + report.obligations.unmeasured, + report.uncited_cases.len(), + ), tally_line("total", &report.forms), ]; lines.extend( diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs index 3c373a1d6..1c96daf81 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::fmt::Debug; -use crate::results::models::{ResultState, ResultsDiff, StatementOutcome}; +use crate::results::models::{ObligationState, ResultState, ResultsDiff, StatementOutcome}; /// Whether a change from the old value or none to the new or none regresses. pub(crate) type Regresses = fn(Option, Option) -> bool; @@ -25,6 +25,14 @@ pub(crate) fn form_regresses(base: Option, head: Option, + head: Option, +) -> bool { + base == Some(ObligationState::Met) && head != Some(ObligationState::Met) +} + /// Each changed key of one kind, as a regression or another change. pub(crate) fn compare( label: &str, diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs index 0620a2e3d..8a97a1a6f 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs @@ -7,6 +7,7 @@ use serde::de::DeserializeOwned; use crate::formats::main::content_sha256::content_sha256; use crate::formats::main::is_utc_timestamp::is_utc_timestamp; +use crate::results::_helpers::obligations::load_obligations; use crate::results::constants::{ FORM_LINKS_SUBJECT, FUNCTION_LINKS_SUBJECT, LINKS_FILE, NOT_TRANSLATABLE_FILE, NOT_TRANSLATABLE_SUBJECT, RESULTS_REVIEW_FILE, @@ -149,8 +150,9 @@ fn check_review(review: &ResultsReviewFile) -> Vec { /// The files under `directory`, or every problem with them; ids must be catalogued forms. pub(crate) fn load_files( directory: &Path, - catalogued: &BTreeSet<&str>, + families: &BTreeMap<&str, &str>, ) -> Result> { + let catalogued: &BTreeSet<&str> = &families.keys().copied().collect(); let read = |name: &str| { let path = directory.join(name); read_text(&path).map(|text| (path, text)) @@ -182,11 +184,13 @@ pub(crate) fn load_files( if !problems.is_empty() { return Err(problems); } + let obligations = load_obligations(directory, families)?; Ok(ResultsFiles { links, not_translatable, review, links_sha256: content_sha256(links_text.as_bytes()), + obligations, }) } diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs index 7b1d39a66..98ef807f3 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs @@ -6,8 +6,12 @@ use crate::results::models::{ FormResult, FormTally, RecordedStatement, ResultState, StatementOutcome, StatementTally, }; -/// A form's state: listed, then any statement that differs, then any refused, then matching rows. -pub(crate) fn form_state(listed: bool, outcomes: &[StatementOutcome]) -> ResultState { +/// A form's state: listed, differs, refused, then matching only with every obligation met. +pub(crate) fn form_state( + listed: bool, + outcomes: &[StatementOutcome], + obligations_met: bool, +) -> ResultState { if listed { return ResultState::NotTranslatable; } @@ -20,9 +24,13 @@ pub(crate) fn form_state(listed: bool, outcomes: &[StatementOutcome]) -> ResultS if outcomes.iter().any(|outcome| outcome.refused()) { return ResultState::Refused; } - match outcomes.contains(&StatementOutcome::Matching) { - true => ResultState::Matching, - false => ResultState::SyntaxOnly, + match ( + outcomes.contains(&StatementOutcome::Matching), + obligations_met, + ) { + (true, true) => ResultState::Matching, + (true, false) => ResultState::UnmetObligations, + (false, _) => ResultState::SyntaxOnly, } } @@ -31,6 +39,7 @@ pub(crate) fn form_result( (id, family): (&str, &str), listed: bool, linked: &[&RecordedStatement], + unmet_obligations: Vec, ) -> FormResult { let outcomes: Vec = linked.iter().map(|statement| statement.outcome).collect(); @@ -42,9 +51,10 @@ pub(crate) fn form_result( FormResult { id: id.to_owned(), family: family.to_owned(), - state: form_state(listed, &outcomes), + state: form_state(listed, &outcomes, unmet_obligations.is_empty()), statements: linked.len(), matching_statements: outcomes.iter().filter(|outcome| outcome.matches()).count(), + unmet_obligations, codes: codes.into_iter().collect(), } } @@ -59,6 +69,7 @@ pub(crate) fn tally<'a>(forms: impl Iterator) -> FormTall ResultState::Matching => &mut tally.matching, ResultState::SyntaxOnly => &mut tally.syntax_only, ResultState::Refused => &mut tally.refused, + ResultState::UnmetObligations => &mut tally.unmet_obligations, ResultState::Differs => &mut tally.differs, ResultState::Unmeasured => &mut tally.unmeasured, }; diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/mod.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/mod.rs index f49f47a64..93a2ec27e 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/mod.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/mod.rs @@ -2,5 +2,6 @@ pub(crate) mod diff; pub(crate) mod files; pub(crate) mod forms; pub(crate) mod links; +pub(crate) mod obligations; pub(crate) mod report; pub(crate) mod worklist; diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs new file mode 100644 index 000000000..f70166532 --- /dev/null +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs @@ -0,0 +1,250 @@ +//! The per-family obligation files, read fail-closed, and each obligation's state. + +use std::collections::{BTreeMap, BTreeSet}; +use std::path::Path; + +use crate::results::constants::{ + BOUNDARY_SUBKINDS, OBLIGATION_CASES_PREFIX, OBLIGATION_FILE_EXTENSION, OBLIGATIONS_DIR, + RETIRED_OBLIGATIONS_FILE, TRANSLATION_CASES, +}; +use crate::results::models::{ + ObligationKind, ObligationState, ObligationsFile, RecordedStatement, RetiredFile, + TranslationObligation, +}; + +/// Every obligation under `directory/obligations`, or every problem; none when the directory is absent. +pub(crate) fn load_obligations( + directory: &Path, + catalogued: &BTreeMap<&str, &str>, +) -> Result, Vec> { + let folder = directory.join(OBLIGATIONS_DIR); + let entries = match std::fs::read_dir(&folder) { + Ok(entries) => entries, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()), + Err(error) => return Err(vec![format!("{}: {error}", folder.display())]), + }; + let mut paths: Vec = Vec::new(); + for entry in entries { + paths.push( + entry + .map_err(|error| vec![format!("{}: {error}", folder.display())])? + .path(), + ); + } + paths.sort(); + let families: BTreeSet<&str> = catalogued.values().copied().collect(); + let mut problems: Vec = Vec::new(); + let mut obligations: Vec = Vec::new(); + for path in paths { + let label = path.display().to_string(); + let family = match (path.extension(), path.file_stem()) { + (Some(extension), Some(stem)) if extension == OBLIGATION_FILE_EXTENSION => { + stem.to_string_lossy() + } + _ => { + problems.push(format!("{label}: not a .toml obligation file")); + continue; + } + }; + if !families.contains(family.as_ref()) { + problems.push(format!("{label}: {family} is not a catalogue family")); + continue; + } + let parsed = std::fs::read_to_string(&path) + .map_err(|error| error.to_string()) + .and_then(|text| { + toml::from_str::(&text).map_err(|error| error.to_string()) + }); + match parsed { + Ok(file) => { + for obligation in file.obligations { + problems.extend( + obligation_problems(&obligation, (&family, catalogued)) + .into_iter() + .map(|problem| format!("obligation {}: {problem}", obligation.id)), + ); + obligations.push(obligation); + } + } + Err(error) => problems.push(format!("{label}: {error}")), + } + } + let mut ids: BTreeSet<&str> = BTreeSet::new(); + for obligation in &obligations { + if !ids.insert(&obligation.id) { + problems.push(format!("obligation {}: declared twice", obligation.id)); + } + } + problems.extend(retired_problems(directory, &ids)); + match problems.is_empty() { + true => Ok(obligations), + false => Err(problems), + } +} + +/// Every problem with the retired ids: a reused id, a blank reason, or an unresolved replacement. +fn retired_problems(directory: &Path, live: &BTreeSet<&str>) -> Vec { + let path = directory.join(RETIRED_OBLIGATIONS_FILE); + let text = match std::fs::read_to_string(&path) { + Ok(text) => text, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Vec::new(), + Err(error) => return vec![format!("{}: {error}", path.display())], + }; + let file: RetiredFile = match toml::from_str(&text) { + Ok(file) => file, + Err(error) => return vec![format!("{}: {error}", path.display())], + }; + let mut problems: Vec = Vec::new(); + let mut seen: BTreeSet<&str> = BTreeSet::new(); + for retired in &file.retired { + let id = retired.id.as_str(); + if !seen.insert(id) { + problems.push(format!("retired obligation {id}: retired twice")); + } + if live.contains(id) { + problems.push(format!( + "retired obligation {id}: the id is reused in obligations/" + )); + } + if retired.reason.trim().is_empty() || retired.form.trim().is_empty() { + problems.push(format!( + "retired obligation {id}: needs its form and a reason" + )); + } + for replacement in &retired.replaced_by { + if !live.contains(replacement.as_str()) { + problems.push(format!( + "retired obligation {id}: replaced_by {replacement} is not a live obligation" + )); + } + } + } + problems +} + +/// Whether `text` holds something other than whitespace. +fn written(text: Option<&String>) -> bool { + text.is_some_and(|text| !text.trim().is_empty()) +} + +/// Every problem with one obligation in the file of `family`. +fn obligation_problems( + obligation: &TranslationObligation, + (family, catalogued): (&str, &BTreeMap<&str, &str>), +) -> Vec { + let mut problems: Vec = Vec::new(); + match catalogued.get(obligation.form.as_str()) { + None => problems.push(format!( + "{} is not a catalogued form still in its source; retarget or remove the obligation", + obligation.form + )), + Some(owner) if *owner != family => problems.push(format!( + "{} belongs to {owner}, not {family}", + obligation.form + )), + Some(_) => {} + } + let number = obligation + .id + .strip_prefix(obligation.form.as_str()) + .and_then(|rest| rest.strip_prefix(".t")); + if !number + .is_some_and(|digits| !digits.is_empty() && digits.bytes().all(|b| b.is_ascii_digit())) + { + problems.push(format!("the id is not {}.t", obligation.form)); + } + let boundary = obligation.kind == ObligationKind::Boundary; + match (&obligation.subkind, boundary) { + (Some(subkind), true) if BOUNDARY_SUBKINDS.contains(&subkind.as_str()) => {} + (Some(subkind), true) => problems.push(format!("subkind {subkind} is not a boundary kind")), + (None, true) => problems.push("a boundary obligation needs a subkind".to_owned()), + (Some(_), false) => problems.push("only a boundary obligation has a subkind".to_owned()), + (None, false) => {} + } + let prefix = format!("{OBLIGATION_CASES_PREFIX}{TRANSLATION_CASES}{family}/"); + let mut cited: BTreeSet<&str> = BTreeSet::new(); + for case in &obligation.cases { + if !case.starts_with(&prefix) || !case.contains(".toml#") { + problems.push(format!("case {case} is not {prefix}.toml#")); + } + if !cited.insert(case) { + problems.push(format!("cites {case} twice")); + } + } + let empty = obligation.cases.is_empty(); + let (held, reason) = (obligation.held.as_ref(), obligation.reason.as_ref()); + let shape = match (obligation.required, empty) { + (true, false) if held.is_none() && reason.is_none() => None, + (true, false) => Some("a required obligation with cases has neither held nor reason"), + (true, true) if reason.is_some() => { + Some("a required obligation has no reason; held says why it has no case") + } + (true, true) if !written(held) => { + Some("a required obligation with no cases needs a non-empty held reason") + } + (true, true) => None, + (false, _) if held.is_some() => Some("held is for required obligations"), + (false, false) => Some("an obligation that is not required cites no cases"), + (false, true) if !written(reason) => { + Some("an obligation that is not required needs a non-empty reason") + } + (false, true) => None, + }; + problems.extend(shape.map(str::to_owned)); + problems +} + +/// Each obligation's state; a cited case no statement records is a problem. +pub(crate) fn obligation_states( + obligations: &[TranslationObligation], + statements: &[RecordedStatement], +) -> Result, Vec> { + let outcomes: BTreeMap<&str, _> = statements + .iter() + .map(|statement| (statement.reference.as_str(), statement.outcome)) + .collect(); + let mut problems: Vec = Vec::new(); + let mut states: BTreeMap = BTreeMap::new(); + for obligation in obligations { + let mut met = !obligation.cases.is_empty(); + for case in &obligation.cases { + let reference = case.strip_prefix(OBLIGATION_CASES_PREFIX).unwrap_or(case); + match outcomes.get(reference) { + Some(outcome) => met &= outcome.matches(), + None => problems.push(format!( + "obligation {}: no recorded statement is the case {case}", + obligation.id + )), + } + } + let state = match (obligation.required, obligation.held.is_some(), met) { + (false, _, _) => ObligationState::Unmeasured, + (true, true, _) => ObligationState::Held, + (true, false, true) => ObligationState::Met, + (true, false, false) => ObligationState::Unmet, + }; + states.insert(obligation.id.clone(), state); + } + match problems.is_empty() { + true => Ok(states), + false => Err(problems), + } +} + +/// The recorded translation cases no obligation cites, by reference. +pub(crate) fn uncited_cases( + obligations: &[TranslationObligation], + statements: &[RecordedStatement], +) -> Vec { + let cited: BTreeSet<&str> = obligations + .iter() + .flat_map(|obligation| &obligation.cases) + .map(|case| case.strip_prefix(OBLIGATION_CASES_PREFIX).unwrap_or(case)) + .collect(); + statements + .iter() + .map(|statement| statement.reference.as_str()) + .filter(|reference| reference.starts_with(TRANSLATION_CASES) && !cited.contains(reference)) + .map(str::to_owned) + .collect() +} diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs index 7c4c5fc36..dd876ffaf 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs @@ -6,10 +6,12 @@ use crate::formats::models::SyntaxCoverage; use crate::results::_helpers::files::{group_sha256, signed, subjects}; use crate::results::_helpers::forms::{family_tallies, form_result, statement_tally}; use crate::results::_helpers::links::{FunctionIndex, link_statement}; +use crate::results::_helpers::obligations::uncited_cases; use crate::results::_helpers::worklist::worklist; use crate::results::constants::{NOT_TRANSLATABLE_SUBJECT, QUERY_FAMILIES}; use crate::results::models::{ - FormResult, RecordedStatement, ResultState, ResultsFiles, ResultsReport, StatementOutcome, + FormResult, ObligationState, ObligationTally, RecordedStatement, ResultState, ResultsFiles, + ResultsReport, StatementOutcome, TranslationObligation, }; use crate::translation::main::catalogued_forms::catalogued_forms; @@ -80,7 +82,21 @@ pub(crate) fn form_results( coverage: &SyntaxCoverage, files: &ResultsFiles, (statements, links): (&[RecordedStatement], &Links), + states: &BTreeMap, ) -> Result, Vec> { + let mut unmet: BTreeMap<&str, Vec> = BTreeMap::new(); + for obligation in files + .obligations + .iter() + .filter(|obligation| obligation.required) + { + if states.get(&obligation.id) != Some(&ObligationState::Met) { + unmet + .entry(obligation.form.as_str()) + .or_default() + .push(obligation.id.clone()); + } + } let mut linked: BTreeMap<&str, Vec<&RecordedStatement>> = BTreeMap::new(); for statement in statements { let forms = links.get(statement.reference.as_str()); @@ -103,7 +119,8 @@ pub(crate) fn form_results( matching.reference )); } - results.push(form_result((id, family), is_listed, statements)); + let unmet_here = unmet.get(id).cloned().unwrap_or_default(); + results.push(form_result((id, family), is_listed, statements, unmet_here)); } match problems.is_empty() { true => Ok(results), @@ -148,8 +165,18 @@ pub(crate) fn assemble( files: &ResultsFiles, functions: FunctionIndex, (statements, links): (&[RecordedStatement], &Links), - form_results: Vec, + (form_results, obligation_states): (Vec, BTreeMap), ) -> ResultsReport { + let mut obligations = ObligationTally::default(); + for state in obligation_states.values() { + obligations.declared += 1; + *match state { + ObligationState::Met => &mut obligations.met, + ObligationState::Unmet => &mut obligations.unmet, + ObligationState::Held => &mut obligations.held, + ObligationState::Unmeasured => &mut obligations.unmeasured, + } += 1; + } let with_forms: BTreeSet<&str> = links .iter() .filter(|(_, forms)| !forms.is_empty()) @@ -187,5 +214,31 @@ pub(crate) fn assemble( .map(|statement| (statement.reference.clone(), statement.outcome)) .collect(), form_results, + obligations, + held: reasons(&files.obligations, |obligation| obligation.held.as_ref()), + unmeasured: reasons(&files.obligations, |obligation| { + obligation.reason.as_ref().filter(|_| !obligation.required) + }), + uncited_cases: uncited_cases(&files.obligations, statements), + obligation_states, } } + +/// Each obligation `pick` gives a reason for, by id. +fn reasons( + obligations: &[TranslationObligation], + pick: fn(&TranslationObligation) -> Option<&String>, +) -> BTreeMap { + obligations + .iter() + .filter_map(|obligation| reason(obligation, pick)) + .collect() +} + +/// The obligation's id and the reason `pick` gives, if any. +fn reason( + obligation: &TranslationObligation, + pick: fn(&TranslationObligation) -> Option<&String>, +) -> Option<(String, String)> { + pick(obligation).map(|why| (obligation.id.clone(), why.clone())) +} diff --git a/crates/sqlquack-syntax-coverage/src/results/constants.rs b/crates/sqlquack-syntax-coverage/src/results/constants.rs index 8e902d816..72b58f647 100644 --- a/crates/sqlquack-syntax-coverage/src/results/constants.rs +++ b/crates/sqlquack-syntax-coverage/src/results/constants.rs @@ -42,3 +42,23 @@ pub const CALL_BARE: &str = "call_bare:"; pub const CALL_PREFIXES: [&str; 4] = [CALL, CALL_OVER, CALL_NAMED, CALL_BARE]; /// The refused construct of a refusal that names no construct: the whole statement. pub const STATEMENT_REFUSAL: &str = "statement"; +/// The directory of per-family obligation files, in the translation directory. +pub const OBLIGATIONS_DIR: &str = "obligations"; +/// The prefix of every case an obligation cites, before the statement's reference. +pub const OBLIGATION_CASES_PREFIX: &str = "cases/"; +/// The directory under the evidence cases holding translation cases. +pub const TRANSLATION_CASES: &str = "translation/"; +/// The boundary kinds a boundary obligation may name. +pub const BOUNDARY_SUBKINDS: [&str; 7] = [ + "overflow", + "magnitude", + "rounding_scale", + "empty_string", + "negative", + "timezone_dst", + "leap_day", +]; +/// Withdrawn obligation ids, in the translation directory. +pub const RETIRED_OBLIGATIONS_FILE: &str = "retired-obligations.toml"; +/// The extension of each `` obligation file. +pub const OBLIGATION_FILE_EXTENSION: &str = "toml"; diff --git a/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs b/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs index 39555153f..5e2c5617f 100644 --- a/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs +++ b/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs @@ -1,6 +1,8 @@ //! `diff_results`: a baseline against a later one; drops out of matching and into differs regress. -use crate::results::_helpers::diff::{compare, form_regresses, statement_regresses}; +use crate::results::_helpers::diff::{ + compare, form_regresses, obligation_regresses, statement_regresses, +}; use crate::results::models::{ResultsBaseline, ResultsDiff}; /// How `head` differs from `base`; any regression fails the gate, any change needs a new baseline. @@ -11,8 +13,18 @@ pub fn diff_results(base: &ResultsBaseline, head: &ResultsBaseline) -> ResultsDi statement_regresses, ); let forms = compare("form", (&base.forms, &head.forms), form_regresses); + let obligations = compare( + "obligation", + (&base.obligations, &head.obligations), + obligation_regresses, + ); ResultsDiff { - regressions: [statements.regressions, forms.regressions].concat(), - changes: [statements.changes, forms.changes].concat(), + regressions: [ + statements.regressions, + forms.regressions, + obligations.regressions, + ] + .concat(), + changes: [statements.changes, forms.changes, obligations.changes].concat(), } } diff --git a/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs b/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs index 1b6d10466..d4bd4d60b 100644 --- a/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs +++ b/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs @@ -1,6 +1,5 @@ //! `load_results_files`: the link, list and review files, checked against the catalogue. -use std::collections::BTreeSet; use std::path::Path; use crate::formats::models::SyntaxCoverage; @@ -13,6 +12,5 @@ pub fn load_results_files( directory: &Path, coverage: &SyntaxCoverage, ) -> Result> { - let catalogued: BTreeSet<&str> = catalogued_forms(coverage, None).into_keys().collect(); - load_files(directory, &catalogued) + load_files(directory, &catalogued_forms(coverage, None)) } diff --git a/crates/sqlquack-syntax-coverage/src/results/main/measure_results.rs b/crates/sqlquack-syntax-coverage/src/results/main/measure_results.rs index 59f2d6593..b292cefb6 100644 --- a/crates/sqlquack-syntax-coverage/src/results/main/measure_results.rs +++ b/crates/sqlquack-syntax-coverage/src/results/main/measure_results.rs @@ -2,6 +2,7 @@ use crate::formats::models::SyntaxCoverage; use crate::results::_helpers::links::function_index; +use crate::results::_helpers::obligations::obligation_states; use crate::results::_helpers::report::{assemble, form_results, link_all}; use crate::results::constants::STATEMENTS_FORMAT; use crate::results::models::{ResultsFiles, ResultsReport, StatementsFile}; @@ -21,6 +22,12 @@ pub fn measure_results( let statements = statements.statements.as_slice(); let functions = function_index(coverage); let links = link_all(statements, &functions, files)?; - let results = form_results(coverage, files, (statements, &links))?; - Ok(assemble(files, functions, (statements, &links), results)) + let states = obligation_states(&files.obligations, statements)?; + let results = form_results(coverage, files, (statements, &links), &states)?; + Ok(assemble( + files, + functions, + (statements, &links), + (results, states), + )) } diff --git a/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs b/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs index b0323dc22..d0a681b31 100644 --- a/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs +++ b/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs @@ -13,5 +13,6 @@ pub fn results_baseline(report: &ResultsReport) -> ResultsBaseline { .iter() .map(|form| (form.id.clone(), form.state)) .collect(), + obligations: report.obligation_states.clone(), } } diff --git a/crates/sqlquack-syntax-coverage/src/results/models.rs b/crates/sqlquack-syntax-coverage/src/results/models.rs index eaf03f86a..537c0c12c 100644 --- a/crates/sqlquack-syntax-coverage/src/results/models.rs +++ b/crates/sqlquack-syntax-coverage/src/results/models.rs @@ -131,6 +131,93 @@ pub struct ResultsSignoff { pub reviewed_utc: String, } +/// `obligations/.toml`: what a family's forms must show before they count as matching. +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ObligationsFile { + #[serde(default, rename = "obligation")] + pub obligations: Vec, +} + +/// One documented behaviour of a form, met only by a cited case whose replay matches Snowflake. +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct TranslationObligation { + /// `.t`. + pub id: String, + pub form: String, + pub kind: ObligationKind, + /// The boundary's kind, on boundary obligations only. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub subkind: Option, + pub target: String, + pub note: String, + pub catches: String, + pub reading: String, + /// `cases/translation//.toml#`. + pub cases: Vec, + pub required: bool, + /// Why a required obligation has no case yet; it is never met. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub held: Option, + /// Why an obligation that is not required no case can measure; it is never met. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub reason: Option, +} + +/// `retired-obligations.toml`: obligation ids withdrawn, never to be reused. +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RetiredFile { + #[serde(default, rename = "retired")] + pub retired: Vec, +} + +/// One withdrawn obligation id, why, and the live obligations that carry its cases now. +#[derive(Clone, Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct RetiredObligation { + pub id: String, + pub form: String, + pub reason: String, + #[serde(default)] + pub replaced_by: Vec, +} + +/// What a translation obligation checks. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum ObligationKind { + TypeCombination, + NullArgument, + Boundary, + ErrorParity, +} + +/// Whether an obligation is met: only `met` lets its form count as matching. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum ObligationState { + /// A cited case translates with results matching Snowflake. + Met, + /// Required, and no cited case matches: refused, differing, unrecorded or only shaped. + Unmet, + /// Required, with no case yet and a `held` reason. + Held, + /// Not required: a documented alternative no case can measure, with its reason. + Unmeasured, +} + +/// Obligation counts by state. +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)] +pub struct ObligationTally { + pub declared: usize, + pub met: usize, + pub unmet: usize, + pub held: usize, + pub unmeasured: usize, +} + /// The loaded link and list files, checked against the catalogue. #[derive(Clone, Debug)] pub struct ResultsFiles { @@ -139,6 +226,8 @@ pub struct ResultsFiles { pub review: ResultsReviewFile, /// SHA-256 of `form-links.toml`'s text. pub links_sha256: String, + /// Every family's obligations, in file then declaration order. + pub obligations: Vec, } /// A form's state over the recorded statements linked to it. @@ -153,6 +242,8 @@ pub enum ResultState { SyntaxOnly, /// A statement's refusal or guard raise names it, or a statement linked to it cannot be judged. Refused, + /// Its statements would match, but a required obligation is unmet or held. + UnmetObligations, /// At least one linked statement's replay differs from Snowflake's result: a bug. Differs, /// No recorded statement links to it. @@ -167,6 +258,9 @@ pub struct FormResult { pub state: ResultState, pub statements: usize, pub matching_statements: usize, + /// Its required obligations that are not met, by id. + #[serde(skip_serializing_if = "Vec::is_empty")] + pub unmet_obligations: Vec, /// The refusal codes of its statements, sorted and distinct. #[serde(skip_serializing_if = "Vec::is_empty")] pub codes: Vec, @@ -182,6 +276,7 @@ pub struct FormTally { pub matching: usize, pub syntax_only: usize, pub refused: usize, + pub unmet_obligations: usize, pub differs: usize, pub unmeasured: usize, } @@ -237,6 +332,14 @@ pub struct ResultsReport { pub function_links_sha256: String, pub form_results: Vec, pub statement_outcomes: BTreeMap, + pub obligations: ObligationTally, + /// Each obligation's state, by id. + pub obligation_states: BTreeMap, + /// Each held obligation's reason, and each unmeasured one's. + pub held: BTreeMap, + pub unmeasured: BTreeMap, + /// Recorded translation cases no obligation cites; they can make no form match. + pub uncited_cases: Vec, } /// `results-baseline.json`: every statement's outcome and every form's state. @@ -246,6 +349,9 @@ pub struct ResultsBaseline { pub format: String, pub statements: BTreeMap, pub forms: BTreeMap, + /// Absent from baselines written before obligations were read. + #[serde(default)] + pub obligations: BTreeMap, } /// How a report differs from the baseline. diff --git a/crates/sqlquack-syntax-coverage/src/results/tests.rs b/crates/sqlquack-syntax-coverage/src/results/tests.rs index 7778a1ced..b69d0edab 100644 --- a/crates/sqlquack-syntax-coverage/src/results/tests.rs +++ b/crates/sqlquack-syntax-coverage/src/results/tests.rs @@ -4,5 +4,7 @@ pub(crate) mod helpers; mod test_diff_results; #[path = "tests/test_measure_results.rs"] mod test_measure_results; +#[path = "tests/test_obligations.rs"] +mod test_obligations; #[path = "tests/test_types.rs"] mod test_types; diff --git a/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs b/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs index 13441d72b..3ee1b571a 100644 --- a/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs +++ b/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs @@ -174,3 +174,43 @@ pub(crate) fn form_state( .expect("form"); (form.state, form.statements, report.forms.translatable) } + +/// The cited case of the COUNT_IF obligations, as a statement reference and as a case path. +pub(crate) const COUNT_IF_CASE: &str = "translation/functions/count-if.toml#t001"; + +/// One COUNT_IF obligation numbered `number`, with `fields` after its descriptive keys. +pub(crate) fn obligation(number: u32, fields: &str) -> String { + format!( + "[[obligation]]\nid = \"sf.functions.count-if.t{number:03}\"\nform = \"sf.functions.count-if\"\n\ + kind = \"type_combination\"\ntarget = \"BOOLEAN\"\nnote = \"n\"\ncatches = \"c\"\n\ + reading = \"r\"\n{fields}\n" + ) +} + +/// The fields of a required obligation citing `reference` under `cases/`. +pub(crate) fn citing(reference: &str) -> String { + format!("cases = [\"cases/{reference}\"]\nrequired = true") +} + +/// The measure of `statements` over the fixture tree, with `obligations` as the functions file. +pub(crate) fn measure_obligations( + statements: Vec, + (obligations, retired): (&str, &str), +) -> Result> { + let directory = tempfile::tempdir().expect("directory"); + let root = tree(directory.path()); + let translation = directory.path().join("translation"); + write(&translation, "form-links.toml", LINKS); + write(&translation, "obligations/functions.toml", obligations); + write(&translation, "retired-obligations.toml", retired); + let coverage = load_coverage(&root).expect("coverage loads"); + let files = load_results_files(&translation, &coverage)?; + measure_results( + &coverage, + &files, + &StatementsFile { + format: STATEMENTS_FORMAT.to_owned(), + statements, + }, + ) +} diff --git a/crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs b/crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs new file mode 100644 index 000000000..a919cf8e1 --- /dev/null +++ b/crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs @@ -0,0 +1,357 @@ +use std::process::ExitCode; + +use crate::check::tests::helpers::write; +use crate::cli::_helpers::results_command::results; +use crate::cli::models::Common; +use crate::results::constants::STATEMENTS_FORMAT; +use crate::results::main::diff_results::diff_results; +use crate::results::models::{ObligationState, ResultState, ResultsBaseline, StatementOutcome}; +use crate::results::tests::helpers::{ + COUNT_IF_CASE, LINKS, citing, measure_obligations, obligation, statement, tree, +}; +use crate::results::tests::test_types::{ + ObligationDiffTestCase, ObligationLoadTestCase, ObligationStateTestCase, ObligationsCliTestCase, +}; + +/// The statement under COUNT_IF's form that matches Snowflake, cited by no obligation. +const MATCHING: &str = "translation/functions/count-if.toml#t009"; + +#[test] +fn given_malformed_obligations_when_loading_then_each_is_a_load_error() { + let cited = citing(COUNT_IF_CASE); + let test_cases = [ + ObligationLoadTestCase { + description: "a required obligation with no cases and no held reason", + obligations: obligation(1, "cases = []\nrequired = true"), + retired: "", + expected_problem: "needs a non-empty held reason", + }, + ObligationLoadTestCase { + description: "a held obligation whose reason is blank", + obligations: obligation(1, "cases = []\nrequired = true\nheld = \" \""), + retired: "", + expected_problem: "needs a non-empty held reason", + }, + ObligationLoadTestCase { + description: "a held obligation that also cites a case", + obligations: obligation(1, &format!("{cited}\nheld = \"parse gap\"")), + retired: "", + expected_problem: "with cases has neither held nor reason", + }, + ObligationLoadTestCase { + description: "held on an obligation that is not required", + obligations: obligation( + 1, + "cases = []\nrequired = false\nheld = \"x\"\nreason = \"y\"", + ), + retired: "", + expected_problem: "held is for required obligations", + }, + ObligationLoadTestCase { + description: "a reason on a required obligation without cases", + obligations: obligation(1, "cases = []\nrequired = true\nreason = \"x\""), + retired: "", + expected_problem: "a required obligation has no reason", + }, + ObligationLoadTestCase { + description: "an obligation that is not required, without a reason", + obligations: obligation(1, "cases = []\nrequired = false"), + retired: "", + expected_problem: "needs a non-empty reason", + }, + ObligationLoadTestCase { + description: "an obligation that is not required but cites a case", + obligations: obligation( + 1, + &format!("cases = [\"cases/{COUNT_IF_CASE}\"]\nrequired = false\nreason = \"x\""), + ), + retired: "", + expected_problem: "cites no cases", + }, + ObligationLoadTestCase { + description: "an unknown key", + obligations: obligation(1, &format!("{cited}\nweight = 2")), + retired: "", + expected_problem: "unknown field `weight`", + }, + ObligationLoadTestCase { + description: "a form the catalogue does not hold", + obligations: obligation(1, &cited).replace( + "form = \"sf.functions.count-if\"", + "form = \"sf.functions.count-if-not\"", + ), + retired: "", + expected_problem: "not a catalogued form still in its source", + }, + ObligationLoadTestCase { + description: "an id declared twice", + obligations: obligation(1, &cited) + &obligation(1, &cited), + retired: "", + expected_problem: "declared twice", + }, + ObligationLoadTestCase { + description: "an id that is not the form's", + obligations: obligation(1, &cited).replace("count-if.t001", "iff.t001"), + retired: "", + expected_problem: "the id is not sf.functions.count-if.t", + }, + ObligationLoadTestCase { + description: "a boundary without a subkind", + obligations: obligation(1, &cited).replace("type_combination", "boundary"), + retired: "", + expected_problem: "needs a subkind", + }, + ObligationLoadTestCase { + description: "a case under another family", + obligations: obligation( + 1, + "cases = [\"cases/translation/query/x.toml#t001\"]\nrequired = true", + ), + retired: "", + expected_problem: "is not cases/translation/functions/.toml#", + }, + ObligationLoadTestCase { + description: "a retired id reused in obligations/", + obligations: obligation(1, &cited), + retired: "[[retired]]\nid = \"sf.functions.count-if.t001\"\nform = \"sf.functions.count-if\"\nreason = \"r\"\n", + expected_problem: "the id is reused in obligations/", + }, + ObligationLoadTestCase { + description: "a retired id replaced by an obligation that does not exist", + obligations: obligation(1, &cited), + retired: "[[retired]]\nid = \"sf.functions.count-if.t002\"\nform = \"sf.functions.count-if\"\nreason = \"r\"\nreplaced_by = [\"sf.functions.count-if.t404\"]\n", + expected_problem: "is not a live obligation", + }, + ObligationLoadTestCase { + description: "a retired id without a reason", + obligations: obligation(1, &cited), + retired: "[[retired]]\nid = \"sf.functions.count-if.t002\"\nform = \"sf.functions.count-if\"\nreason = \" \"\n", + expected_problem: "needs its form and a reason", + }, + ObligationLoadTestCase { + description: "a cited case no statement records", + obligations: obligation(1, &citing("translation/functions/count-if.toml#t404")), + retired: "", + expected_problem: "no recorded statement is the case", + }, + ]; + for test_case in test_cases { + let problems = measure_obligations( + vec![statement( + COUNT_IF_CASE, + StatementOutcome::Matching, + &["fn:COUNT_IF"], + )], + (&test_case.obligations, test_case.retired), + ) + .err() + .unwrap_or_default(); + assert!( + problems + .iter() + .any(|problem| problem.contains(test_case.expected_problem)), + "{}: {problems:?}", + test_case.description + ); + } +} + +#[test] +fn given_obligations_when_measuring_then_a_form_matches_only_when_every_required_one_is_met() { + let met = obligation(1, &citing(COUNT_IF_CASE)); + let test_cases = [ + ObligationStateTestCase { + description: "the cited case matches", + cited_outcome: StatementOutcome::Matching, + obligations: met.clone(), + expected_form: ResultState::Matching, + expected_states: vec![ObligationState::Met], + }, + ObligationStateTestCase { + description: "the cited case only has its shape recorded, beside a matching statement", + cited_outcome: StatementOutcome::ShapeOnly, + obligations: met.clone(), + expected_form: ResultState::UnmetObligations, + expected_states: vec![ObligationState::Unmet], + }, + ObligationStateTestCase { + description: "the cited case has no Snowflake result", + cited_outcome: StatementOutcome::UnrecordedTranslates, + obligations: met.clone(), + expected_form: ResultState::UnmetObligations, + expected_states: vec![ObligationState::Unmet], + }, + ObligationStateTestCase { + description: "one of two cited cases only has its shape recorded", + cited_outcome: StatementOutcome::ShapeOnly, + obligations: obligation( + 1, + &format!( + "cases = [\"cases/{MATCHING}\", \"cases/{COUNT_IF_CASE}\"]\nrequired = true" + ), + ), + expected_form: ResultState::UnmetObligations, + expected_states: vec![ObligationState::Unmet], + }, + ObligationStateTestCase { + description: "a held obligation is never met, though every statement matches", + cited_outcome: StatementOutcome::Matching, + obligations: met.clone() + + &obligation(2, "cases = []\nrequired = true\nheld = \"waits on #118\""), + expected_form: ResultState::UnmetObligations, + expected_states: vec![ObligationState::Met, ObligationState::Held], + }, + ObligationStateTestCase { + description: "an unmeasured obligation is never met and does not block the form", + cited_outcome: StatementOutcome::Matching, + obligations: met + + &obligation( + 3, + "cases = []\nrequired = false\nreason = \"row order unspecified\"", + ), + expected_form: ResultState::Matching, + expected_states: vec![ObligationState::Met, ObligationState::Unmeasured], + }, + ]; + for test_case in test_cases { + let report = measure_obligations( + vec![ + statement(MATCHING, StatementOutcome::Matching, &["fn:COUNT_IF"]), + statement(COUNT_IF_CASE, test_case.cited_outcome, &["fn:COUNT_IF"]), + ], + (&test_case.obligations, ""), + ) + .expect("measures"); + let form = report + .form_results + .iter() + .find(|form| form.id == "sf.functions.count-if") + .expect("form"); + let states: Vec = report.obligation_states.values().copied().collect(); + assert_eq!( + (form.state, states, report.obligations.met), + ( + test_case.expected_form, + test_case.expected_states.clone(), + test_case + .expected_states + .iter() + .filter(|state| **state == ObligationState::Met) + .count() + ), + "{}", + test_case.description + ); + } +} + +#[test] +fn given_obligations_when_running_the_results_command_then_the_json_reports_each_bucket() { + let test_cases = [ + ObligationsCliTestCase { + description: "a held and an unmeasured obligation land in their own buckets", + obligations: obligation(1, &citing(COUNT_IF_CASE)) + + &obligation(2, "cases = []\nrequired = true\nheld = \"parse gap\"") + + &obligation(3, "cases = []\nrequired = false\nreason = \"unspecified\""), + expected_exit: ExitCode::SUCCESS, + expected_buckets: Some((1, 1, 1, 3)), + }, + ObligationsCliTestCase { + description: "a required obligation without cases or held fails the command", + obligations: obligation(1, "cases = []\nrequired = true"), + expected_exit: ExitCode::FAILURE, + expected_buckets: None, + }, + ]; + for test_case in test_cases { + let directory = tempfile::tempdir().expect("directory"); + let root = tree(directory.path()); + let translation = directory.path().join("translation"); + write(&translation, "form-links.toml", LINKS); + write( + &translation, + "obligations/functions.toml", + &test_case.obligations, + ); + let statements = serde_json::json!({ + "format": STATEMENTS_FORMAT, + "statements": [ + statement(MATCHING, StatementOutcome::Matching, &["fn:COUNT_IF"]), + statement(COUNT_IF_CASE, StatementOutcome::Matching, &["fn:COUNT_IF"]), + ], + }); + write(directory.path(), "statements.json", &statements.to_string()); + let report_path = directory.path().join("report.json"); + let exit = results( + &directory.path().join("statements.json"), + (true, Some(&report_path), None), + &Common { root, json: true }, + ) + .unwrap_or_else(|exit| exit); + let buckets = std::fs::read_to_string(&report_path).ok().map(|text| { + let report: serde_json::Value = serde_json::from_str(&text).expect("report JSON"); + let baseline: ResultsBaseline = serde_json::from_str( + &std::fs::read_to_string(translation.join("results-baseline.json")) + .expect("baseline"), + ) + .expect("baseline JSON"); + let count = |key: &str| report["obligations"][key].as_u64().unwrap_or(u64::MAX); + ( + count("met"), + count("held"), + count("unmeasured"), + u64::try_from(baseline.obligations.len()).unwrap_or(u64::MAX), + ) + }); + assert_eq!( + (exit, buckets), + (test_case.expected_exit, test_case.expected_buckets), + "{}", + test_case.description + ); + } +} + +#[test] +fn given_a_met_obligation_when_it_stops_being_met_then_the_diff_regresses() { + let baseline = |state: ObligationState| ResultsBaseline { + obligations: [("sf.functions.count-if.t001".to_owned(), state)].into(), + ..ResultsBaseline::default() + }; + let test_cases = [ + ObligationDiffTestCase { + description: "met to unmet regresses", + before: ObligationState::Met, + after: ObligationState::Unmet, + expected_regressions: 1, + }, + ObligationDiffTestCase { + description: "met to held regresses", + before: ObligationState::Met, + after: ObligationState::Held, + expected_regressions: 1, + }, + ObligationDiffTestCase { + description: "unmet to met is an improvement", + before: ObligationState::Unmet, + after: ObligationState::Met, + expected_regressions: 0, + }, + ObligationDiffTestCase { + description: "held to unmet is a change, not a regression", + before: ObligationState::Held, + after: ObligationState::Unmet, + expected_regressions: 0, + }, + ]; + for test_case in test_cases { + assert_eq!( + diff_results(&baseline(test_case.before), &baseline(test_case.after)) + .regressions + .len(), + test_case.expected_regressions, + "{}", + test_case.description + ); + } +} diff --git a/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs b/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs index 428839514..dc58f410f 100644 --- a/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs +++ b/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs @@ -1,4 +1,6 @@ -use crate::results::models::{ResultState, StatementOutcome}; +use std::process::ExitCode; + +use crate::results::models::{ObligationState, ResultState, StatementOutcome}; /// The outcomes of the statements calling COUNT_IF, and the state its form must take. pub(crate) struct FormStateTestCase { @@ -59,3 +61,39 @@ pub(crate) struct CallShapeTestCase { pub(crate) constructs: &'static [&'static str], pub(crate) expected_forms: &'static [&'static str], } + +/// An obligation file the loader must refuse, and a fragment of the problem it reports. +pub(crate) struct ObligationLoadTestCase { + pub(crate) description: &'static str, + pub(crate) obligations: String, + /// The retired-obligations file, or nothing. + pub(crate) retired: &'static str, + pub(crate) expected_problem: &'static str, +} + +/// COUNT_IF's obligations, its cited case's outcome beside a matching statement, and the states. +pub(crate) struct ObligationStateTestCase { + pub(crate) description: &'static str, + pub(crate) cited_outcome: StatementOutcome, + pub(crate) obligations: String, + pub(crate) expected_form: ResultState, + /// Each obligation's state, in id order. + pub(crate) expected_states: Vec, +} + +/// The results command over an obligation file, and its exit and JSON buckets. +pub(crate) struct ObligationsCliTestCase { + pub(crate) description: &'static str, + pub(crate) obligations: String, + pub(crate) expected_exit: ExitCode, + /// Met, held and unmeasured obligations in the report, and obligations in the baseline. + pub(crate) expected_buckets: Option<(u64, u64, u64, u64)>, +} + +/// One obligation's state before and after, and how many regressions the diff reports. +pub(crate) struct ObligationDiffTestCase { + pub(crate) description: &'static str, + pub(crate) before: ObligationState, + pub(crate) after: ObligationState, + pub(crate) expected_regressions: usize, +} From 8448deaf3f4b52934dbc0848f6433a18b559080b Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Fri, 6 Nov 2026 15:16:17 +0000 Subject: [PATCH 2/3] Close the loader's fail-open paths (D272 review round 1) A cited case file whose construct is another form, or that is missing, is a load error, and so is a missing obligations directory. A form declaring no required obligation is no_obligations, never matching. The baseline records retired ids, and dropping any other obligation from the head regresses. --- coverage/translation/README.md | 18 +-- .../src/cli/_helpers/results_command.rs | 15 +-- .../src/results/_helpers/diff.rs | 32 +++++- .../src/results/_helpers/files.rs | 7 +- .../src/results/_helpers/forms.rs | 16 ++- .../src/results/_helpers/obligations.rs | 80 ++++++++++--- .../src/results/_helpers/report.rs | 10 +- .../src/results/main/diff_results.rs | 10 +- .../src/results/main/load_results_files.rs | 6 +- .../src/results/main/results_baseline.rs | 1 + .../src/results/models.rs | 20 +++- .../src/results/tests/helpers.rs | 20 +++- .../src/results/tests/test_measure_results.rs | 12 +- .../src/results/tests/test_obligations.rs | 105 ++++++++++++++---- .../src/results/tests/test_types.rs | 8 +- 15 files changed, 269 insertions(+), 91 deletions(-) diff --git a/coverage/translation/README.md b/coverage/translation/README.md index 86db93c06..70a26e025 100644 --- a/coverage/translation/README.md +++ b/coverage/translation/README.md @@ -52,15 +52,16 @@ forms when it names none. Any other statement counts for every form it links to. | `not_translatable` | Listed in a signed-off group. Outside the denominator. | | `differs` | Any linked statement differs. | | `refused` | Any linked statement is refused for it, raised a guard for it, or cannot be judged. | +| `no_obligations` | Otherwise, a linked statement returns Snowflake's rows, but the form declares no required obligation, so nothing shows what it must do. | | `unmet_obligations` | Otherwise, a linked statement returns Snowflake's rows, but a required obligation is unmet or held. | -| `matching` | Otherwise, at least one linked statement returns Snowflake's rows, and every required obligation is met. | +| `matching` | Otherwise, at least one linked statement returns Snowflake's rows, and it declares required obligations, every one met. | | `syntax_only` | Otherwise, linked statements exist but none returns compared rows: only types or matching errors. | | `unmeasured` | No recorded statement links to it. | An obligation is `met` when it cites at least one case and every cited case is `matching` or `matching_error`; otherwise it is `unmet`, or `held` or `unmeasured` by its shape. The report lists each obligation's state, the `held` and `unmeasured` obligations with their reasons, and the -`uncited_cases`: recorded translation cases no obligation cites, which can make no form match. +`uncited_cases`: recorded translation cases no obligation cites, which meet no obligation. ## Figures @@ -80,16 +81,17 @@ syntax-coverage results target/translation-statements.json --report target/trans syntax-coverage results target/translation-statements.json --write-baseline ``` -The check fails on an obligation file it cannot read whole: an unknown key, a form the catalogue -does not hold or that is absent from its source, an id that is not the form's or is declared or -retired twice, a case outside its family's folder, cited twice or not recorded, a boundary without -a known subkind, a required obligation with neither cases nor a `held` reason, a blank reason, and +The check fails on obligations it cannot read whole: a missing `obligations/` directory, an +unknown key, a form the catalogue does not hold or that is absent from its source, an id that is +not the form's or is declared or retired twice, a case outside its family's folder, cited twice, +not recorded, or in a case file whose `construct` is another form, a boundary without a known +subkind, a required obligation with neither cases nor a `held` reason, a blank reason, and a retired id that is reused or replaced by an id that is not a live obligation. It also fails on a construct that neither links nor names no form, a link to a form the catalogue does not hold, a signed-off not-translatable form with a matching statement, and any difference from `results-baseline.json`. Against the target branch's baseline it prints the diff and fails if a -statement or form drops out of matching, a met obligation stops being met, or anything becomes -`differs`. +statement or form drops out of matching, a met obligation stops being met, an obligation is +dropped without being listed in `retired-obligations.toml`, or anything becomes `differs`. The report's worklist lists differences first, then refusals by how many forms each keeps from matching, then forms that need a recorded result. diff --git a/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs b/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs index 3b3adda35..0e62b06f8 100644 --- a/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs +++ b/crates/sqlquack-syntax-coverage/src/cli/_helpers/results_command.rs @@ -45,13 +45,15 @@ fn percent(part: usize, whole: usize) -> String { fn tally_line(name: &str, tally: &FormTally) -> String { format!( "{name}: {} of {} translatable forms match ({}); {} syntax only, {} refused, {} with unmet \ - obligations, {} differ, {} unmeasured; {} of {} catalogued forms not translatable", + obligations, {} with none declared, {} differ, {} unmeasured; {} of {} catalogued forms \ + not translatable", tally.matching, tally.translatable, percent(tally.matching, tally.translatable), tally.syntax_only, tally.refused, tally.unmet_obligations, + tally.no_obligations, tally.differs, tally.unmeasured, tally.not_translatable, @@ -198,12 +200,11 @@ pub(crate) fn results( statements.display() )); let coverage = load_coverage(&common.root).map_err(|problems| fail(&problems))?; - let directory: PathBuf = common - .root - .parent() - .unwrap_or(Path::new(".")) - .join(TRANSLATION_DIR); - let files = load_results_files(&directory, &coverage).map_err(|problems| fail(&problems))?; + let coverage_root: &Path = common.root.parent().unwrap_or(Path::new(".")); + let directory: PathBuf = coverage_root.join(TRANSLATION_DIR); + let repository: &Path = coverage_root.parent().unwrap_or(Path::new(".")); + let files = load_results_files((&directory, repository), &coverage) + .map_err(|problems| fail(&problems))?; let recorded: StatementsFile = read_json(statements).map_err(|problem| fail(&[problem]))?; let report = measure_results(&coverage, &files, &recorded).map_err(|problems| fail(&problems))?; diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs index 1c96daf81..e0b2b095f 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/diff.rs @@ -25,12 +25,32 @@ pub(crate) fn form_regresses(base: Option, head: Option, - head: Option, -) -> bool { - base == Some(ObligationState::Met) && head != Some(ObligationState::Met) +/// Obligation changes: a met one stops being met, or any is dropped that `retired` does not list. +pub(crate) fn compare_obligations( + (base, head): ( + &BTreeMap, + &BTreeMap, + ), + retired: &BTreeSet, +) -> ResultsDiff { + let mut diff = ResultsDiff::default(); + let keys: BTreeSet<&String> = base.keys().chain(head.keys()).collect(); + for key in keys { + let (before, after) = (base.get(key).copied(), head.get(key).copied()); + if before == after { + continue; + } + let line = format!("obligation {key}: {before:?} -> {after:?}"); + let regresses = match after { + None => !retired.contains(key.as_str()), + Some(after) => before == Some(ObligationState::Met) && after != ObligationState::Met, + }; + match regresses { + true => diff.regressions.push(line), + false => diff.changes.push(line), + } + } + diff } /// Each changed key of one kind, as a regression or another change. diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs index 8a97a1a6f..f932be24b 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/files.rs @@ -147,9 +147,9 @@ fn check_review(review: &ResultsReviewFile) -> Vec { problems } -/// The files under `directory`, or every problem with them; ids must be catalogued forms. +/// The files under `directory`, cases under `repository`, or every problem; ids must be catalogued. pub(crate) fn load_files( - directory: &Path, + (directory, repository): (&Path, &Path), families: &BTreeMap<&str, &str>, ) -> Result> { let catalogued: &BTreeSet<&str> = &families.keys().copied().collect(); @@ -184,13 +184,14 @@ pub(crate) fn load_files( if !problems.is_empty() { return Err(problems); } - let obligations = load_obligations(directory, families)?; + let (obligations, retired) = load_obligations((directory, repository), families)?; Ok(ResultsFiles { links, not_translatable, review, links_sha256: content_sha256(links_text.as_bytes()), obligations, + retired, }) } diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs index 98ef807f3..4a966b3e3 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/forms.rs @@ -10,7 +10,7 @@ use crate::results::models::{ pub(crate) fn form_state( listed: bool, outcomes: &[StatementOutcome], - obligations_met: bool, + obligations_met: Option, ) -> ResultState { if listed { return ResultState::NotTranslatable; @@ -28,8 +28,9 @@ pub(crate) fn form_state( outcomes.contains(&StatementOutcome::Matching), obligations_met, ) { - (true, true) => ResultState::Matching, - (true, false) => ResultState::UnmetObligations, + (true, Some(true)) => ResultState::Matching, + (true, Some(false)) => ResultState::UnmetObligations, + (true, None) => ResultState::NoObligations, (false, _) => ResultState::SyntaxOnly, } } @@ -39,7 +40,7 @@ pub(crate) fn form_result( (id, family): (&str, &str), listed: bool, linked: &[&RecordedStatement], - unmet_obligations: Vec, + (unmet_obligations, declared): (Vec, bool), ) -> FormResult { let outcomes: Vec = linked.iter().map(|statement| statement.outcome).collect(); @@ -51,7 +52,11 @@ pub(crate) fn form_result( FormResult { id: id.to_owned(), family: family.to_owned(), - state: form_state(listed, &outcomes, unmet_obligations.is_empty()), + state: form_state( + listed, + &outcomes, + declared.then_some(unmet_obligations.is_empty()), + ), statements: linked.len(), matching_statements: outcomes.iter().filter(|outcome| outcome.matches()).count(), unmet_obligations, @@ -70,6 +75,7 @@ pub(crate) fn tally<'a>(forms: impl Iterator) -> FormTall ResultState::SyntaxOnly => &mut tally.syntax_only, ResultState::Refused => &mut tally.refused, ResultState::UnmetObligations => &mut tally.unmet_obligations, + ResultState::NoObligations => &mut tally.no_obligations, ResultState::Differs => &mut tally.differs, ResultState::Unmeasured => &mut tally.unmeasured, }; diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs index f70166532..8b17c68f8 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/obligations.rs @@ -8,21 +8,18 @@ use crate::results::constants::{ RETIRED_OBLIGATIONS_FILE, TRANSLATION_CASES, }; use crate::results::models::{ - ObligationKind, ObligationState, ObligationsFile, RecordedStatement, RetiredFile, - TranslationObligation, + CaseFileHeader, ObligationKind, ObligationState, ObligationsFile, RecordedStatement, + RetiredFile, TranslationObligation, }; -/// Every obligation under `directory/obligations`, or every problem; none when the directory is absent. +/// Every obligation under `directory/obligations` and every retired id, or every problem. pub(crate) fn load_obligations( - directory: &Path, + (directory, repository): (&Path, &Path), catalogued: &BTreeMap<&str, &str>, -) -> Result, Vec> { +) -> Result<(Vec, BTreeSet), Vec> { let folder = directory.join(OBLIGATIONS_DIR); - let entries = match std::fs::read_dir(&folder) { - Ok(entries) => entries, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()), - Err(error) => return Err(vec![format!("{}: {error}", folder.display())]), - }; + let entries = std::fs::read_dir(&folder) + .map_err(|error| vec![format!("{}: {error}", folder.display())])?; let mut paths: Vec = Vec::new(); for entry in entries { paths.push( @@ -75,24 +72,70 @@ pub(crate) fn load_obligations( problems.push(format!("obligation {}: declared twice", obligation.id)); } } - problems.extend(retired_problems(directory, &ids)); + let (retired, retired_problems) = load_retired(directory, &ids); + problems.extend(retired_problems); + problems.extend(construct_problems(repository, &obligations)); match problems.is_empty() { - true => Ok(obligations), + true => Ok((obligations, retired)), false => Err(problems), } } -/// Every problem with the retired ids: a reused id, a blank reason, or an unresolved replacement. -fn retired_problems(directory: &Path, live: &BTreeSet<&str>) -> Vec { +/// Every cited case whose file is missing or whose `construct` is not the obligation's form. +fn construct_problems(repository: &Path, obligations: &[TranslationObligation]) -> Vec { + let mut constructs: BTreeMap<&str, Result> = BTreeMap::new(); + let mut problems: Vec = Vec::new(); + for obligation in obligations { + for case in &obligation.cases { + let file = case.split_once('#').map_or(case.as_str(), |(file, _)| file); + let construct = constructs + .entry(file) + .or_insert_with(|| case_construct(&repository.join(file))); + match construct { + Ok(construct) if *construct == obligation.form => {} + Ok(construct) => problems.push(format!( + "obligation {}: cites {case}, a case of {construct}", + obligation.id + )), + Err(problem) => problems.push(format!("obligation {}: {problem}", obligation.id)), + } + } + } + problems +} + +/// The `construct` a case file names, or why it cannot be read. +fn case_construct(path: &Path) -> Result { + let text = + std::fs::read_to_string(path).map_err(|error| format!("{}: {error}", path.display()))?; + toml::from_str::(&text) + .map(|header| header.construct) + .map_err(|error| format!("{}: {error}", path.display())) +} + +/// The retired ids, and every problem with them: reuse, a blank reason, an unresolved replacement. +fn load_retired(directory: &Path, live: &BTreeSet<&str>) -> (BTreeSet, Vec) { let path = directory.join(RETIRED_OBLIGATIONS_FILE); let text = match std::fs::read_to_string(&path) { Ok(text) => text, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Vec::new(), - Err(error) => return vec![format!("{}: {error}", path.display())], + Err(error) if error.kind() == std::io::ErrorKind::NotFound => { + return (BTreeSet::new(), Vec::new()); + } + Err(error) => { + return ( + BTreeSet::new(), + vec![format!("{}: {error}", path.display())], + ); + } }; let file: RetiredFile = match toml::from_str(&text) { Ok(file) => file, - Err(error) => return vec![format!("{}: {error}", path.display())], + Err(error) => { + return ( + BTreeSet::new(), + vec![format!("{}: {error}", path.display())], + ); + } }; let mut problems: Vec = Vec::new(); let mut seen: BTreeSet<&str> = BTreeSet::new(); @@ -119,7 +162,8 @@ fn retired_problems(directory: &Path, live: &BTreeSet<&str>) -> Vec { } } } - problems + let ids: BTreeSet = file.retired.into_iter().map(|retired| retired.id).collect(); + (ids, problems) } /// Whether `text` holds something other than whitespace. diff --git a/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs b/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs index dd876ffaf..8b907f3dc 100644 --- a/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs +++ b/crates/sqlquack-syntax-coverage/src/results/_helpers/report.rs @@ -85,11 +85,13 @@ pub(crate) fn form_results( states: &BTreeMap, ) -> Result, Vec> { let mut unmet: BTreeMap<&str, Vec> = BTreeMap::new(); + let mut declared: BTreeSet<&str> = BTreeSet::new(); for obligation in files .obligations .iter() .filter(|obligation| obligation.required) { + declared.insert(obligation.form.as_str()); if states.get(&obligation.id) != Some(&ObligationState::Met) { unmet .entry(obligation.form.as_str()) @@ -120,7 +122,12 @@ pub(crate) fn form_results( )); } let unmet_here = unmet.get(id).cloned().unwrap_or_default(); - results.push(form_result((id, family), is_listed, statements, unmet_here)); + results.push(form_result( + (id, family), + is_listed, + statements, + (unmet_here, declared.contains(id)), + )); } match problems.is_empty() { true => Ok(results), @@ -220,6 +227,7 @@ pub(crate) fn assemble( obligation.reason.as_ref().filter(|_| !obligation.required) }), uncited_cases: uncited_cases(&files.obligations, statements), + retired_obligations: files.retired.clone(), obligation_states, } } diff --git a/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs b/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs index 5e2c5617f..bde7dc1cb 100644 --- a/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs +++ b/crates/sqlquack-syntax-coverage/src/results/main/diff_results.rs @@ -1,7 +1,7 @@ -//! `diff_results`: a baseline against a later one; drops out of matching and into differs regress. +//! `diff_results`: a baseline against a later one; drops out of matching or into differs regress. use crate::results::_helpers::diff::{ - compare, form_regresses, obligation_regresses, statement_regresses, + compare, compare_obligations, form_regresses, statement_regresses, }; use crate::results::models::{ResultsBaseline, ResultsDiff}; @@ -13,11 +13,7 @@ pub fn diff_results(base: &ResultsBaseline, head: &ResultsBaseline) -> ResultsDi statement_regresses, ); let forms = compare("form", (&base.forms, &head.forms), form_regresses); - let obligations = compare( - "obligation", - (&base.obligations, &head.obligations), - obligation_regresses, - ); + let obligations = compare_obligations((&base.obligations, &head.obligations), &head.retired); ResultsDiff { regressions: [ statements.regressions, diff --git a/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs b/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs index d4bd4d60b..7fa90b335 100644 --- a/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs +++ b/crates/sqlquack-syntax-coverage/src/results/main/load_results_files.rs @@ -7,10 +7,10 @@ use crate::results::_helpers::files::load_files; use crate::results::models::ResultsFiles; use crate::translation::main::catalogued_forms::catalogued_forms; -/// The files under the translation `directory`, or every problem with them. +/// The files under the translation `directory`, with the cited cases under `repository`, or every problem. pub fn load_results_files( - directory: &Path, + (directory, repository): (&Path, &Path), coverage: &SyntaxCoverage, ) -> Result> { - load_files(directory, &catalogued_forms(coverage, None)) + load_files((directory, repository), &catalogued_forms(coverage, None)) } diff --git a/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs b/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs index d0a681b31..5e7bdbefa 100644 --- a/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs +++ b/crates/sqlquack-syntax-coverage/src/results/main/results_baseline.rs @@ -14,5 +14,6 @@ pub fn results_baseline(report: &ResultsReport) -> ResultsBaseline { .map(|form| (form.id.clone(), form.state)) .collect(), obligations: report.obligation_states.clone(), + retired: report.retired_obligations.clone(), } } diff --git a/crates/sqlquack-syntax-coverage/src/results/models.rs b/crates/sqlquack-syntax-coverage/src/results/models.rs index 537c0c12c..a25dcc8ee 100644 --- a/crates/sqlquack-syntax-coverage/src/results/models.rs +++ b/crates/sqlquack-syntax-coverage/src/results/models.rs @@ -1,6 +1,6 @@ //! Recorded statements, their links to catalogue forms, and the result-matching measure (D139). -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use serde::{Deserialize, Serialize}; @@ -165,6 +165,12 @@ pub struct TranslationObligation { pub reason: Option, } +/// The header of a case file a translation obligation cites: the form its cases exercise. +#[derive(Clone, Debug, Deserialize)] +pub struct CaseFileHeader { + pub construct: String, +} + /// `retired-obligations.toml`: obligation ids withdrawn, never to be reused. #[derive(Clone, Debug, Default, Deserialize)] #[serde(deny_unknown_fields)] @@ -228,6 +234,8 @@ pub struct ResultsFiles { pub links_sha256: String, /// Every family's obligations, in file then declaration order. pub obligations: Vec, + /// The ids `retired-obligations.toml` withdraws. + pub retired: BTreeSet, } /// A form's state over the recorded statements linked to it. @@ -244,6 +252,8 @@ pub enum ResultState { Refused, /// Its statements would match, but a required obligation is unmet or held. UnmetObligations, + /// Its statements would match, but it declares no required obligation, so nothing shows it. + NoObligations, /// At least one linked statement's replay differs from Snowflake's result: a bug. Differs, /// No recorded statement links to it. @@ -277,6 +287,7 @@ pub struct FormTally { pub syntax_only: usize, pub refused: usize, pub unmet_obligations: usize, + pub no_obligations: usize, pub differs: usize, pub unmeasured: usize, } @@ -338,8 +349,10 @@ pub struct ResultsReport { /// Each held obligation's reason, and each unmeasured one's. pub held: BTreeMap, pub unmeasured: BTreeMap, - /// Recorded translation cases no obligation cites; they can make no form match. + /// Recorded translation cases no obligation cites; they meet no obligation. pub uncited_cases: Vec, + /// The obligation ids withdrawn in `retired-obligations.toml`. + pub retired_obligations: BTreeSet, } /// `results-baseline.json`: every statement's outcome and every form's state. @@ -352,6 +365,9 @@ pub struct ResultsBaseline { /// Absent from baselines written before obligations were read. #[serde(default)] pub obligations: BTreeMap, + /// The withdrawn obligation ids; dropping any other obligation regresses. + #[serde(default)] + pub retired: BTreeSet, } /// How a report differs from the baseline. diff --git a/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs b/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs index 3ee1b571a..3cf5caa4c 100644 --- a/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs +++ b/crates/sqlquack-syntax-coverage/src/results/tests/helpers.rs @@ -134,8 +134,9 @@ pub(crate) fn measure( write(&translation, "form-links.toml", links); write(&translation, "not-translatable.toml", not_translatable); write(&translation, "reviews/auditor-results.toml", review); + write(&translation, "obligations/functions.toml", ""); let coverage = load_coverage(&root).expect("coverage loads"); - let files = load_results_files(&translation, &coverage)?; + let files = load_results_files((&translation, directory.path()), &coverage)?; measure_results( &coverage, &files, @@ -187,6 +188,20 @@ pub(crate) fn obligation(number: u32, fields: &str) -> String { ) } +/// The COUNT_IF case file under `repository`, and an IFF one the obligations may wrongly cite. +pub(crate) fn count_if_cases(repository: &Path) { + write( + repository, + "cases/translation/functions/count-if.toml", + "construct = \"sf.functions.count-if\"\n", + ); + write( + repository, + "cases/translation/functions/iff.toml", + "construct = \"sf.functions.iff\"\n", + ); +} + /// The fields of a required obligation citing `reference` under `cases/`. pub(crate) fn citing(reference: &str) -> String { format!("cases = [\"cases/{reference}\"]\nrequired = true") @@ -203,8 +218,9 @@ pub(crate) fn measure_obligations( write(&translation, "form-links.toml", LINKS); write(&translation, "obligations/functions.toml", obligations); write(&translation, "retired-obligations.toml", retired); + count_if_cases(directory.path()); let coverage = load_coverage(&root).expect("coverage loads"); - let files = load_results_files(&translation, &coverage)?; + let files = load_results_files((&translation, directory.path()), &coverage)?; measure_results( &coverage, &files, diff --git a/crates/sqlquack-syntax-coverage/src/results/tests/test_measure_results.rs b/crates/sqlquack-syntax-coverage/src/results/tests/test_measure_results.rs index 141ae8aaa..332529bc9 100644 --- a/crates/sqlquack-syntax-coverage/src/results/tests/test_measure_results.rs +++ b/crates/sqlquack-syntax-coverage/src/results/tests/test_measure_results.rs @@ -15,11 +15,11 @@ const COUNT_IF_CONSTRUCTS: &[&str] = &["fn:COUNT_IF", "node:column", "node:selec fn given_linked_statements_when_measuring_then_the_form_takes_the_weakest_state() { let test_cases = [ FormStateTestCase { - description: "rows and a matching error both match", + description: "rows and a matching error both match, but no obligation is declared", outcomes: &[StatementOutcome::Matching, StatementOutcome::MatchingError], list: nothing, review: nothing, - expected_state: ResultState::Matching, + expected_state: ResultState::NoObligations, expected_translatable: 12, }, FormStateTestCase { @@ -46,11 +46,11 @@ fn given_linked_statements_when_measuring_then_the_form_takes_the_weakest_state( expected_translatable: 12, }, FormStateTestCase { - description: "types only beside a match: the match decides", + description: "types only beside a match: the match decides, then the obligations", outcomes: &[StatementOutcome::Matching, StatementOutcome::ShapeOnly], list: nothing, review: nothing, - expected_state: ResultState::Matching, + expected_state: ResultState::NoObligations, expected_translatable: 12, }, FormStateTestCase { @@ -334,9 +334,9 @@ fn given_a_two_construct_link_when_measuring_then_it_links_only_when_both_are_us fn given_a_refusal_naming_one_construct_when_measuring_then_only_its_forms_are_refused() { let test_cases = [ RefusedConstructTestCase { - description: "names COUNT_IF: IFF keeps its own evidence", + description: "names COUNT_IF: IFF keeps its own evidence, short only of obligations", refused: &["fn:COUNT_IF"], - expected_iff: ResultState::Matching, + expected_iff: ResultState::NoObligations, }, RefusedConstructTestCase { description: "the whole statement", diff --git a/crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs b/crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs index a919cf8e1..899a7a08e 100644 --- a/crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs +++ b/crates/sqlquack-syntax-coverage/src/results/tests/test_obligations.rs @@ -7,7 +7,7 @@ use crate::results::constants::STATEMENTS_FORMAT; use crate::results::main::diff_results::diff_results; use crate::results::models::{ObligationState, ResultState, ResultsBaseline, StatementOutcome}; use crate::results::tests::helpers::{ - COUNT_IF_CASE, LINKS, citing, measure_obligations, obligation, statement, tree, + COUNT_IF_CASE, LINKS, citing, count_if_cases, measure_obligations, obligation, statement, tree, }; use crate::results::tests::test_types::{ ObligationDiffTestCase, ObligationLoadTestCase, ObligationStateTestCase, ObligationsCliTestCase, @@ -128,6 +128,18 @@ fn given_malformed_obligations_when_loading_then_each_is_a_load_error() { retired: "[[retired]]\nid = \"sf.functions.count-if.t002\"\nform = \"sf.functions.count-if\"\nreason = \" \"\n", expected_problem: "needs its form and a reason", }, + ObligationLoadTestCase { + description: "a cited case of another form", + obligations: obligation(1, &citing("translation/functions/iff.toml#t001")), + retired: "", + expected_problem: "a case of sf.functions.iff", + }, + ObligationLoadTestCase { + description: "a cited case file that does not exist", + obligations: obligation(1, &citing("translation/functions/count-if-gone.toml#t001")), + retired: "", + expected_problem: "count-if-gone.toml", + }, ObligationLoadTestCase { description: "a cited case no statement records", obligations: obligation(1, &citing("translation/functions/count-if.toml#t404")), @@ -193,6 +205,23 @@ fn given_obligations_when_measuring_then_a_form_matches_only_when_every_required expected_form: ResultState::UnmetObligations, expected_states: vec![ObligationState::Unmet], }, + ObligationStateTestCase { + description: "no obligation declared: matching rows alone do not match the form", + cited_outcome: StatementOutcome::Matching, + obligations: String::new(), + expected_form: ResultState::NoObligations, + expected_states: vec![], + }, + ObligationStateTestCase { + description: "only an unmeasured obligation: no required one, so the form cannot match", + cited_outcome: StatementOutcome::Matching, + obligations: obligation( + 3, + "cases = []\nrequired = false\nreason = \"row order unspecified\"", + ), + expected_form: ResultState::NoObligations, + expected_states: vec![ObligationState::Unmeasured], + }, ObligationStateTestCase { description: "a held obligation is never met, though every statement matches", cited_outcome: StatementOutcome::Matching, @@ -250,29 +279,37 @@ fn given_obligations_when_running_the_results_command_then_the_json_reports_each let test_cases = [ ObligationsCliTestCase { description: "a held and an unmeasured obligation land in their own buckets", - obligations: obligation(1, &citing(COUNT_IF_CASE)) - + &obligation(2, "cases = []\nrequired = true\nheld = \"parse gap\"") - + &obligation(3, "cases = []\nrequired = false\nreason = \"unspecified\""), + obligations: Some( + obligation(1, &citing(COUNT_IF_CASE)) + + &obligation(2, "cases = []\nrequired = true\nheld = \"parse gap\"") + + &obligation(3, "cases = []\nrequired = false\nreason = \"unspecified\""), + ), expected_exit: ExitCode::SUCCESS, expected_buckets: Some((1, 1, 1, 3)), }, + ObligationsCliTestCase { + description: "no obligations directory fails the command, not zero obligations", + obligations: None, + expected_exit: ExitCode::FAILURE, + expected_buckets: None, + }, ObligationsCliTestCase { description: "a required obligation without cases or held fails the command", - obligations: obligation(1, "cases = []\nrequired = true"), + obligations: Some(obligation(1, "cases = []\nrequired = true")), expected_exit: ExitCode::FAILURE, expected_buckets: None, }, ]; for test_case in test_cases { let directory = tempfile::tempdir().expect("directory"); - let root = tree(directory.path()); - let translation = directory.path().join("translation"); + let root = tree(&directory.path().join("coverage")); + let translation = directory.path().join("coverage/translation"); write(&translation, "form-links.toml", LINKS); - write( - &translation, - "obligations/functions.toml", - &test_case.obligations, - ); + test_case + .obligations + .iter() + .for_each(|obligations| write(&translation, "obligations/functions.toml", obligations)); + count_if_cases(directory.path()); let statements = serde_json::json!({ "format": STATEMENTS_FORMAT, "statements": [ @@ -314,41 +351,67 @@ fn given_obligations_when_running_the_results_command_then_the_json_reports_each #[test] fn given_a_met_obligation_when_it_stops_being_met_then_the_diff_regresses() { - let baseline = |state: ObligationState| ResultsBaseline { - obligations: [("sf.functions.count-if.t001".to_owned(), state)].into(), + let id = "sf.functions.count-if.t001"; + let baseline = |state: Option, retired: bool| ResultsBaseline { + obligations: state + .map(|state| (id.to_owned(), state)) + .into_iter() + .collect(), + retired: retired.then(|| id.to_owned()).into_iter().collect(), ..ResultsBaseline::default() }; let test_cases = [ ObligationDiffTestCase { description: "met to unmet regresses", before: ObligationState::Met, - after: ObligationState::Unmet, + after: Some(ObligationState::Unmet), + retired: false, expected_regressions: 1, }, ObligationDiffTestCase { description: "met to held regresses", before: ObligationState::Met, - after: ObligationState::Held, + after: Some(ObligationState::Held), + retired: false, expected_regressions: 1, }, ObligationDiffTestCase { description: "unmet to met is an improvement", before: ObligationState::Unmet, - after: ObligationState::Met, + after: Some(ObligationState::Met), + retired: false, expected_regressions: 0, }, ObligationDiffTestCase { description: "held to unmet is a change, not a regression", before: ObligationState::Held, - after: ObligationState::Unmet, + after: Some(ObligationState::Unmet), + retired: false, + expected_regressions: 0, + }, + ObligationDiffTestCase { + description: "an unmet obligation deleted without a tombstone regresses", + before: ObligationState::Unmet, + after: None, + retired: false, + expected_regressions: 1, + }, + ObligationDiffTestCase { + description: "a met obligation retired in retired-obligations.toml is a change", + before: ObligationState::Met, + after: None, + retired: true, expected_regressions: 0, }, ]; for test_case in test_cases { assert_eq!( - diff_results(&baseline(test_case.before), &baseline(test_case.after)) - .regressions - .len(), + diff_results( + &baseline(Some(test_case.before), false), + &baseline(test_case.after, test_case.retired), + ) + .regressions + .len(), test_case.expected_regressions, "{}", test_case.description diff --git a/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs b/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs index dc58f410f..6f7ebe8b9 100644 --- a/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs +++ b/crates/sqlquack-syntax-coverage/src/results/tests/test_types.rs @@ -84,7 +84,8 @@ pub(crate) struct ObligationStateTestCase { /// The results command over an obligation file, and its exit and JSON buckets. pub(crate) struct ObligationsCliTestCase { pub(crate) description: &'static str, - pub(crate) obligations: String, + /// The functions obligation file, or no obligations directory at all. + pub(crate) obligations: Option, pub(crate) expected_exit: ExitCode, /// Met, held and unmeasured obligations in the report, and obligations in the baseline. pub(crate) expected_buckets: Option<(u64, u64, u64, u64)>, @@ -94,6 +95,9 @@ pub(crate) struct ObligationsCliTestCase { pub(crate) struct ObligationDiffTestCase { pub(crate) description: &'static str, pub(crate) before: ObligationState, - pub(crate) after: ObligationState, + /// None when the head drops the obligation. + pub(crate) after: Option, + /// Whether the head's retired-obligations.toml lists it. + pub(crate) retired: bool, pub(crate) expected_regressions: usize, } From bfecd6398256b8d3de09d9b8a625dd6f9768f1f7 Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Fri, 6 Nov 2026 19:15:19 +0000 Subject: [PATCH 3/3] Re-record the translation results baseline with obligation states (D272c) The 30 auditor-confirmed forms move from matching to unmet_obligations; the figure is 57 of 1,187 translatable forms. No statement outcome changes. --- coverage/translation/results-baseline.json | 3497 +++++++++++++++++++- 1 file changed, 3466 insertions(+), 31 deletions(-) diff --git a/coverage/translation/results-baseline.json b/coverage/translation/results-baseline.json index 4053e30f0..d6611687b 100644 --- a/coverage/translation/results-baseline.json +++ b/coverage/translation/results-baseline.json @@ -12997,12 +12997,12 @@ "sf.expressions.data-types-datetime.interval": "unmeasured", "sf.expressions.data-types-datetime.interval-yearmonthqualifier-daytimequalifier": "unmeasured", "sf.expressions.data-types-datetime.interval.interval-constants": "refused", - "sf.expressions.data-types-datetime.time": "matching", + "sf.expressions.data-types-datetime.time": "unmet_obligations", "sf.expressions.data-types-datetime.timestamp": "matching", "sf.expressions.data-types-datetime.timestamp-variations": "refused", "sf.expressions.data-types-ipaddress": "unmeasured", "sf.expressions.data-types-ipaddress.typed-literal": "unmeasured", - "sf.expressions.data-types-logical": "matching", + "sf.expressions.data-types-logical": "unmet_obligations", "sf.expressions.data-types-numeric.decfloat": "unmeasured", "sf.expressions.data-types-numeric.decimal": "refused", "sf.expressions.data-types-numeric.double": "matching", @@ -13125,19 +13125,19 @@ "sf.functions.array-agg.array-agg-over": "refused", "sf.functions.array-append": "refused", "sf.functions.array-cat": "matching", - "sf.functions.array-compact": "matching", + "sf.functions.array-compact": "unmet_obligations", "sf.functions.array-construct": "refused", "sf.functions.array-construct-compact": "refused", "sf.functions.array-construct-structured": "refused", "sf.functions.array-contains": "refused", "sf.functions.array-distinct": "refused", "sf.functions.array-except": "refused", - "sf.functions.array-flatten": "matching", + "sf.functions.array-flatten": "unmet_obligations", "sf.functions.array-generate-range": "matching", "sf.functions.array-insert": "refused", "sf.functions.array-intersection": "refused", - "sf.functions.array-max": "matching", - "sf.functions.array-min": "matching", + "sf.functions.array-max": "unmet_obligations", + "sf.functions.array-min": "unmet_obligations", "sf.functions.array-position": "refused", "sf.functions.array-prepend": "refused", "sf.functions.array-remove": "matching", @@ -13246,9 +13246,9 @@ "sf.functions.complete-snowflake-cortex-multimodal.from.syntax": "unmeasured", "sf.functions.complete-task-graphs": "not_translatable", "sf.functions.compress": "refused", - "sf.functions.concat-ws": "matching", - "sf.functions.concat.concat": "matching", - "sf.functions.concat.concat-subscript-dot": "matching", + "sf.functions.concat-ws": "unmet_obligations", + "sf.functions.concat.concat": "unmet_obligations", + "sf.functions.concat.concat-subscript-dot": "unmet_obligations", "sf.functions.conditional-change-event": "refused", "sf.functions.conditional-true-event": "refused", "sf.functions.contains": "matching", @@ -13278,8 +13278,8 @@ "sf.functions.current-available-roles": "not_translatable", "sf.functions.current-client": "not_translatable", "sf.functions.current-database": "refused", - "sf.functions.current-date.current-date": "matching", - "sf.functions.current-date.current-date.syntax": "matching", + "sf.functions.current-date.current-date": "unmet_obligations", + "sf.functions.current-date.current-date.syntax": "unmet_obligations", "sf.functions.current-ip-address": "not_translatable", "sf.functions.current-organization-name": "not_translatable", "sf.functions.current-organization-user": "not_translatable", @@ -13700,9 +13700,9 @@ "sf.functions.is-agent-activated": "not_translatable", "sf.functions.is-application-role-activated": "not_translatable", "sf.functions.is-application-role-in-session": "not_translatable", - "sf.functions.is-array": "matching", - "sf.functions.is-binary": "matching", - "sf.functions.is-boolean": "matching", + "sf.functions.is-array": "unmet_obligations", + "sf.functions.is-binary": "unmet_obligations", + "sf.functions.is-boolean": "unmet_obligations", "sf.functions.is-char-varchar.is-char": "refused", "sf.functions.is-char-varchar.is-varchar": "refused", "sf.functions.is-configuration-set": "not_translatable", @@ -13718,19 +13718,19 @@ "sf.functions.is-group-activated": "not_translatable", "sf.functions.is-group-imported": "not_translatable", "sf.functions.is-instance-role-in-session": "not_translatable", - "sf.functions.is-integer": "matching", + "sf.functions.is-integer": "unmet_obligations", "sf.functions.is-null": "refused", "sf.functions.is-null-value": "matching", - "sf.functions.is-object": "matching", + "sf.functions.is-object": "unmet_obligations", "sf.functions.is-organization-user": "not_translatable", "sf.functions.is-organization-user-group": "not_translatable", "sf.functions.is-organization-user-group-in-session": "not_translatable", "sf.functions.is-role-activated": "not_translatable", "sf.functions.is-role-in-session": "not_translatable", - "sf.functions.is-time": "matching", + "sf.functions.is-time": "unmet_obligations", "sf.functions.is-timestamp.is-timestamp-ltz": "refused", "sf.functions.is-timestamp.is-timestamp-ntz": "refused", - "sf.functions.is-timestamp.is-timestamp-tz": "matching", + "sf.functions.is-timestamp.is-timestamp-tz": "unmet_obligations", "sf.functions.is-user-imported": "not_translatable", "sf.functions.jarowinkler-similarity": "refused", "sf.functions.json-extract-path-text": "refused", @@ -13745,9 +13745,9 @@ "sf.functions.lead": "refused", "sf.functions.least": "refused", "sf.functions.least-ignore-nulls": "refused", - "sf.functions.left": "matching", - "sf.functions.length.len": "matching", - "sf.functions.length.length": "matching", + "sf.functions.left": "unmet_obligations", + "sf.functions.length.len": "unmet_obligations", + "sf.functions.length.length": "unmet_obligations", "sf.functions.like-all": "unmeasured", "sf.functions.like-any": "refused", "sf.functions.like.like": "refused", @@ -13755,7 +13755,7 @@ "sf.functions.listagg.listagg": "refused", "sf.functions.listagg.listagg-over": "refused", "sf.functions.listing-refresh-history": "not_translatable", - "sf.functions.ln": "matching", + "sf.functions.ln": "unmet_obligations", "sf.functions.localtime.localtime": "refused", "sf.functions.localtime.localtime.syntax": "refused", "sf.functions.localtimestamp.localtimestamp": "refused", @@ -13764,7 +13764,7 @@ "sf.functions.login-history.login-history": "not_translatable", "sf.functions.login-history.login-history-by-user": "not_translatable", "sf.functions.lower": "matching", - "sf.functions.lpad": "matching", + "sf.functions.lpad": "unmet_obligations", "sf.functions.ltrim": "matching", "sf.functions.map-cat": "refused", "sf.functions.map-construct": "refused", @@ -13814,7 +13814,7 @@ "sf.functions.notification-history": "not_translatable", "sf.functions.nth-value": "refused", "sf.functions.ntile": "refused", - "sf.functions.nullif": "matching", + "sf.functions.nullif": "unmet_obligations", "sf.functions.nullifzero": "matching", "sf.functions.nvl": "matching", "sf.functions.nvl2": "refused", @@ -13861,7 +13861,7 @@ "sf.functions.policy-references.policy-name-policy-kind": "not_translatable", "sf.functions.policy-references.ref-entity-name-ref-entity-domain": "not_translatable", "sf.functions.position.position": "refused", - "sf.functions.position.position-in": "matching", + "sf.functions.position.position-in": "unmet_obligations", "sf.functions.pow.pow": "refused", "sf.functions.pow.power": "refused", "sf.functions.previous-day": "refused", @@ -13921,13 +13921,13 @@ "sf.functions.rest-event-history": "not_translatable", "sf.functions.result-scan": "not_translatable", "sf.functions.reverse": "refused", - "sf.functions.right": "matching", + "sf.functions.right": "unmet_obligations", "sf.functions.rlike.rlike": "refused", "sf.functions.rlike.rlike.syntax": "refused", "sf.functions.round.round": "refused", "sf.functions.round.round-expr-scale": "refused", "sf.functions.row-number": "matching", - "sf.functions.rpad": "matching", + "sf.functions.rpad": "unmet_obligations", "sf.functions.rtrim": "matching", "sf.functions.rtrimmed-length": "refused", "sf.functions.sanitize-webhook-content": "unmeasured", @@ -13973,7 +13973,7 @@ "sf.functions.split-text-markdown-header-snowflake-cortex": "not_translatable", "sf.functions.split-text-recursive-character-snowflake-cortex": "not_translatable", "sf.functions.split-to-table": "refused", - "sf.functions.sqrt": "matching", + "sf.functions.sqrt": "unmet_obligations", "sf.functions.square": "refused", "sf.functions.st-area": "refused", "sf.functions.st-asewkb": "refused", @@ -14067,8 +14067,8 @@ "sf.functions.strtok": "refused", "sf.functions.strtok-split-to-table": "refused", "sf.functions.strtok-to-array": "refused", - "sf.functions.substr.substr": "matching", - "sf.functions.substr.substring": "matching", + "sf.functions.substr.substr": "unmet_obligations", + "sf.functions.substr.substring": "unmet_obligations", "sf.functions.sum.sum": "refused", "sf.functions.sum.sum-over": "refused", "sf.functions.sys-context": "not_translatable", @@ -15224,5 +15224,3440 @@ "sf.utility.execute-task.task-retry-graph-run": "not_translatable", "sf.utility.execute-task.task-retry-last": "not_translatable", "sf.utility.explain": "not_translatable" - } + }, + "obligations": { + "sf.expressions.data-types-datetime.time.t001": "unmet", + "sf.expressions.data-types-datetime.time.t002": "unmet", + "sf.expressions.data-types-datetime.time.t003": "met", + "sf.expressions.data-types-datetime.timestamp.t001": "met", + "sf.expressions.data-types-datetime.timestamp.t002": "met", + "sf.expressions.data-types-datetime.timestamp.t003": "met", + "sf.expressions.data-types-logical.t001": "met", + "sf.expressions.data-types-logical.t002": "met", + "sf.expressions.data-types-logical.t003": "met", + "sf.expressions.data-types-logical.t004": "met", + "sf.expressions.data-types-logical.t005": "unmet", + "sf.expressions.data-types-logical.t006": "unmet", + "sf.expressions.data-types-logical.t007": "met", + "sf.expressions.data-types-logical.t008": "held", + "sf.expressions.data-types-logical.t009": "met", + "sf.expressions.data-types-logical.t010": "unmet", + "sf.expressions.data-types-numeric.double.t001": "met", + "sf.expressions.data-types-numeric.double.t002": "met", + "sf.expressions.data-types-numeric.double.t003": "met", + "sf.expressions.data-types-numeric.int.t001": "met", + "sf.expressions.data-types-numeric.int.t002": "met", + "sf.expressions.data-types-numeric.int.t003": "met", + "sf.expressions.data-types-numeric.int.t004": "met", + "sf.expressions.data-types-semistructured.array-index-access.t001": "met", + "sf.expressions.data-types-semistructured.array-index-access.t002": "met", + "sf.expressions.data-types-semistructured.array-index-access.t003": "met", + "sf.expressions.data-types-semistructured.array.t001": "met", + "sf.expressions.data-types-semistructured.array.t002": "met", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t001": "met", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t002": "unmet", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t003": "unmet", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t004": "unmet", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t005": "unmet", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t006": "held", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t007": "held", + "sf.expressions.data-types-semistructured.colon-subscript-dot.t008": "met", + "sf.expressions.data-types-semistructured.object-key-access.t001": "met", + "sf.expressions.data-types-semistructured.object-key-access.t002": "met", + "sf.expressions.data-types-semistructured.object-key-access.t003": "met", + "sf.expressions.data-types-semistructured.object.t001": "met", + "sf.expressions.data-types-semistructured.object.t002": "met", + "sf.expressions.data-types-semistructured.subscript-dot.t001": "met", + "sf.expressions.data-types-semistructured.subscript-dot.t002": "unmet", + "sf.expressions.data-types-text.dollar-quoted-string-constant.t001": "met", + "sf.expressions.data-types-text.dollar-quoted-string-constant.t002": "met", + "sf.expressions.data-types-text.dollar-quoted-string-constant.t003": "met", + "sf.expressions.data-types-text.dollar-quoted-string-constant.t004": "met", + "sf.expressions.data-types-text.dollar-quoted-string-constant.t005": "met", + "sf.expressions.operators-arithmetic.add.t001": "met", + "sf.expressions.operators-arithmetic.add.t002": "met", + "sf.expressions.operators-arithmetic.add.t003": "met", + "sf.expressions.operators-arithmetic.add.t004": "met", + "sf.expressions.operators-arithmetic.add.t005": "met", + "sf.expressions.operators-arithmetic.add.t006": "met", + "sf.expressions.operators-arithmetic.add.t007": "met", + "sf.expressions.operators-arithmetic.add.t008": "met", + "sf.expressions.operators-arithmetic.add.t009": "met", + "sf.expressions.operators-arithmetic.add.t010": "met", + "sf.expressions.operators-arithmetic.add.t011": "met", + "sf.expressions.operators-arithmetic.divide.t001": "met", + "sf.expressions.operators-arithmetic.divide.t002": "met", + "sf.expressions.operators-arithmetic.divide.t003": "met", + "sf.expressions.operators-arithmetic.divide.t004": "met", + "sf.expressions.operators-arithmetic.divide.t005": "met", + "sf.expressions.operators-arithmetic.divide.t006": "met", + "sf.expressions.operators-arithmetic.divide.t007": "met", + "sf.expressions.operators-arithmetic.divide.t008": "met", + "sf.expressions.operators-arithmetic.divide.t009": "met", + "sf.expressions.operators-arithmetic.divide.t010": "met", + "sf.expressions.operators-arithmetic.divide.t011": "met", + "sf.expressions.operators-arithmetic.modulo.t001": "met", + "sf.expressions.operators-arithmetic.modulo.t002": "met", + "sf.expressions.operators-arithmetic.modulo.t003": "met", + "sf.expressions.operators-arithmetic.modulo.t004": "unmet", + "sf.expressions.operators-arithmetic.modulo.t005": "unmet", + "sf.expressions.operators-arithmetic.modulo.t006": "met", + "sf.expressions.operators-arithmetic.modulo.t007": "met", + "sf.expressions.operators-arithmetic.modulo.t008": "met", + "sf.expressions.operators-arithmetic.modulo.t009": "unmet", + "sf.expressions.operators-arithmetic.modulo.t010": "met", + "sf.expressions.operators-arithmetic.multiply.t001": "met", + "sf.expressions.operators-arithmetic.multiply.t002": "met", + "sf.expressions.operators-arithmetic.multiply.t003": "met", + "sf.expressions.operators-arithmetic.multiply.t004": "met", + "sf.expressions.operators-arithmetic.multiply.t005": "met", + "sf.expressions.operators-arithmetic.multiply.t006": "met", + "sf.expressions.operators-arithmetic.multiply.t007": "met", + "sf.expressions.operators-arithmetic.multiply.t008": "met", + "sf.expressions.operators-arithmetic.multiply.t009": "met", + "sf.expressions.operators-arithmetic.multiply.t010": "met", + "sf.expressions.operators-arithmetic.multiply.t011": "met", + "sf.expressions.operators-arithmetic.subtract.t001": "met", + "sf.expressions.operators-arithmetic.subtract.t002": "met", + "sf.expressions.operators-arithmetic.subtract.t003": "met", + "sf.expressions.operators-arithmetic.subtract.t004": "met", + "sf.expressions.operators-arithmetic.subtract.t005": "met", + "sf.expressions.operators-arithmetic.subtract.t006": "met", + "sf.expressions.operators-arithmetic.subtract.t007": "unmet", + "sf.expressions.operators-arithmetic.subtract.t008": "met", + "sf.expressions.operators-arithmetic.subtract.t009": "met", + "sf.expressions.operators-arithmetic.subtract.t010": "met", + "sf.expressions.operators-arithmetic.subtract.t011": "met", + "sf.expressions.operators-arithmetic.unary-minus.t001": "met", + "sf.expressions.operators-arithmetic.unary-minus.t002": "met", + "sf.expressions.operators-arithmetic.unary-minus.t003": "met", + "sf.expressions.operators-arithmetic.unary-minus.t004": "met", + "sf.expressions.operators-arithmetic.unary-minus.t005": "met", + "sf.expressions.operators-arithmetic.unary-minus.t006": "met", + "sf.expressions.operators-arithmetic.unary-plus.t001": "unmet", + "sf.expressions.operators-arithmetic.unary-plus.t002": "unmet", + "sf.expressions.operators-arithmetic.unary-plus.t003": "unmet", + "sf.expressions.operators-arithmetic.unary-plus.t004": "unmet", + "sf.expressions.operators-arithmetic.unary-plus.t005": "unmet", + "sf.expressions.operators-arithmetic.unary-plus.t006": "unmet", + "sf.expressions.operators-comparison.equal.t001": "met", + "sf.expressions.operators-comparison.equal.t002": "met", + "sf.expressions.operators-comparison.equal.t003": "unmet", + "sf.expressions.operators-comparison.equal.t004": "met", + "sf.expressions.operators-comparison.equal.t005": "met", + "sf.expressions.operators-comparison.equal.t006": "met", + "sf.expressions.operators-comparison.greater-or-equal.t001": "met", + "sf.expressions.operators-comparison.greater-or-equal.t002": "met", + "sf.expressions.operators-comparison.greater-or-equal.t003": "unmet", + "sf.expressions.operators-comparison.greater-or-equal.t004": "met", + "sf.expressions.operators-comparison.greater-or-equal.t005": "met", + "sf.expressions.operators-comparison.greater.t001": "met", + "sf.expressions.operators-comparison.greater.t002": "met", + "sf.expressions.operators-comparison.greater.t003": "unmet", + "sf.expressions.operators-comparison.greater.t004": "met", + "sf.expressions.operators-comparison.greater.t005": "met", + "sf.expressions.operators-comparison.less-or-equal.t001": "met", + "sf.expressions.operators-comparison.less-or-equal.t002": "met", + "sf.expressions.operators-comparison.less-or-equal.t003": "unmet", + "sf.expressions.operators-comparison.less-or-equal.t004": "met", + "sf.expressions.operators-comparison.less-or-equal.t005": "met", + "sf.expressions.operators-comparison.less.t001": "met", + "sf.expressions.operators-comparison.less.t002": "met", + "sf.expressions.operators-comparison.less.t003": "unmet", + "sf.expressions.operators-comparison.less.t004": "met", + "sf.expressions.operators-comparison.less.t005": "met", + "sf.expressions.operators-comparison.not-equal-angle.t001": "met", + "sf.expressions.operators-comparison.not-equal-angle.t002": "met", + "sf.expressions.operators-comparison.not-equal-angle.t003": "unmet", + "sf.expressions.operators-comparison.not-equal-angle.t004": "met", + "sf.expressions.operators-comparison.not-equal-angle.t005": "met", + "sf.expressions.operators-comparison.not-equal-bang.t001": "met", + "sf.expressions.operators-comparison.not-equal-bang.t002": "met", + "sf.expressions.operators-comparison.not-equal-bang.t003": "unmet", + "sf.expressions.operators-comparison.not-equal-bang.t004": "met", + "sf.expressions.operators-comparison.not-equal-bang.t005": "met", + "sf.expressions.operators-flow.t001": "held", + "sf.expressions.operators-flow.t002": "held", + "sf.expressions.operators-flow.t003": "held", + "sf.expressions.operators-logical.and.t001": "met", + "sf.expressions.operators-logical.and.t002": "met", + "sf.expressions.operators-logical.and.t003": "met", + "sf.expressions.operators-logical.and.t004": "met", + "sf.expressions.operators-logical.not.t001": "met", + "sf.expressions.operators-logical.not.t002": "met", + "sf.expressions.operators-logical.not.t003": "met", + "sf.expressions.operators-logical.or.t001": "met", + "sf.expressions.operators-logical.or.t002": "met", + "sf.expressions.operators-logical.or.t003": "met", + "sf.expressions.operators-logical.or.t004": "met", + "sf.expressions.operators-subquery.comparisonoperator-all-any.t001": "unmet", + "sf.expressions.operators-subquery.comparisonoperator-all-any.t002": "unmet", + "sf.expressions.operators-subquery.comparisonoperator-all-any.t003": "unmet", + "sf.expressions.operators-subquery.comparisonoperator-all-any.t004": "unmet", + "sf.expressions.operators-subquery.comparisonoperator-all-any.t005": "unmet", + "sf.expressions.operators-subquery.exists.t001": "met", + "sf.expressions.operators-subquery.exists.t002": "met", + "sf.expressions.operators-subquery.exists.t003": "met", + "sf.expressions.operators-subquery.in.t001": "met", + "sf.expressions.operators-subquery.in.t002": "met", + "sf.expressions.operators-subquery.in.t003": "met", + "sf.expressions.operators-subquery.in.t004": "met", + "sf.functions.abs.t001": "met", + "sf.functions.abs.t002": "met", + "sf.functions.abs.t003": "met", + "sf.functions.abs.t004": "met", + "sf.functions.abs.t005": "met", + "sf.functions.accumulate.t001": "unmet", + "sf.functions.accumulate.t002": "unmet", + "sf.functions.accumulate.t003": "unmet", + "sf.functions.acos.t001": "unmet", + "sf.functions.acos.t002": "unmet", + "sf.functions.acos.t003": "unmet", + "sf.functions.acos.t004": "unmet", + "sf.functions.acos.t005": "unmet", + "sf.functions.acosh.t001": "unmet", + "sf.functions.acosh.t002": "unmet", + "sf.functions.acosh.t003": "unmet", + "sf.functions.acosh.t004": "unmet", + "sf.functions.acosh.t005": "unmet", + "sf.functions.add-months.t001": "unmet", + "sf.functions.add-months.t002": "unmet", + "sf.functions.add-months.t003": "unmet", + "sf.functions.add-months.t004": "unmet", + "sf.functions.add-months.t005": "unmet", + "sf.functions.add-months.t006": "unmet", + "sf.functions.add-months.t007": "unmet", + "sf.functions.any-value.any-value-over.t001": "unmet", + "sf.functions.any-value.any-value-over.t002": "unmet", + "sf.functions.any-value.any-value-over.t003": "unmet", + "sf.functions.any-value.any-value-over.t004": "unmet", + "sf.functions.any-value.any-value.t001": "met", + "sf.functions.any-value.any-value.t002": "met", + "sf.functions.any-value.any-value.t003": "unmet", + "sf.functions.any-value.any-value.t004": "met", + "sf.functions.any-value.any-value.t005": "met", + "sf.functions.approx-count-distinct.approx-count-distinct-over.syntax.t001": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct-over.syntax.t002": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct-over.syntax.t003": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct-over.t001": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct-over.t002": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct-over.t003": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct-over.t004": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct.t001": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct.t002": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct.t003": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct.t004": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct.t005": "unmet", + "sf.functions.approx-count-distinct.approx-count-distinct.t006": "unmet", + "sf.functions.approx-percentile-accumulate.t001": "unmet", + "sf.functions.approx-percentile-accumulate.t002": "unmet", + "sf.functions.approx-percentile-combine.t001": "unmet", + "sf.functions.approx-percentile-combine.t002": "unmet", + "sf.functions.approx-percentile-estimate.t001": "unmet", + "sf.functions.approx-percentile-estimate.t002": "unmet", + "sf.functions.approx-percentile-estimate.t003": "unmet", + "sf.functions.approx-percentile.approx-percentile-over.t001": "unmet", + "sf.functions.approx-percentile.approx-percentile-over.t002": "unmet", + "sf.functions.approx-percentile.approx-percentile-over.t003": "unmet", + "sf.functions.approx-percentile.approx-percentile-over.t004": "unmet", + "sf.functions.approx-percentile.approx-percentile.t001": "unmet", + "sf.functions.approx-percentile.approx-percentile.t002": "unmet", + "sf.functions.approx-percentile.approx-percentile.t003": "unmet", + "sf.functions.approx-percentile.approx-percentile.t004": "unmet", + "sf.functions.approx-percentile.approx-percentile.t005": "unmet", + "sf.functions.approx-top-k-accumulate.t001": "unmet", + "sf.functions.approx-top-k-accumulate.t002": "unmet", + "sf.functions.approx-top-k-combine.t001": "unmet", + "sf.functions.approx-top-k-combine.t002": "unmet", + "sf.functions.approx-top-k-combine.t003": "unmet", + "sf.functions.approx-top-k-estimate.t001": "unmet", + "sf.functions.approx-top-k-estimate.t002": "unmet", + "sf.functions.approx-top-k-estimate.t003": "unmet", + "sf.functions.approx-top-k.approx-top-k-over.t001": "unmet", + "sf.functions.approx-top-k.approx-top-k-over.t002": "unmet", + "sf.functions.approx-top-k.approx-top-k-over.t003": "unmet", + "sf.functions.approx-top-k.approx-top-k-over.t004": "unmet", + "sf.functions.approx-top-k.approx-top-k.t001": "unmet", + "sf.functions.approx-top-k.approx-top-k.t002": "unmet", + "sf.functions.approx-top-k.approx-top-k.t003": "unmet", + "sf.functions.approx-top-k.approx-top-k.t004": "unmet", + "sf.functions.approx-top-k.approx-top-k.t005": "unmet", + "sf.functions.approx-top-k.approx-top-k.t006": "unmet", + "sf.functions.approximate-jaccard-index.approximate-jaccard-index.t001": "unmet", + "sf.functions.approximate-jaccard-index.approximate-jaccard-index.t002": "unmet", + "sf.functions.approximate-jaccard-index.approximate-jaccard-index.t003": "unmet", + "sf.functions.approximate-jaccard-index.approximate-jaccard-index.t004": "unmet", + "sf.functions.approximate-similarity.approximate-similarity.t001": "unmet", + "sf.functions.approximate-similarity.approximate-similarity.t002": "unmet", + "sf.functions.approximate-similarity.approximate-similarity.t003": "unmet", + "sf.functions.approximate-similarity.approximate-similarity.t004": "unmet", + "sf.functions.array-agg.array-agg-over.t001": "unmet", + "sf.functions.array-agg.array-agg-over.t002": "unmet", + "sf.functions.array-agg.array-agg-over.t003": "unmet", + "sf.functions.array-agg.array-agg-over.t004": "unmet", + "sf.functions.array-agg.array-agg-over.t005": "unmet", + "sf.functions.array-agg.array-agg-over.t006": "unmet", + "sf.functions.array-agg.array-agg-over.t007": "unmet", + "sf.functions.array-agg.array-agg-over.t008": "unmet", + "sf.functions.array-agg.array-agg.t001": "met", + "sf.functions.array-agg.array-agg.t002": "met", + "sf.functions.array-agg.array-agg.t003": "met", + "sf.functions.array-agg.array-agg.t004": "unmet", + "sf.functions.array-agg.array-agg.t005": "unmet", + "sf.functions.array-agg.array-agg.t006": "met", + "sf.functions.array-agg.array-agg.t007": "met", + "sf.functions.array-append.t001": "met", + "sf.functions.array-append.t002": "met", + "sf.functions.array-append.t003": "unmet", + "sf.functions.array-cat.t001": "met", + "sf.functions.array-cat.t002": "met", + "sf.functions.array-cat.t003": "met", + "sf.functions.array-cat.t004": "met", + "sf.functions.array-cat.t005": "met", + "sf.functions.array-compact.t001": "met", + "sf.functions.array-compact.t002": "unmet", + "sf.functions.array-compact.t003": "met", + "sf.functions.array-construct-compact.t001": "met", + "sf.functions.array-construct-compact.t002": "met", + "sf.functions.array-construct-compact.t003": "unmet", + "sf.functions.array-construct-compact.t004": "met", + "sf.functions.array-construct-structured.t001": "unmet", + "sf.functions.array-construct-structured.t002": "unmet", + "sf.functions.array-construct-structured.t003": "unmet", + "sf.functions.array-construct.t001": "met", + "sf.functions.array-construct.t002": "met", + "sf.functions.array-construct.t003": "unmet", + "sf.functions.array-contains.t001": "met", + "sf.functions.array-contains.t002": "met", + "sf.functions.array-contains.t003": "met", + "sf.functions.array-contains.t004": "unmet", + "sf.functions.array-distinct.t001": "met", + "sf.functions.array-distinct.t002": "met", + "sf.functions.array-distinct.t003": "unmet", + "sf.functions.array-distinct.t004": "met", + "sf.functions.array-except.t001": "unmet", + "sf.functions.array-except.t002": "unmet", + "sf.functions.array-except.t003": "unmet", + "sf.functions.array-except.t004": "met", + "sf.functions.array-flatten.t001": "met", + "sf.functions.array-flatten.t002": "met", + "sf.functions.array-flatten.t003": "unmet", + "sf.functions.array-generate-range.t001": "met", + "sf.functions.array-generate-range.t002": "met", + "sf.functions.array-generate-range.t003": "met", + "sf.functions.array-generate-range.t004": "met", + "sf.functions.array-generate-range.t005": "met", + "sf.functions.array-insert.t001": "unmet", + "sf.functions.array-insert.t002": "unmet", + "sf.functions.array-insert.t003": "unmet", + "sf.functions.array-insert.t004": "unmet", + "sf.functions.array-intersection.t001": "met", + "sf.functions.array-intersection.t002": "met", + "sf.functions.array-intersection.t003": "met", + "sf.functions.array-intersection.t004": "met", + "sf.functions.array-max.t001": "met", + "sf.functions.array-max.t002": "met", + "sf.functions.array-max.t003": "met", + "sf.functions.array-max.t004": "met", + "sf.functions.array-max.t005": "unmet", + "sf.functions.array-min.t001": "met", + "sf.functions.array-min.t002": "met", + "sf.functions.array-min.t003": "met", + "sf.functions.array-min.t004": "met", + "sf.functions.array-min.t005": "unmet", + "sf.functions.array-position.t001": "met", + "sf.functions.array-position.t002": "met", + "sf.functions.array-position.t003": "met", + "sf.functions.array-position.t004": "unmet", + "sf.functions.array-prepend.t001": "unmet", + "sf.functions.array-prepend.t002": "unmet", + "sf.functions.array-prepend.t003": "unmet", + "sf.functions.array-remove-at.t001": "unmet", + "sf.functions.array-remove-at.t002": "unmet", + "sf.functions.array-remove-at.t003": "unmet", + "sf.functions.array-remove-at.t004": "unmet", + "sf.functions.array-remove.t001": "met", + "sf.functions.array-remove.t002": "met", + "sf.functions.array-remove.t003": "met", + "sf.functions.array-repeat.t001": "unmet", + "sf.functions.array-repeat.t002": "unmet", + "sf.functions.array-repeat.t003": "unmet", + "sf.functions.array-reverse.t001": "met", + "sf.functions.array-reverse.t002": "met", + "sf.functions.array-size.t001": "met", + "sf.functions.array-size.t002": "unmet", + "sf.functions.array-size.t003": "met", + "sf.functions.array-size.t004": "met", + "sf.functions.array-slice.t001": "met", + "sf.functions.array-slice.t002": "met", + "sf.functions.array-slice.t003": "met", + "sf.functions.array-slice.t004": "met", + "sf.functions.array-sort.t001": "unmet", + "sf.functions.array-sort.t002": "unmet", + "sf.functions.array-sort.t003": "unmet", + "sf.functions.array-sort.t004": "unmet", + "sf.functions.array-sort.t005": "unmet", + "sf.functions.array-sum.t001": "unmet", + "sf.functions.array-sum.t002": "unmet", + "sf.functions.array-sum.t003": "unmet", + "sf.functions.array-sum.t004": "unmet", + "sf.functions.array-to-string.t001": "unmet", + "sf.functions.array-to-string.t002": "met", + "sf.functions.array-to-string.t003": "unmet", + "sf.functions.array-to-string.t004": "unmet", + "sf.functions.array-to-string.t005": "unmet", + "sf.functions.array-union-agg.array-union-agg-over.t001": "unmet", + "sf.functions.array-union-agg.array-union-agg-over.t002": "unmet", + "sf.functions.array-union-agg.array-union-agg-over.t003": "unmet", + "sf.functions.array-union-agg.array-union-agg-over.t004": "unmet", + "sf.functions.array-union-agg.array-union-agg.t001": "unmet", + "sf.functions.array-union-agg.array-union-agg.t002": "unmet", + "sf.functions.array-union-agg.array-union-agg.t003": "unmet", + "sf.functions.array-union-agg.array-union-agg.t004": "unmet", + "sf.functions.array-unique-agg.array-unique-agg-over.t001": "unmet", + "sf.functions.array-unique-agg.array-unique-agg-over.t002": "unmet", + "sf.functions.array-unique-agg.array-unique-agg-over.t003": "unmet", + "sf.functions.array-unique-agg.array-unique-agg-over.t004": "unmet", + "sf.functions.array-unique-agg.array-unique-agg.t001": "unmet", + "sf.functions.array-unique-agg.array-unique-agg.t002": "unmet", + "sf.functions.array-unique-agg.array-unique-agg.t003": "unmet", + "sf.functions.array-unique-agg.array-unique-agg.t004": "unmet", + "sf.functions.arrays-overlap.t001": "met", + "sf.functions.arrays-overlap.t002": "met", + "sf.functions.arrays-overlap.t003": "met", + "sf.functions.arrays-overlap.t004": "unmet", + "sf.functions.arrays-to-object.t001": "unmet", + "sf.functions.arrays-to-object.t002": "unmet", + "sf.functions.arrays-to-object.t003": "unmet", + "sf.functions.arrays-to-object.t004": "unmet", + "sf.functions.arrays-zip.t001": "unmet", + "sf.functions.arrays-zip.t002": "unmet", + "sf.functions.arrays-zip.t003": "unmet", + "sf.functions.arrays-zip.t004": "unmet", + "sf.functions.as-array.t001": "unmet", + "sf.functions.as-array.t002": "unmet", + "sf.functions.as-array.t003": "unmet", + "sf.functions.as-binary.t001": "unmet", + "sf.functions.as-binary.t002": "unmet", + "sf.functions.as-binary.t003": "unmet", + "sf.functions.as-boolean.t001": "unmet", + "sf.functions.as-boolean.t002": "unmet", + "sf.functions.as-boolean.t003": "unmet", + "sf.functions.as-char-varchar.as-char.t001": "unmet", + "sf.functions.as-char-varchar.as-char.t002": "unmet", + "sf.functions.as-char-varchar.as-char.t003": "unmet", + "sf.functions.as-char-varchar.as-varchar.t001": "unmet", + "sf.functions.as-char-varchar.as-varchar.t002": "unmet", + "sf.functions.as-char-varchar.as-varchar.t003": "unmet", + "sf.functions.as-date.t001": "unmet", + "sf.functions.as-date.t002": "unmet", + "sf.functions.as-date.t003": "unmet", + "sf.functions.as-date.t004": "unmet", + "sf.functions.as-decimal-number.as-decimal.t001": "unmet", + "sf.functions.as-decimal-number.as-decimal.t002": "unmet", + "sf.functions.as-decimal-number.as-decimal.t003": "unmet", + "sf.functions.as-decimal-number.as-decimal.t004": "unmet", + "sf.functions.as-decimal-number.as-decimal.t005": "unmet", + "sf.functions.as-decimal-number.as-number.t001": "unmet", + "sf.functions.as-decimal-number.as-number.t002": "unmet", + "sf.functions.as-decimal-number.as-number.t003": "unmet", + "sf.functions.as-decimal-number.as-number.t004": "unmet", + "sf.functions.as-decimal-number.as-number.t005": "unmet", + "sf.functions.as-double-real.as-double.t001": "unmet", + "sf.functions.as-double-real.as-double.t002": "unmet", + "sf.functions.as-double-real.as-double.t003": "unmet", + "sf.functions.as-double-real.as-double.t004": "unmet", + "sf.functions.as-double-real.as-real.t001": "unmet", + "sf.functions.as-double-real.as-real.t002": "unmet", + "sf.functions.as-double-real.as-real.t003": "unmet", + "sf.functions.as-double-real.as-real.t004": "unmet", + "sf.functions.as-integer.t001": "unmet", + "sf.functions.as-integer.t002": "unmet", + "sf.functions.as-integer.t003": "unmet", + "sf.functions.as-integer.t004": "unmet", + "sf.functions.as-object.t001": "unmet", + "sf.functions.as-object.t002": "unmet", + "sf.functions.as-object.t003": "unmet", + "sf.functions.as-time.t001": "unmet", + "sf.functions.as-time.t002": "unmet", + "sf.functions.as-time.t003": "unmet", + "sf.functions.as-timestamp.as-timestamp-ltz.t001": "unmet", + "sf.functions.as-timestamp.as-timestamp-ltz.t002": "unmet", + "sf.functions.as-timestamp.as-timestamp-ltz.t003": "unmet", + "sf.functions.as-timestamp.as-timestamp-ltz.t004": "unmet", + "sf.functions.as-timestamp.as-timestamp-ntz.t001": "unmet", + "sf.functions.as-timestamp.as-timestamp-ntz.t002": "unmet", + "sf.functions.as-timestamp.as-timestamp-ntz.t003": "unmet", + "sf.functions.as-timestamp.as-timestamp-ntz.t004": "unmet", + "sf.functions.as-timestamp.as-timestamp-tz.t001": "unmet", + "sf.functions.as-timestamp.as-timestamp-tz.t002": "unmet", + "sf.functions.as-timestamp.as-timestamp-tz.t003": "unmet", + "sf.functions.as-timestamp.as-timestamp-tz.t004": "unmet", + "sf.functions.ascii.t001": "unmet", + "sf.functions.ascii.t002": "unmet", + "sf.functions.ascii.t003": "unmet", + "sf.functions.asin.t001": "unmet", + "sf.functions.asin.t002": "unmet", + "sf.functions.asin.t003": "unmet", + "sf.functions.asin.t004": "unmet", + "sf.functions.asin.t005": "unmet", + "sf.functions.asinh.t001": "unmet", + "sf.functions.asinh.t002": "unmet", + "sf.functions.asinh.t003": "unmet", + "sf.functions.asinh.t004": "unmet", + "sf.functions.atan.t001": "unmet", + "sf.functions.atan.t002": "unmet", + "sf.functions.atan.t003": "unmet", + "sf.functions.atan.t004": "unmet", + "sf.functions.atan2.t001": "unmet", + "sf.functions.atan2.t002": "unmet", + "sf.functions.atan2.t003": "unmet", + "sf.functions.atan2.t004": "unmet", + "sf.functions.atan2.t005": "unmet", + "sf.functions.atan2.t006": "unmet", + "sf.functions.atan2.t007": "unmet", + "sf.functions.atan2.t008": "unmet", + "sf.functions.atanh.t001": "unmet", + "sf.functions.atanh.t002": "unmet", + "sf.functions.atanh.t003": "unmet", + "sf.functions.atanh.t004": "unmet", + "sf.functions.atanh.t005": "unmet", + "sf.functions.atanh.t006": "unmet", + "sf.functions.avg.avg-over.t001": "met", + "sf.functions.avg.avg-over.t002": "met", + "sf.functions.avg.avg-over.t003": "met", + "sf.functions.avg.avg-over.t004": "met", + "sf.functions.avg.avg-over.t005": "met", + "sf.functions.avg.avg-over.t006": "met", + "sf.functions.avg.avg-over.t007": "met", + "sf.functions.avg.avg-over.t008": "unmet", + "sf.functions.avg.avg-over.t009": "unmet", + "sf.functions.avg.avg.t001": "met", + "sf.functions.avg.avg.t002": "met", + "sf.functions.avg.avg.t003": "unmet", + "sf.functions.avg.avg.t004": "unmet", + "sf.functions.avg.avg.t005": "held", + "sf.functions.avg.avg.t006": "met", + "sf.functions.avg.avg.t007": "met", + "sf.functions.base64-decode-binary.t001": "unmet", + "sf.functions.base64-decode-binary.t002": "unmet", + "sf.functions.base64-decode-binary.t003": "unmet", + "sf.functions.base64-decode-binary.t004": "unmet", + "sf.functions.base64-decode-binary.t005": "unmet", + "sf.functions.base64-decode-binary.t006": "unmet", + "sf.functions.base64-decode-string.t001": "unmet", + "sf.functions.base64-decode-string.t002": "unmet", + "sf.functions.base64-decode-string.t003": "unmet", + "sf.functions.base64-decode-string.t004": "unmet", + "sf.functions.base64-decode-string.t005": "unmet", + "sf.functions.base64-decode-string.t006": "unmet", + "sf.functions.base64-encode.t001": "unmet", + "sf.functions.base64-encode.t002": "unmet", + "sf.functions.base64-encode.t003": "unmet", + "sf.functions.base64-encode.t004": "unmet", + "sf.functions.base64-encode.t005": "unmet", + "sf.functions.base64-encode.t006": "unmet", + "sf.functions.base64-encode.t007": "unmet", + "sf.functions.base64-encode.t008": "unmet", + "sf.functions.between.t001": "met", + "sf.functions.between.t002": "met", + "sf.functions.between.t003": "unmet", + "sf.functions.between.t004": "met", + "sf.functions.between.t005": "met", + "sf.functions.between.t006": "met", + "sf.functions.between.t007": "met", + "sf.functions.between.t008": "unmet", + "sf.functions.bit-length.t001": "unmet", + "sf.functions.bit-length.t002": "unmet", + "sf.functions.bit-length.t003": "unmet", + "sf.functions.bit-length.t004": "unmet", + "sf.functions.bitand-agg.bitand-agg-over.t001": "unmet", + "sf.functions.bitand-agg.bitand-agg-over.t002": "unmet", + "sf.functions.bitand-agg.bitand-agg-over.t003": "unmet", + "sf.functions.bitand-agg.bitand-agg-over.t004": "unmet", + "sf.functions.bitand-agg.bitand-agg.t001": "unmet", + "sf.functions.bitand-agg.bitand-agg.t002": "unmet", + "sf.functions.bitand-agg.bitand-agg.t003": "unmet", + "sf.functions.bitand-agg.bitand-agg.t004": "unmet", + "sf.functions.bitand-agg.bitand-agg.t005": "unmet", + "sf.functions.bitand-agg.bitand-agg.t006": "unmet", + "sf.functions.bitand-agg.bitand-agg.t007": "unmet", + "sf.functions.bitand.t001": "met", + "sf.functions.bitand.t002": "unmet", + "sf.functions.bitand.t003": "unmet", + "sf.functions.bitand.t004": "unmet", + "sf.functions.bitand.t005": "unmet", + "sf.functions.bitand.t006": "met", + "sf.functions.bitmap-absolute-position.t001": "unmet", + "sf.functions.bitmap-absolute-position.t002": "unmet", + "sf.functions.bitmap-absolute-position.t003": "unmet", + "sf.functions.bitmap-absolute-position.t004": "unmet", + "sf.functions.bitmap-and-agg.t001": "unmet", + "sf.functions.bitmap-and-agg.t002": "unmet", + "sf.functions.bitmap-and-agg.t003": "unmet", + "sf.functions.bitmap-and.t001": "unmet", + "sf.functions.bitmap-and.t002": "unmet", + "sf.functions.bitmap-and.t003": "unmet", + "sf.functions.bitmap-bit-position.t001": "unmet", + "sf.functions.bitmap-bit-position.t002": "unmet", + "sf.functions.bitmap-bucket-number.t001": "unmet", + "sf.functions.bitmap-bucket-number.t002": "unmet", + "sf.functions.bitmap-bucket-number.t003": "unmet", + "sf.functions.bitmap-construct-agg.t001": "unmet", + "sf.functions.bitmap-construct-agg.t002": "unmet", + "sf.functions.bitmap-construct-agg.t003": "unmet", + "sf.functions.bitmap-count.t001": "unmet", + "sf.functions.bitmap-count.t002": "unmet", + "sf.functions.bitmap-or-agg.t001": "unmet", + "sf.functions.bitmap-or-agg.t002": "unmet", + "sf.functions.bitmap-or-agg.t003": "unmet", + "sf.functions.bitmap-or.t001": "unmet", + "sf.functions.bitmap-or.t002": "unmet", + "sf.functions.bitmap-or.t003": "unmet", + "sf.functions.bitmap-to-array.t001": "unmet", + "sf.functions.bitmap-to-array.t002": "unmet", + "sf.functions.bitmap-to-array.t003": "unmet", + "sf.functions.bitmap-to-array.t004": "unmet", + "sf.functions.bitnot.t001": "unmet", + "sf.functions.bitnot.t002": "unmet", + "sf.functions.bitnot.t003": "unmet", + "sf.functions.bitor-agg.bitor-agg-over.t001": "unmet", + "sf.functions.bitor-agg.bitor-agg-over.t002": "unmet", + "sf.functions.bitor-agg.bitor-agg-over.t003": "unmet", + "sf.functions.bitor-agg.bitor-agg-over.t004": "unmet", + "sf.functions.bitor-agg.bitor-agg.t001": "unmet", + "sf.functions.bitor-agg.bitor-agg.t002": "unmet", + "sf.functions.bitor-agg.bitor-agg.t003": "unmet", + "sf.functions.bitor-agg.bitor-agg.t004": "unmet", + "sf.functions.bitor-agg.bitor-agg.t005": "unmet", + "sf.functions.bitor-agg.bitor-agg.t006": "unmet", + "sf.functions.bitor-agg.bitor-agg.t007": "unmet", + "sf.functions.bitor.t001": "met", + "sf.functions.bitor.t002": "unmet", + "sf.functions.bitor.t003": "unmet", + "sf.functions.bitor.t004": "unmet", + "sf.functions.bitor.t005": "unmet", + "sf.functions.bitor.t006": "met", + "sf.functions.bitshiftleft.t001": "unmet", + "sf.functions.bitshiftleft.t002": "unmet", + "sf.functions.bitshiftleft.t003": "unmet", + "sf.functions.bitshiftright.t001": "unmet", + "sf.functions.bitshiftright.t002": "unmet", + "sf.functions.bitshiftright.t003": "unmet", + "sf.functions.bitxor-agg.bitxor-agg-over.t001": "unmet", + "sf.functions.bitxor-agg.bitxor-agg-over.t002": "unmet", + "sf.functions.bitxor-agg.bitxor-agg-over.t003": "unmet", + "sf.functions.bitxor-agg.bitxor-agg-over.t004": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t001": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t002": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t003": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t004": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t005": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t006": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t007": "unmet", + "sf.functions.bitxor-agg.bitxor-agg.t008": "unmet", + "sf.functions.bitxor.t001": "met", + "sf.functions.bitxor.t002": "unmet", + "sf.functions.bitxor.t003": "unmet", + "sf.functions.bitxor.t004": "unmet", + "sf.functions.bitxor.t005": "unmet", + "sf.functions.bitxor.t006": "met", + "sf.functions.booland-agg.booland-agg-over.t001": "met", + "sf.functions.booland-agg.booland-agg-over.t002": "met", + "sf.functions.booland-agg.booland-agg-over.t003": "met", + "sf.functions.booland-agg.booland-agg-over.t004": "met", + "sf.functions.booland-agg.booland-agg.t001": "met", + "sf.functions.booland-agg.booland-agg.t002": "unmet", + "sf.functions.booland-agg.booland-agg.t003": "unmet", + "sf.functions.booland-agg.booland-agg.t004": "met", + "sf.functions.booland-agg.booland-agg.t005": "met", + "sf.functions.booland-agg.booland-agg.t006": "unmet", + "sf.functions.booland.t001": "unmet", + "sf.functions.booland.t002": "unmet", + "sf.functions.booland.t003": "unmet", + "sf.functions.booland.t004": "unmet", + "sf.functions.booland.t005": "unmet", + "sf.functions.boolnot.t001": "unmet", + "sf.functions.boolnot.t002": "unmet", + "sf.functions.boolnot.t003": "unmet", + "sf.functions.boolor-agg.boolor-agg-over.t001": "met", + "sf.functions.boolor-agg.boolor-agg-over.t002": "met", + "sf.functions.boolor-agg.boolor-agg-over.t003": "met", + "sf.functions.boolor-agg.boolor-agg-over.t004": "met", + "sf.functions.boolor-agg.boolor-agg.t001": "met", + "sf.functions.boolor-agg.boolor-agg.t002": "unmet", + "sf.functions.boolor-agg.boolor-agg.t003": "unmet", + "sf.functions.boolor-agg.boolor-agg.t004": "met", + "sf.functions.boolor-agg.boolor-agg.t005": "met", + "sf.functions.boolor-agg.boolor-agg.t006": "unmet", + "sf.functions.boolor.t001": "unmet", + "sf.functions.boolor.t002": "unmet", + "sf.functions.boolor.t003": "unmet", + "sf.functions.boolor.t004": "unmet", + "sf.functions.boolor.t005": "unmet", + "sf.functions.boolxor-agg.boolxor-agg-over.t001": "unmet", + "sf.functions.boolxor-agg.boolxor-agg-over.t002": "unmet", + "sf.functions.boolxor-agg.boolxor-agg-over.t003": "unmet", + "sf.functions.boolxor-agg.boolxor-agg-over.t004": "unmet", + "sf.functions.boolxor-agg.boolxor-agg.t001": "unmet", + "sf.functions.boolxor-agg.boolxor-agg.t002": "unmet", + "sf.functions.boolxor-agg.boolxor-agg.t003": "unmet", + "sf.functions.boolxor-agg.boolxor-agg.t004": "unmet", + "sf.functions.boolxor-agg.boolxor-agg.t005": "unmet", + "sf.functions.boolxor-agg.boolxor-agg.t006": "unmet", + "sf.functions.boolxor.t001": "unmet", + "sf.functions.boolxor.t002": "unmet", + "sf.functions.boolxor.t003": "unmet", + "sf.functions.boolxor.t004": "unmet", + "sf.functions.boolxor.t005": "unmet", + "sf.functions.case.end.syntax.t001": "met", + "sf.functions.case.end.syntax.t002": "unmet", + "sf.functions.case.end.syntax.t003": "met", + "sf.functions.case.end.t001": "met", + "sf.functions.case.end.t002": "met", + "sf.functions.case.end.t003": "met", + "sf.functions.case.end.t004": "met", + "sf.functions.case.end.t005": "met", + "sf.functions.case.end.t006": "met", + "sf.functions.cast.cast-as.t001": "met", + "sf.functions.cast.cast-as.t002": "met", + "sf.functions.cast.cast-as.t003": "met", + "sf.functions.cast.cast-as.t004": "met", + "sf.functions.cast.cast-as.t005": "met", + "sf.functions.cast.double-colon.t001": "met", + "sf.functions.cast.double-colon.t002": "met", + "sf.functions.cast.double-colon.t003": "met", + "sf.functions.cast.double-colon.t004": "met", + "sf.functions.cast.double-colon.t005": "met", + "sf.functions.cbrt.t001": "unmet", + "sf.functions.cbrt.t002": "unmet", + "sf.functions.cbrt.t003": "unmet", + "sf.functions.cbrt.t004": "unmet", + "sf.functions.cbrt.t005": "unmet", + "sf.functions.ceil.t001": "unmet", + "sf.functions.ceil.t002": "unmet", + "sf.functions.ceil.t003": "unmet", + "sf.functions.ceil.t004": "unmet", + "sf.functions.ceil.t005": "unmet", + "sf.functions.ceil.t006": "unmet", + "sf.functions.ceil.t007": "unmet", + "sf.functions.ceil.t008": "unmet", + "sf.functions.charindex.t001": "met", + "sf.functions.charindex.t002": "unmet", + "sf.functions.charindex.t003": "unmet", + "sf.functions.charindex.t004": "met", + "sf.functions.charindex.t005": "met", + "sf.functions.charindex.t006": "met", + "sf.functions.charindex.t007": "unmet", + "sf.functions.charindex.t008": "unmet", + "sf.functions.charindex.t009": "unmet", + "sf.functions.check-json.t001": "unmet", + "sf.functions.check-json.t002": "unmet", + "sf.functions.check-json.t003": "unmet", + "sf.functions.check-json.t004": "unmet", + "sf.functions.check-xml.check-xml-str.t001": "unmet", + "sf.functions.check-xml.check-xml-str.t002": "unmet", + "sf.functions.check-xml.check-xml-str.t003": "unmet", + "sf.functions.check-xml.check-xml.t001": "unmet", + "sf.functions.check-xml.check-xml.t002": "unmet", + "sf.functions.check-xml.check-xml.t003": "unmet", + "sf.functions.chr.t001": "met", + "sf.functions.chr.t002": "met", + "sf.functions.chr.t003": "met", + "sf.functions.coalesce.t001": "met", + "sf.functions.coalesce.t002": "met", + "sf.functions.coalesce.t003": "met", + "sf.functions.coalesce.t004": "met", + "sf.functions.coalesce.t005": "met", + "sf.functions.collate.collate.syntax.t001": "unmet", + "sf.functions.collate.collate.syntax.t002": "unmet", + "sf.functions.collate.collate.syntax.t003": "unmet", + "sf.functions.collate.collate.syntax.t004": "unmet", + "sf.functions.collate.collate.syntax.t005": "unmet", + "sf.functions.collate.collate.t001": "unmet", + "sf.functions.collate.collate.t002": "unmet", + "sf.functions.collate.collate.t003": "unmet", + "sf.functions.collate.collate.t004": "unmet", + "sf.functions.collate.collate.t005": "unmet", + "sf.functions.collation.t001": "unmet", + "sf.functions.collation.t002": "unmet", + "sf.functions.compress.t001": "unmet", + "sf.functions.compress.t002": "unmet", + "sf.functions.compress.t003": "unmet", + "sf.functions.compress.t004": "unmet", + "sf.functions.compress.t005": "unmet", + "sf.functions.compress.t006": "unmet", + "sf.functions.compress.t007": "unmet", + "sf.functions.concat-ws.t001": "met", + "sf.functions.concat-ws.t002": "met", + "sf.functions.concat-ws.t003": "unmet", + "sf.functions.concat-ws.t004": "met", + "sf.functions.concat-ws.t005": "met", + "sf.functions.concat-ws.t006": "met", + "sf.functions.concat.concat-subscript-dot.t001": "met", + "sf.functions.concat.concat-subscript-dot.t002": "unmet", + "sf.functions.concat.concat-subscript-dot.t003": "met", + "sf.functions.concat.concat-subscript-dot.t004": "met", + "sf.functions.concat.concat.t001": "met", + "sf.functions.concat.concat.t002": "unmet", + "sf.functions.concat.concat.t003": "met", + "sf.functions.concat.concat.t004": "met", + "sf.functions.concat.concat.t005": "met", + "sf.functions.conditional-change-event.t001": "unmet", + "sf.functions.conditional-change-event.t002": "unmet", + "sf.functions.conditional-true-event.t001": "unmet", + "sf.functions.conditional-true-event.t002": "unmet", + "sf.functions.conditional-true-event.t003": "unmet", + "sf.functions.contains.t001": "met", + "sf.functions.contains.t002": "met", + "sf.functions.contains.t003": "met", + "sf.functions.contains.t004": "met", + "sf.functions.convert-timezone.t001": "met", + "sf.functions.convert-timezone.t002": "unmet", + "sf.functions.convert-timezone.t003": "met", + "sf.functions.convert-timezone.t004": "met", + "sf.functions.convert-timezone.t005": "met", + "sf.functions.convert-timezone.t006": "met", + "sf.functions.convert-timezone.t007": "met", + "sf.functions.convert-timezone.t008": "unmet", + "sf.functions.convert-timezone.t009": "met", + "sf.functions.corr.corr.t001": "unmet", + "sf.functions.corr.corr.t002": "unmet", + "sf.functions.corr.corr.t003": "unmet", + "sf.functions.corr.corr.t004": "unmet", + "sf.functions.corr.corr.t005": "unmet", + "sf.functions.corr.corr.t006": "unmet", + "sf.functions.corr.x-over.t001": "unmet", + "sf.functions.corr.x-over.t002": "unmet", + "sf.functions.corr.x-over.t003": "unmet", + "sf.functions.corr.x-over.t004": "unmet", + "sf.functions.cos.t001": "unmet", + "sf.functions.cos.t002": "unmet", + "sf.functions.cos.t003": "unmet", + "sf.functions.cos.t004": "unmet", + "sf.functions.cosh.t001": "unmet", + "sf.functions.cosh.t002": "unmet", + "sf.functions.cosh.t003": "unmet", + "sf.functions.cosh.t004": "unmet", + "sf.functions.cot.t001": "unmet", + "sf.functions.cot.t002": "unmet", + "sf.functions.cot.t003": "unmet", + "sf.functions.cot.t004": "unmet", + "sf.functions.cot.t005": "unmet", + "sf.functions.count-if.count-if-over.t001": "met", + "sf.functions.count-if.count-if-over.t002": "met", + "sf.functions.count-if.count-if-over.t003": "met", + "sf.functions.count-if.count-if-over.t004": "met", + "sf.functions.count-if.count-if-over.t005": "unmet", + "sf.functions.count-if.count-if-over.t006": "met", + "sf.functions.count-if.count-if-over.t007": "met", + "sf.functions.count-if.count-if.t001": "met", + "sf.functions.count-if.count-if.t002": "met", + "sf.functions.count-if.count-if.t003": "met", + "sf.functions.count-if.count-if.t004": "met", + "sf.functions.count.count-over.t001": "met", + "sf.functions.count.count-over.t002": "met", + "sf.functions.count.count-over.t003": "met", + "sf.functions.count.count-over.t004": "met", + "sf.functions.count.count-over.t005": "met", + "sf.functions.count.count-over.t006": "met", + "sf.functions.count.count-over.t007": "met", + "sf.functions.count.count-over.t008": "met", + "sf.functions.count.count-over.t009": "met", + "sf.functions.count.count.t001": "met", + "sf.functions.count.count.t002": "unmet", + "sf.functions.count.count.t003": "met", + "sf.functions.count.count.t004": "held", + "sf.functions.count.count.t005": "held", + "sf.functions.count.count.t006": "held", + "sf.functions.count.count.t007": "met", + "sf.functions.count.count.t008": "met", + "sf.functions.covar-pop.covar-pop.t001": "unmet", + "sf.functions.covar-pop.covar-pop.t002": "unmet", + "sf.functions.covar-pop.covar-pop.t003": "unmet", + "sf.functions.covar-pop.covar-pop.t004": "unmet", + "sf.functions.covar-pop.covar-pop.t005": "unmet", + "sf.functions.covar-pop.x-over.t001": "unmet", + "sf.functions.covar-pop.x-over.t002": "unmet", + "sf.functions.covar-pop.x-over.t003": "unmet", + "sf.functions.covar-pop.x-over.t004": "unmet", + "sf.functions.covar-samp.covar-samp.t001": "unmet", + "sf.functions.covar-samp.covar-samp.t002": "unmet", + "sf.functions.covar-samp.covar-samp.t003": "unmet", + "sf.functions.covar-samp.covar-samp.t004": "unmet", + "sf.functions.covar-samp.covar-samp.t005": "unmet", + "sf.functions.covar-samp.x-over.t001": "unmet", + "sf.functions.covar-samp.x-over.t002": "unmet", + "sf.functions.covar-samp.x-over.t003": "unmet", + "sf.functions.covar-samp.x-over.t004": "unmet", + "sf.functions.cume-dist.t001": "unmet", + "sf.functions.cume-dist.t002": "unmet", + "sf.functions.cume-dist.t003": "unmet", + "sf.functions.current-database.t001": "unmet", + "sf.functions.current-database.t002": "unmet", + "sf.functions.current-date.current-date.syntax.t001": "unmet", + "sf.functions.current-date.current-date.syntax.t002": "met", + "sf.functions.current-date.current-date.t001": "unmet", + "sf.functions.current-date.current-date.t002": "met", + "sf.functions.current-schema.t001": "unmet", + "sf.functions.current-schema.t002": "unmet", + "sf.functions.current-schemas.t001": "unmet", + "sf.functions.current-schemas.t002": "unmet", + "sf.functions.current-time.current-time.syntax.t001": "unmet", + "sf.functions.current-time.current-time.syntax.t002": "unmet", + "sf.functions.current-time.current-time.t001": "unmet", + "sf.functions.current-time.current-time.t002": "unmet", + "sf.functions.current-time.current-time.t003": "unmet", + "sf.functions.current-time.current-time.t004": "unmet", + "sf.functions.current-timestamp.current-timestamp.syntax.t001": "unmet", + "sf.functions.current-timestamp.current-timestamp.syntax.t002": "unmet", + "sf.functions.current-timestamp.current-timestamp.t001": "unmet", + "sf.functions.current-timestamp.current-timestamp.t002": "unmet", + "sf.functions.current-timestamp.current-timestamp.t003": "unmet", + "sf.functions.datasketches-hll-accumulate.t001": "unmet", + "sf.functions.datasketches-hll-accumulate.t002": "unmet", + "sf.functions.datasketches-hll-accumulate.t003": "unmet", + "sf.functions.datasketches-hll-accumulate.t004": "unmet", + "sf.functions.datasketches-hll-accumulate.t005": "unmet", + "sf.functions.datasketches-hll-combine.t001": "unmet", + "sf.functions.datasketches-hll-combine.t002": "unmet", + "sf.functions.datasketches-hll-combine.t003": "unmet", + "sf.functions.datasketches-hll-combine.t004": "unmet", + "sf.functions.datasketches-hll-estimate.t001": "unmet", + "sf.functions.datasketches-hll-estimate.t002": "unmet", + "sf.functions.datasketches-hll.datasketches-hll-over.t001": "unmet", + "sf.functions.datasketches-hll.datasketches-hll-over.t002": "unmet", + "sf.functions.datasketches-hll.datasketches-hll-over.t003": "unmet", + "sf.functions.datasketches-hll.datasketches-hll-over.t004": "unmet", + "sf.functions.datasketches-hll.datasketches-hll.t001": "unmet", + "sf.functions.datasketches-hll.datasketches-hll.t002": "unmet", + "sf.functions.datasketches-hll.datasketches-hll.t003": "unmet", + "sf.functions.datasketches-hll.datasketches-hll.t004": "unmet", + "sf.functions.datasketches-hll.datasketches-hll.t005": "unmet", + "sf.functions.datasketches-hll.datasketches-hll.t006": "unmet", + "sf.functions.datasketches-hll.datasketches-hll.t007": "unmet", + "sf.functions.date-from-parts.t001": "met", + "sf.functions.date-from-parts.t002": "met", + "sf.functions.date-from-parts.t003": "met", + "sf.functions.date-from-parts.t004": "met", + "sf.functions.date-from-parts.t005": "met", + "sf.functions.date-from-parts.t006": "met", + "sf.functions.date-from-parts.t007": "met", + "sf.functions.date-part.date-part.t001": "met", + "sf.functions.date-part.date-part.t002": "met", + "sf.functions.date-part.date-part.t003": "unmet", + "sf.functions.date-part.date-part.t004": "met", + "sf.functions.date-part.date-part.t005": "met", + "sf.functions.date-part.date-part.t006": "met", + "sf.functions.date-part.date-part.t007": "met", + "sf.functions.date-part.date-part.t008": "met", + "sf.functions.date-trunc.t001": "met", + "sf.functions.date-trunc.t002": "unmet", + "sf.functions.date-trunc.t003": "unmet", + "sf.functions.date-trunc.t004": "unmet", + "sf.functions.date-trunc.t005": "met", + "sf.functions.date-trunc.t006": "unmet", + "sf.functions.date-trunc.t007": "unmet", + "sf.functions.dateadd.t001": "met", + "sf.functions.dateadd.t002": "unmet", + "sf.functions.dateadd.t003": "met", + "sf.functions.dateadd.t004": "met", + "sf.functions.dateadd.t005": "unmet", + "sf.functions.dateadd.t006": "met", + "sf.functions.dateadd.t007": "met", + "sf.functions.dateadd.t008": "met", + "sf.functions.dateadd.t009": "met", + "sf.functions.dateadd.t010": "unmet", + "sf.functions.dateadd.t011": "unmet", + "sf.functions.datediff.datediff.t001": "met", + "sf.functions.datediff.datediff.t002": "met", + "sf.functions.datediff.datediff.t003": "met", + "sf.functions.datediff.datediff.t004": "unmet", + "sf.functions.datediff.datediff.t005": "met", + "sf.functions.datediff.datediff.t006": "met", + "sf.functions.datediff.datediff.t007": "met", + "sf.functions.datediff.datediff.t008": "unmet", + "sf.functions.datediff.datediff.t009": "met", + "sf.functions.datediff.syntax.t001": "unmet", + "sf.functions.datediff.syntax.t002": "unmet", + "sf.functions.datediff.syntax.t003": "unmet", + "sf.functions.datediff.syntax.t004": "unmet", + "sf.functions.dayname.t001": "met", + "sf.functions.dayname.t002": "unmet", + "sf.functions.dayname.t003": "met", + "sf.functions.decode.t001": "met", + "sf.functions.decode.t002": "met", + "sf.functions.decode.t003": "met", + "sf.functions.decode.t004": "met", + "sf.functions.decompress-binary.t001": "unmet", + "sf.functions.decompress-binary.t002": "unmet", + "sf.functions.decompress-binary.t003": "unmet", + "sf.functions.decompress-binary.t004": "unmet", + "sf.functions.decompress-binary.t005": "unmet", + "sf.functions.decompress-binary.t006": "unmet", + "sf.functions.decompress-binary.t007": "unmet", + "sf.functions.decompress-string.t001": "unmet", + "sf.functions.decompress-string.t002": "unmet", + "sf.functions.decompress-string.t003": "unmet", + "sf.functions.decompress-string.t004": "unmet", + "sf.functions.decompress-string.t005": "unmet", + "sf.functions.decompress-string.t006": "unmet", + "sf.functions.decompress-string.t007": "unmet", + "sf.functions.decrypt-raw.t001": "unmet", + "sf.functions.decrypt-raw.t002": "unmet", + "sf.functions.decrypt-raw.t003": "unmet", + "sf.functions.decrypt.t001": "unmet", + "sf.functions.decrypt.t002": "unmet", + "sf.functions.decrypt.t003": "unmet", + "sf.functions.decrypt.t004": "unmet", + "sf.functions.degrees.t001": "unmet", + "sf.functions.degrees.t002": "unmet", + "sf.functions.degrees.t003": "unmet", + "sf.functions.degrees.t004": "unmet", + "sf.functions.degrees.t005": "unmet", + "sf.functions.dense-rank.t001": "met", + "sf.functions.dense-rank.t002": "met", + "sf.functions.dense-rank.t003": "met", + "sf.functions.div0.t001": "met", + "sf.functions.div0.t002": "met", + "sf.functions.div0.t003": "met", + "sf.functions.div0.t004": "met", + "sf.functions.div0.t005": "met", + "sf.functions.div0.t006": "met", + "sf.functions.div0null.t001": "met", + "sf.functions.div0null.t002": "met", + "sf.functions.div0null.t003": "met", + "sf.functions.div0null.t004": "met", + "sf.functions.div0null.t005": "met", + "sf.functions.div0null.t006": "met", + "sf.functions.editdistance.t001": "met", + "sf.functions.editdistance.t002": "unmet", + "sf.functions.editdistance.t003": "met", + "sf.functions.editdistance.t004": "met", + "sf.functions.editdistance.t005": "unmet", + "sf.functions.editdistance.t006": "unmet", + "sf.functions.editdistance.t007": "met", + "sf.functions.encrypt-raw.t001": "unmet", + "sf.functions.encrypt-raw.t002": "unmet", + "sf.functions.encrypt-raw.t003": "unmet", + "sf.functions.encrypt-raw.t004": "unmet", + "sf.functions.encrypt.t001": "unmet", + "sf.functions.encrypt.t002": "unmet", + "sf.functions.encrypt.t003": "unmet", + "sf.functions.encrypt.t004": "unmet", + "sf.functions.endswith.t001": "met", + "sf.functions.endswith.t002": "met", + "sf.functions.endswith.t003": "met", + "sf.functions.endswith.t004": "met", + "sf.functions.equal-null.t001": "met", + "sf.functions.equal-null.t002": "met", + "sf.functions.equal-null.t003": "met", + "sf.functions.equal-null.t004": "met", + "sf.functions.exp.t001": "met", + "sf.functions.exp.t002": "met", + "sf.functions.exp.t003": "unmet", + "sf.functions.exp.t004": "met", + "sf.functions.exp.t005": "unmet", + "sf.functions.extract.extract-from.t001": "met", + "sf.functions.extract.extract-from.t002": "met", + "sf.functions.extract.extract-from.t003": "unmet", + "sf.functions.extract.extract-from.t004": "met", + "sf.functions.extract.extract-from.t005": "held", + "sf.functions.extract.extract-from.t006": "met", + "sf.functions.extract.extract-from.t007": "met", + "sf.functions.extract.extract-from.t008": "met", + "sf.functions.extract.extract.t001": "unmet", + "sf.functions.extract.extract.t002": "unmet", + "sf.functions.extract.extract.t003": "unmet", + "sf.functions.extract.extract.t004": "unmet", + "sf.functions.extract.extract.t005": "unmet", + "sf.functions.extract.extract.t006": "unmet", + "sf.functions.extract.extract.t007": "unmet", + "sf.functions.extract.extract.t008": "unmet", + "sf.functions.factorial.t001": "unmet", + "sf.functions.factorial.t002": "unmet", + "sf.functions.factorial.t003": "unmet", + "sf.functions.factorial.t004": "unmet", + "sf.functions.factorial.t005": "unmet", + "sf.functions.factorial.t006": "unmet", + "sf.functions.filter.t001": "unmet", + "sf.functions.filter.t002": "unmet", + "sf.functions.filter.t003": "unmet", + "sf.functions.first-value.t001": "met", + "sf.functions.first-value.t002": "met", + "sf.functions.first-value.t003": "met", + "sf.functions.first-value.t004": "met", + "sf.functions.flatten.t001": "met", + "sf.functions.flatten.t002": "met", + "sf.functions.flatten.t003": "met", + "sf.functions.flatten.t004": "met", + "sf.functions.flatten.t005": "met", + "sf.functions.flatten.t006": "met", + "sf.functions.flatten.t007": "met", + "sf.functions.flatten.t008": "met", + "sf.functions.flatten.t009": "met", + "sf.functions.floor.t001": "unmet", + "sf.functions.floor.t002": "unmet", + "sf.functions.floor.t003": "unmet", + "sf.functions.floor.t004": "unmet", + "sf.functions.floor.t005": "unmet", + "sf.functions.floor.t006": "unmet", + "sf.functions.floor.t007": "unmet", + "sf.functions.floor.t008": "unmet", + "sf.functions.format-string-template.t001": "unmet", + "sf.functions.format-string-template.t002": "unmet", + "sf.functions.format-string-template.t003": "unmet", + "sf.functions.format-string-template.t004": "unmet", + "sf.functions.format-string-template.t005": "unmet", + "sf.functions.format-string-template.t006": "unmet", + "sf.functions.generator.generator-rowcount.t001": "unmet", + "sf.functions.generator.generator-rowcount.t002": "unmet", + "sf.functions.generator.generator-rowcount.t003": "unmet", + "sf.functions.generator.generator.t001": "unmet", + "sf.functions.generator.generator.t002": "unmet", + "sf.functions.generator.generator.t003": "unmet", + "sf.functions.get-ignore-case.t001": "unmet", + "sf.functions.get-ignore-case.t002": "unmet", + "sf.functions.get-ignore-case.t003": "unmet", + "sf.functions.get-ignore-case.t004": "unmet", + "sf.functions.get-path.colon.syntax.t001": "held", + "sf.functions.get-path.colon.t001": "met", + "sf.functions.get-path.colon.t002": "met", + "sf.functions.get-path.colon.t003": "met", + "sf.functions.get-path.get-path.t001": "unmet", + "sf.functions.get-path.get-path.t002": "unmet", + "sf.functions.get-path.get-path.t003": "unmet", + "sf.functions.get.t001": "met", + "sf.functions.get.t002": "met", + "sf.functions.get.t003": "met", + "sf.functions.get.t004": "met", + "sf.functions.get.t005": "unmet", + "sf.functions.get.t006": "met", + "sf.functions.getbit.t001": "unmet", + "sf.functions.getbit.t002": "unmet", + "sf.functions.getbit.t003": "unmet", + "sf.functions.getdate.t001": "unmet", + "sf.functions.getdate.t002": "unmet", + "sf.functions.getdate.t003": "unmet", + "sf.functions.getvariable.t001": "unmet", + "sf.functions.getvariable.t002": "unmet", + "sf.functions.greatest-ignore-nulls.t001": "unmet", + "sf.functions.greatest-ignore-nulls.t002": "unmet", + "sf.functions.greatest-ignore-nulls.t003": "unmet", + "sf.functions.greatest-ignore-nulls.t004": "unmet", + "sf.functions.greatest-ignore-nulls.t005": "unmet", + "sf.functions.greatest.t001": "met", + "sf.functions.greatest.t002": "unmet", + "sf.functions.greatest.t003": "met", + "sf.functions.greatest.t004": "met", + "sf.functions.greatest.t005": "met", + "sf.functions.grouping-id.t001": "held", + "sf.functions.grouping-id.t002": "unmet", + "sf.functions.grouping-id.t003": "unmet", + "sf.functions.grouping-id.t004": "unmet", + "sf.functions.grouping.t001": "held", + "sf.functions.grouping.t002": "unmet", + "sf.functions.grouping.t003": "unmet", + "sf.functions.grouping.t004": "unmet", + "sf.functions.h3-cell-to-boundary.t001": "unmet", + "sf.functions.h3-cell-to-boundary.t002": "unmet", + "sf.functions.h3-cell-to-boundary.t003": "unmet", + "sf.functions.h3-cell-to-children-string.t001": "unmet", + "sf.functions.h3-cell-to-children-string.t002": "unmet", + "sf.functions.h3-cell-to-children-string.t003": "unmet", + "sf.functions.h3-cell-to-children.t001": "unmet", + "sf.functions.h3-cell-to-children.t002": "unmet", + "sf.functions.h3-cell-to-children.t003": "unmet", + "sf.functions.h3-cell-to-parent.t001": "unmet", + "sf.functions.h3-cell-to-parent.t002": "unmet", + "sf.functions.h3-cell-to-parent.t003": "unmet", + "sf.functions.h3-cell-to-parent.t004": "unmet", + "sf.functions.h3-cell-to-point.t001": "unmet", + "sf.functions.h3-cell-to-point.t002": "unmet", + "sf.functions.h3-cell-to-point.t003": "unmet", + "sf.functions.h3-compact-cells-strings.t001": "unmet", + "sf.functions.h3-compact-cells-strings.t002": "unmet", + "sf.functions.h3-compact-cells-strings.t003": "unmet", + "sf.functions.h3-compact-cells-strings.t004": "unmet", + "sf.functions.h3-compact-cells.t001": "unmet", + "sf.functions.h3-compact-cells.t002": "unmet", + "sf.functions.h3-compact-cells.t003": "unmet", + "sf.functions.h3-compact-cells.t004": "unmet", + "sf.functions.h3-coverage-strings.t001": "unmet", + "sf.functions.h3-coverage-strings.t002": "unmet", + "sf.functions.h3-coverage-strings.t003": "unmet", + "sf.functions.h3-coverage-strings.t004": "unmet", + "sf.functions.h3-coverage-strings.t005": "unmet", + "sf.functions.h3-coverage.t001": "unmet", + "sf.functions.h3-coverage.t002": "unmet", + "sf.functions.h3-coverage.t003": "unmet", + "sf.functions.h3-coverage.t004": "unmet", + "sf.functions.h3-coverage.t005": "unmet", + "sf.functions.h3-get-resolution.t001": "unmet", + "sf.functions.h3-get-resolution.t002": "unmet", + "sf.functions.h3-get-resolution.t003": "unmet", + "sf.functions.h3-grid-disk.t001": "unmet", + "sf.functions.h3-grid-disk.t002": "unmet", + "sf.functions.h3-grid-disk.t003": "unmet", + "sf.functions.h3-grid-disk.t004": "unmet", + "sf.functions.h3-grid-distance.t001": "unmet", + "sf.functions.h3-grid-distance.t002": "unmet", + "sf.functions.h3-grid-distance.t003": "unmet", + "sf.functions.h3-grid-distance.t004": "unmet", + "sf.functions.h3-grid-path.t001": "unmet", + "sf.functions.h3-grid-path.t002": "unmet", + "sf.functions.h3-grid-path.t003": "unmet", + "sf.functions.h3-int-to-string.t001": "unmet", + "sf.functions.h3-int-to-string.t002": "unmet", + "sf.functions.h3-is-pentagon.t001": "unmet", + "sf.functions.h3-is-pentagon.t002": "unmet", + "sf.functions.h3-is-pentagon.t003": "unmet", + "sf.functions.h3-is-valid-cell.t001": "unmet", + "sf.functions.h3-is-valid-cell.t002": "unmet", + "sf.functions.h3-is-valid-cell.t003": "unmet", + "sf.functions.h3-latlng-to-cell-string.t001": "unmet", + "sf.functions.h3-latlng-to-cell-string.t002": "unmet", + "sf.functions.h3-latlng-to-cell-string.t003": "unmet", + "sf.functions.h3-latlng-to-cell-string.t004": "unmet", + "sf.functions.h3-latlng-to-cell-string.t005": "unmet", + "sf.functions.h3-latlng-to-cell.t001": "unmet", + "sf.functions.h3-latlng-to-cell.t002": "unmet", + "sf.functions.h3-latlng-to-cell.t003": "unmet", + "sf.functions.h3-latlng-to-cell.t004": "unmet", + "sf.functions.h3-latlng-to-cell.t005": "unmet", + "sf.functions.h3-point-to-cell-string.t001": "unmet", + "sf.functions.h3-point-to-cell-string.t002": "unmet", + "sf.functions.h3-point-to-cell-string.t003": "unmet", + "sf.functions.h3-point-to-cell.t001": "unmet", + "sf.functions.h3-point-to-cell.t002": "unmet", + "sf.functions.h3-point-to-cell.t003": "unmet", + "sf.functions.h3-polygon-to-cells-strings.t001": "unmet", + "sf.functions.h3-polygon-to-cells-strings.t002": "unmet", + "sf.functions.h3-polygon-to-cells-strings.t003": "unmet", + "sf.functions.h3-polygon-to-cells.t001": "unmet", + "sf.functions.h3-polygon-to-cells.t002": "unmet", + "sf.functions.h3-polygon-to-cells.t003": "unmet", + "sf.functions.h3-string-to-int.t001": "unmet", + "sf.functions.h3-string-to-int.t002": "unmet", + "sf.functions.h3-try-coverage-strings.t001": "unmet", + "sf.functions.h3-try-coverage-strings.t002": "unmet", + "sf.functions.h3-try-coverage-strings.t003": "unmet", + "sf.functions.h3-try-coverage-strings.t004": "unmet", + "sf.functions.h3-try-coverage-strings.t005": "unmet", + "sf.functions.h3-try-coverage.t001": "unmet", + "sf.functions.h3-try-coverage.t002": "unmet", + "sf.functions.h3-try-coverage.t003": "unmet", + "sf.functions.h3-try-coverage.t004": "unmet", + "sf.functions.h3-try-coverage.t005": "unmet", + "sf.functions.h3-try-grid-distance.t001": "unmet", + "sf.functions.h3-try-grid-distance.t002": "unmet", + "sf.functions.h3-try-grid-distance.t003": "unmet", + "sf.functions.h3-try-grid-distance.t004": "unmet", + "sf.functions.h3-try-grid-path.t001": "unmet", + "sf.functions.h3-try-grid-path.t002": "unmet", + "sf.functions.h3-try-grid-path.t003": "unmet", + "sf.functions.h3-try-grid-path.t004": "unmet", + "sf.functions.h3-try-polygon-to-cells-strings.t001": "unmet", + "sf.functions.h3-try-polygon-to-cells-strings.t002": "unmet", + "sf.functions.h3-try-polygon-to-cells-strings.t003": "unmet", + "sf.functions.h3-try-polygon-to-cells.t001": "unmet", + "sf.functions.h3-try-polygon-to-cells.t002": "unmet", + "sf.functions.h3-try-polygon-to-cells.t003": "unmet", + "sf.functions.h3-uncompact-cells-strings.t001": "unmet", + "sf.functions.h3-uncompact-cells-strings.t002": "unmet", + "sf.functions.h3-uncompact-cells-strings.t003": "unmet", + "sf.functions.h3-uncompact-cells-strings.t004": "unmet", + "sf.functions.h3-uncompact-cells.t001": "unmet", + "sf.functions.h3-uncompact-cells.t002": "unmet", + "sf.functions.h3-uncompact-cells.t003": "unmet", + "sf.functions.h3-uncompact-cells.t004": "unmet", + "sf.functions.hash-agg.hash-agg-over.syntax.t001": "unmet", + "sf.functions.hash-agg.hash-agg-over.syntax.t002": "unmet", + "sf.functions.hash-agg.hash-agg-over.t001": "unmet", + "sf.functions.hash-agg.hash-agg-over.t002": "unmet", + "sf.functions.hash-agg.hash-agg-over.t003": "unmet", + "sf.functions.hash-agg.hash-agg.t001": "unmet", + "sf.functions.hash-agg.hash-agg.t002": "unmet", + "sf.functions.hash-agg.hash-agg.t003": "unmet", + "sf.functions.hash-agg.hash-agg.t004": "unmet", + "sf.functions.hash-agg.hash-agg.t005": "unmet", + "sf.functions.haversine.t001": "unmet", + "sf.functions.haversine.t002": "unmet", + "sf.functions.hex-decode-binary.t001": "unmet", + "sf.functions.hex-decode-binary.t002": "unmet", + "sf.functions.hex-decode-binary.t003": "unmet", + "sf.functions.hex-decode-binary.t004": "unmet", + "sf.functions.hex-decode-binary.t005": "unmet", + "sf.functions.hex-decode-string.t001": "met", + "sf.functions.hex-decode-string.t002": "met", + "sf.functions.hex-decode-string.t003": "met", + "sf.functions.hex-decode-string.t004": "met", + "sf.functions.hex-decode-string.t005": "met", + "sf.functions.hex-encode.t001": "met", + "sf.functions.hex-encode.t002": "unmet", + "sf.functions.hex-encode.t003": "unmet", + "sf.functions.hex-encode.t004": "met", + "sf.functions.hex-encode.t005": "unmet", + "sf.functions.hex-encode.t006": "met", + "sf.functions.hex-encode.t007": "unmet", + "sf.functions.hll-accumulate.hll-accumulate-over.syntax.t001": "unmet", + "sf.functions.hll-accumulate.hll-accumulate-over.syntax.t002": "unmet", + "sf.functions.hll-accumulate.hll-accumulate-over.t001": "unmet", + "sf.functions.hll-accumulate.hll-accumulate-over.t002": "unmet", + "sf.functions.hll-accumulate.hll-accumulate-over.t003": "unmet", + "sf.functions.hll-accumulate.hll-accumulate.t001": "unmet", + "sf.functions.hll-accumulate.hll-accumulate.t002": "unmet", + "sf.functions.hll-accumulate.hll-accumulate.t003": "unmet", + "sf.functions.hll-accumulate.hll-accumulate.t004": "unmet", + "sf.functions.hll-accumulate.hll-accumulate.t005": "unmet", + "sf.functions.hll-combine.hll-combine-over.t001": "unmet", + "sf.functions.hll-combine.hll-combine-over.t002": "unmet", + "sf.functions.hll-combine.hll-combine-over.t003": "unmet", + "sf.functions.hll-combine.hll-combine.t001": "unmet", + "sf.functions.hll-combine.hll-combine.t002": "unmet", + "sf.functions.hll-combine.hll-combine.t003": "unmet", + "sf.functions.hll-estimate.hll-estimate-over.t001": "unmet", + "sf.functions.hll-estimate.hll-estimate-over.t002": "unmet", + "sf.functions.hll-estimate.hll-estimate.t001": "unmet", + "sf.functions.hll-estimate.hll-estimate.t002": "unmet", + "sf.functions.hll-export.hll-export-over.t001": "unmet", + "sf.functions.hll-export.hll-export-over.t002": "unmet", + "sf.functions.hll-export.hll-export.t001": "unmet", + "sf.functions.hll-export.hll-export.t002": "unmet", + "sf.functions.hll-export.hll-export.t003": "unmet", + "sf.functions.hll-import.hll-import-over.t001": "unmet", + "sf.functions.hll-import.hll-import-over.t002": "unmet", + "sf.functions.hll-import.hll-import.t001": "unmet", + "sf.functions.hll-import.hll-import.t002": "unmet", + "sf.functions.hll-import.hll-import.t003": "unmet", + "sf.functions.hll.hll-over.syntax.t001": "unmet", + "sf.functions.hll.hll-over.syntax.t002": "unmet", + "sf.functions.hll.hll-over.syntax.t003": "unmet", + "sf.functions.hll.hll-over.t001": "unmet", + "sf.functions.hll.hll-over.t002": "unmet", + "sf.functions.hll.hll-over.t003": "unmet", + "sf.functions.hll.hll-over.t004": "unmet", + "sf.functions.hll.hll.t001": "unmet", + "sf.functions.hll.hll.t002": "unmet", + "sf.functions.hll.hll.t003": "unmet", + "sf.functions.hll.hll.t004": "unmet", + "sf.functions.hll.hll.t005": "unmet", + "sf.functions.hll.hll.t006": "unmet", + "sf.functions.hour-minute-second.hour.t001": "met", + "sf.functions.hour-minute-second.hour.t002": "met", + "sf.functions.hour-minute-second.hour.t003": "unmet", + "sf.functions.hour-minute-second.hour.t004": "unmet", + "sf.functions.hour-minute-second.hour.t005": "met", + "sf.functions.hour-minute-second.minute.t001": "met", + "sf.functions.hour-minute-second.minute.t002": "met", + "sf.functions.hour-minute-second.minute.t003": "unmet", + "sf.functions.hour-minute-second.minute.t004": "unmet", + "sf.functions.hour-minute-second.minute.t005": "met", + "sf.functions.hour-minute-second.second.t001": "met", + "sf.functions.hour-minute-second.second.t002": "met", + "sf.functions.hour-minute-second.second.t003": "unmet", + "sf.functions.hour-minute-second.second.t004": "unmet", + "sf.functions.hour-minute-second.second.t005": "met", + "sf.functions.iff.t001": "met", + "sf.functions.iff.t002": "met", + "sf.functions.iff.t003": "met", + "sf.functions.iff.t004": "met", + "sf.functions.iff.t005": "met", + "sf.functions.ifnull.t001": "met", + "sf.functions.ifnull.t002": "met", + "sf.functions.ifnull.t003": "met", + "sf.functions.ifnull.t004": "met", + "sf.functions.ifnull.t005": "met", + "sf.functions.ilike-any.t001": "unmet", + "sf.functions.ilike-any.t002": "unmet", + "sf.functions.ilike-any.t003": "unmet", + "sf.functions.ilike-any.t004": "unmet", + "sf.functions.ilike-any.t005": "unmet", + "sf.functions.ilike-any.t006": "unmet", + "sf.functions.ilike.ilike.syntax.t001": "unmet", + "sf.functions.ilike.ilike.syntax.t002": "unmet", + "sf.functions.ilike.ilike.syntax.t003": "unmet", + "sf.functions.ilike.ilike.syntax.t004": "unmet", + "sf.functions.ilike.ilike.syntax.t005": "unmet", + "sf.functions.ilike.ilike.syntax.t006": "unmet", + "sf.functions.ilike.ilike.syntax.t007": "unmet", + "sf.functions.ilike.ilike.syntax.t008": "unmet", + "sf.functions.ilike.ilike.syntax.t009": "unmet", + "sf.functions.ilike.ilike.t001": "unmet", + "sf.functions.ilike.ilike.t002": "unmet", + "sf.functions.ilike.ilike.t003": "unmet", + "sf.functions.ilike.ilike.t004": "unmet", + "sf.functions.ilike.ilike.t005": "unmet", + "sf.functions.ilike.ilike.t006": "unmet", + "sf.functions.ilike.ilike.t007": "unmet", + "sf.functions.ilike.ilike.t008": "unmet", + "sf.functions.ilike.ilike.t009": "unmet", + "sf.functions.in.in-2.t001": "met", + "sf.functions.in.in-2.t002": "unmet", + "sf.functions.in.in-2.t003": "met", + "sf.functions.in.in-2.t004": "unmet", + "sf.functions.in.in-2.t005": "met", + "sf.functions.in.in.syntax.t001": "unmet", + "sf.functions.in.in.syntax.t002": "unmet", + "sf.functions.in.in.syntax.t003": "unmet", + "sf.functions.in.in.t001": "met", + "sf.functions.in.in.t002": "met", + "sf.functions.in.in.t003": "met", + "sf.functions.in.in.t004": "met", + "sf.functions.in.in.t005": "met", + "sf.functions.initcap.t001": "unmet", + "sf.functions.initcap.t002": "met", + "sf.functions.initcap.t003": "met", + "sf.functions.initcap.t004": "unmet", + "sf.functions.initcap.t005": "met", + "sf.functions.insert.t001": "unmet", + "sf.functions.insert.t002": "unmet", + "sf.functions.insert.t003": "unmet", + "sf.functions.insert.t004": "unmet", + "sf.functions.insert.t005": "unmet", + "sf.functions.insert.t006": "unmet", + "sf.functions.insert.t007": "unmet", + "sf.functions.insert.t008": "unmet", + "sf.functions.interpolate-bfill.interpolate-bfill-over-order-by.t001": "unmet", + "sf.functions.interpolate-bfill.interpolate-bfill-over-order-by.t002": "unmet", + "sf.functions.interpolate-bfill.interpolate-bfill-over-order-by.t003": "unmet", + "sf.functions.interpolate-bfill.interpolate-bfill-over-order-by.t004": "unmet", + "sf.functions.interpolate-bfill.interpolate-ffill-over-order-by.t001": "unmet", + "sf.functions.interpolate-bfill.interpolate-ffill-over-order-by.t002": "unmet", + "sf.functions.interpolate-bfill.interpolate-ffill-over-order-by.t003": "unmet", + "sf.functions.interpolate-bfill.interpolate-ffill-over-order-by.t004": "unmet", + "sf.functions.interpolate-bfill.interpolate-linear-over-order-by.t001": "unmet", + "sf.functions.interpolate-bfill.interpolate-linear-over-order-by.t002": "unmet", + "sf.functions.interpolate-bfill.interpolate-linear-over-order-by.t003": "unmet", + "sf.functions.interpolate-bfill.interpolate-linear-over-order-by.t004": "unmet", + "sf.functions.ipaddress-trunc.t001": "unmet", + "sf.functions.ipaddress-trunc.t002": "unmet", + "sf.functions.ipaddress-trunc.t003": "unmet", + "sf.functions.ipaddress-trunc.t004": "unmet", + "sf.functions.is-array.t001": "unmet", + "sf.functions.is-array.t002": "unmet", + "sf.functions.is-array.t003": "met", + "sf.functions.is-binary.t001": "unmet", + "sf.functions.is-binary.t002": "unmet", + "sf.functions.is-binary.t003": "met", + "sf.functions.is-boolean.t001": "unmet", + "sf.functions.is-boolean.t002": "unmet", + "sf.functions.is-boolean.t003": "met", + "sf.functions.is-char-varchar.is-char.t001": "unmet", + "sf.functions.is-char-varchar.is-char.t002": "unmet", + "sf.functions.is-char-varchar.is-char.t003": "unmet", + "sf.functions.is-char-varchar.is-varchar.t001": "unmet", + "sf.functions.is-char-varchar.is-varchar.t002": "unmet", + "sf.functions.is-char-varchar.is-varchar.t003": "unmet", + "sf.functions.is-date-value.is-date-value.t001": "unmet", + "sf.functions.is-date-value.is-date-value.t002": "unmet", + "sf.functions.is-date-value.is-date-value.t003": "unmet", + "sf.functions.is-date-value.is-date.t001": "unmet", + "sf.functions.is-date-value.is-date.t002": "unmet", + "sf.functions.is-date-value.is-date.t003": "met", + "sf.functions.is-decimal.t001": "unmet", + "sf.functions.is-decimal.t002": "unmet", + "sf.functions.is-decimal.t003": "met", + "sf.functions.is-distinct-from.t001": "met", + "sf.functions.is-distinct-from.t002": "met", + "sf.functions.is-distinct-from.t003": "met", + "sf.functions.is-distinct-from.t004": "met", + "sf.functions.is-double-real.is-double.t001": "unmet", + "sf.functions.is-double-real.is-double.t002": "unmet", + "sf.functions.is-double-real.is-double.t003": "unmet", + "sf.functions.is-double-real.is-real.t001": "unmet", + "sf.functions.is-double-real.is-real.t002": "unmet", + "sf.functions.is-double-real.is-real.t003": "unmet", + "sf.functions.is-integer.t001": "unmet", + "sf.functions.is-integer.t002": "unmet", + "sf.functions.is-integer.t003": "met", + "sf.functions.is-null-value.t001": "met", + "sf.functions.is-null-value.t002": "met", + "sf.functions.is-null.t001": "met", + "sf.functions.is-null.t002": "met", + "sf.functions.is-object.t001": "unmet", + "sf.functions.is-object.t002": "unmet", + "sf.functions.is-object.t003": "met", + "sf.functions.is-time.t001": "unmet", + "sf.functions.is-time.t002": "unmet", + "sf.functions.is-time.t003": "met", + "sf.functions.is-timestamp.is-timestamp-ltz.t001": "unmet", + "sf.functions.is-timestamp.is-timestamp-ltz.t002": "unmet", + "sf.functions.is-timestamp.is-timestamp-ltz.t003": "met", + "sf.functions.is-timestamp.is-timestamp-ntz.t001": "unmet", + "sf.functions.is-timestamp.is-timestamp-ntz.t002": "unmet", + "sf.functions.is-timestamp.is-timestamp-ntz.t003": "met", + "sf.functions.is-timestamp.is-timestamp-tz.t001": "unmet", + "sf.functions.is-timestamp.is-timestamp-tz.t002": "unmet", + "sf.functions.is-timestamp.is-timestamp-tz.t003": "met", + "sf.functions.jarowinkler-similarity.t001": "unmet", + "sf.functions.jarowinkler-similarity.t002": "met", + "sf.functions.jarowinkler-similarity.t003": "met", + "sf.functions.jarowinkler-similarity.t004": "met", + "sf.functions.json-extract-path-text.t001": "unmet", + "sf.functions.json-extract-path-text.t002": "unmet", + "sf.functions.json-extract-path-text.t003": "unmet", + "sf.functions.json-extract-path-text.t004": "unmet", + "sf.functions.kurtosis.kurtosis-over.t001": "unmet", + "sf.functions.kurtosis.kurtosis-over.t002": "unmet", + "sf.functions.kurtosis.kurtosis-over.t003": "unmet", + "sf.functions.kurtosis.kurtosis-over.t004": "unmet", + "sf.functions.kurtosis.kurtosis-over.t005": "unmet", + "sf.functions.kurtosis.kurtosis.t001": "unmet", + "sf.functions.kurtosis.kurtosis.t002": "unmet", + "sf.functions.kurtosis.kurtosis.t003": "unmet", + "sf.functions.kurtosis.kurtosis.t004": "unmet", + "sf.functions.kurtosis.kurtosis.t005": "unmet", + "sf.functions.lag.t001": "met", + "sf.functions.lag.t002": "met", + "sf.functions.lag.t003": "unmet", + "sf.functions.lag.t004": "met", + "sf.functions.last-day.t001": "met", + "sf.functions.last-day.t002": "unmet", + "sf.functions.last-day.t003": "met", + "sf.functions.last-day.t004": "unmet", + "sf.functions.last-day.t005": "met", + "sf.functions.last-day.t006": "met", + "sf.functions.last-value.t001": "met", + "sf.functions.last-value.t002": "met", + "sf.functions.last-value.t003": "met", + "sf.functions.last-value.t004": "met", + "sf.functions.lead.t001": "met", + "sf.functions.lead.t002": "met", + "sf.functions.lead.t003": "unmet", + "sf.functions.lead.t004": "met", + "sf.functions.least-ignore-nulls.t001": "unmet", + "sf.functions.least-ignore-nulls.t002": "unmet", + "sf.functions.least-ignore-nulls.t003": "unmet", + "sf.functions.least-ignore-nulls.t004": "unmet", + "sf.functions.least-ignore-nulls.t005": "unmet", + "sf.functions.least.t001": "met", + "sf.functions.least.t002": "unmet", + "sf.functions.least.t003": "met", + "sf.functions.least.t004": "met", + "sf.functions.least.t005": "met", + "sf.functions.left.t001": "met", + "sf.functions.left.t002": "unmet", + "sf.functions.left.t003": "met", + "sf.functions.left.t004": "met", + "sf.functions.left.t005": "met", + "sf.functions.length.len.t001": "met", + "sf.functions.length.len.t002": "unmet", + "sf.functions.length.len.t003": "met", + "sf.functions.length.len.t004": "met", + "sf.functions.length.length.t001": "met", + "sf.functions.length.length.t002": "unmet", + "sf.functions.length.length.t003": "met", + "sf.functions.length.length.t004": "met", + "sf.functions.like-all.t001": "unmet", + "sf.functions.like-all.t002": "unmet", + "sf.functions.like-all.t003": "unmet", + "sf.functions.like-all.t004": "unmet", + "sf.functions.like-all.t005": "unmet", + "sf.functions.like-all.t006": "unmet", + "sf.functions.like-any.t001": "unmet", + "sf.functions.like-any.t002": "unmet", + "sf.functions.like-any.t003": "unmet", + "sf.functions.like-any.t004": "unmet", + "sf.functions.like-any.t005": "unmet", + "sf.functions.like-any.t006": "unmet", + "sf.functions.like.like.syntax.t001": "met", + "sf.functions.like.like.syntax.t002": "met", + "sf.functions.like.like.syntax.t003": "met", + "sf.functions.like.like.syntax.t004": "met", + "sf.functions.like.like.syntax.t005": "met", + "sf.functions.like.like.syntax.t006": "met", + "sf.functions.like.like.syntax.t007": "met", + "sf.functions.like.like.syntax.t008": "unmet", + "sf.functions.like.like.syntax.t009": "met", + "sf.functions.like.like.t001": "unmet", + "sf.functions.like.like.t002": "unmet", + "sf.functions.like.like.t003": "unmet", + "sf.functions.like.like.t004": "unmet", + "sf.functions.like.like.t005": "unmet", + "sf.functions.like.like.t006": "unmet", + "sf.functions.like.like.t007": "unmet", + "sf.functions.like.like.t008": "unmet", + "sf.functions.like.like.t009": "unmet", + "sf.functions.listagg.listagg-over.t001": "met", + "sf.functions.listagg.listagg-over.t002": "met", + "sf.functions.listagg.listagg-over.t003": "met", + "sf.functions.listagg.listagg-over.t004": "met", + "sf.functions.listagg.listagg-over.t005": "met", + "sf.functions.listagg.listagg.t001": "met", + "sf.functions.listagg.listagg.t002": "met", + "sf.functions.listagg.listagg.t003": "met", + "sf.functions.listagg.listagg.t004": "unmet", + "sf.functions.listagg.listagg.t005": "met", + "sf.functions.listagg.listagg.t006": "met", + "sf.functions.listagg.listagg.t007": "unmet", + "sf.functions.listagg.listagg.t008": "unmet", + "sf.functions.ln.t001": "met", + "sf.functions.ln.t002": "met", + "sf.functions.ln.t003": "unmet", + "sf.functions.ln.t004": "met", + "sf.functions.ln.t005": "met", + "sf.functions.ln.t006": "met", + "sf.functions.localtime.localtime.syntax.t001": "unmet", + "sf.functions.localtime.localtime.syntax.t002": "unmet", + "sf.functions.localtime.localtime.t001": "unmet", + "sf.functions.localtime.localtime.t002": "unmet", + "sf.functions.localtimestamp.localtimestamp.syntax.t001": "unmet", + "sf.functions.localtimestamp.localtimestamp.syntax.t002": "unmet", + "sf.functions.localtimestamp.localtimestamp.t001": "unmet", + "sf.functions.localtimestamp.localtimestamp.t002": "unmet", + "sf.functions.localtimestamp.localtimestamp.t003": "unmet", + "sf.functions.log.t001": "unmet", + "sf.functions.log.t002": "unmet", + "sf.functions.log.t003": "unmet", + "sf.functions.log.t004": "unmet", + "sf.functions.log.t005": "unmet", + "sf.functions.log.t006": "unmet", + "sf.functions.log.t007": "unmet", + "sf.functions.log.t008": "unmet", + "sf.functions.log.t009": "unmet", + "sf.functions.log.t010": "unmet", + "sf.functions.lower.t001": "met", + "sf.functions.lower.t002": "met", + "sf.functions.lower.t003": "met", + "sf.functions.lpad.t001": "met", + "sf.functions.lpad.t002": "met", + "sf.functions.lpad.t003": "met", + "sf.functions.lpad.t004": "unmet", + "sf.functions.lpad.t005": "met", + "sf.functions.lpad.t006": "met", + "sf.functions.lpad.t007": "met", + "sf.functions.lpad.t008": "met", + "sf.functions.lpad.t009": "met", + "sf.functions.ltrim.t001": "met", + "sf.functions.ltrim.t002": "met", + "sf.functions.ltrim.t003": "met", + "sf.functions.ltrim.t004": "met", + "sf.functions.ltrim.t005": "met", + "sf.functions.map-cat.t001": "unmet", + "sf.functions.map-cat.t002": "unmet", + "sf.functions.map-construct.t001": "unmet", + "sf.functions.map-construct.t002": "unmet", + "sf.functions.map-construct.t003": "unmet", + "sf.functions.map-construct.t004": "unmet", + "sf.functions.map-contains-key.t001": "unmet", + "sf.functions.map-contains-key.t002": "unmet", + "sf.functions.map-delete.t001": "unmet", + "sf.functions.map-delete.t002": "unmet", + "sf.functions.map-delete.t003": "unmet", + "sf.functions.map-entries.t001": "unmet", + "sf.functions.map-entries.t002": "unmet", + "sf.functions.map-entries.t003": "unmet", + "sf.functions.map-insert.t001": "unmet", + "sf.functions.map-insert.t002": "unmet", + "sf.functions.map-insert.t003": "unmet", + "sf.functions.map-insert.t004": "unmet", + "sf.functions.map-insert.t005": "unmet", + "sf.functions.map-keys.t001": "unmet", + "sf.functions.map-keys.t002": "unmet", + "sf.functions.map-keys.t003": "unmet", + "sf.functions.map-pick.t001": "unmet", + "sf.functions.map-pick.t002": "unmet", + "sf.functions.map-pick.t003": "unmet", + "sf.functions.map-size.t001": "unmet", + "sf.functions.map-size.t002": "unmet", + "sf.functions.max-by.t001": "met", + "sf.functions.max-by.t002": "unmet", + "sf.functions.max-by.t003": "unmet", + "sf.functions.max-by.t004": "unmet", + "sf.functions.max-by.t005": "met", + "sf.functions.max-by.t006": "unmet", + "sf.functions.max.max.syntax.t001": "met", + "sf.functions.max.max.syntax.t002": "met", + "sf.functions.max.max.syntax.t003": "met", + "sf.functions.max.max.syntax.t004": "met", + "sf.functions.max.max.syntax.t005": "met", + "sf.functions.max.max.syntax.t006": "met", + "sf.functions.max.max.syntax.t007": "met", + "sf.functions.max.max.syntax.t008": "met", + "sf.functions.max.max.t001": "met", + "sf.functions.max.max.t002": "met", + "sf.functions.max.max.t003": "met", + "sf.functions.max.max.t004": "met", + "sf.functions.max.max.t005": "met", + "sf.functions.max.max.t006": "met", + "sf.functions.md5-binary.t001": "unmet", + "sf.functions.md5-binary.t002": "unmet", + "sf.functions.md5-binary.t003": "unmet", + "sf.functions.md5-number-lower64.t001": "unmet", + "sf.functions.md5-number-lower64.t002": "unmet", + "sf.functions.md5-number-lower64.t003": "unmet", + "sf.functions.md5-number-upper64.t001": "unmet", + "sf.functions.md5-number-upper64.t002": "unmet", + "sf.functions.md5-number-upper64.t003": "unmet", + "sf.functions.md5.md5-hex.t001": "unmet", + "sf.functions.md5.md5-hex.t002": "unmet", + "sf.functions.md5.md5-hex.t003": "unmet", + "sf.functions.md5.md5.t001": "met", + "sf.functions.md5.md5.t002": "met", + "sf.functions.md5.md5.t003": "met", + "sf.functions.median.median-over.t001": "unmet", + "sf.functions.median.median-over.t002": "unmet", + "sf.functions.median.median-over.t003": "unmet", + "sf.functions.median.median-over.t004": "unmet", + "sf.functions.median.median.t001": "met", + "sf.functions.median.median.t002": "met", + "sf.functions.median.median.t003": "met", + "sf.functions.median.median.t004": "met", + "sf.functions.median.median.t005": "met", + "sf.functions.median.median.t006": "unmet", + "sf.functions.min-by.t001": "met", + "sf.functions.min-by.t002": "unmet", + "sf.functions.min-by.t003": "unmet", + "sf.functions.min-by.t004": "unmet", + "sf.functions.min-by.t005": "met", + "sf.functions.min-by.t006": "unmet", + "sf.functions.min.min.syntax.t001": "met", + "sf.functions.min.min.syntax.t002": "met", + "sf.functions.min.min.syntax.t003": "met", + "sf.functions.min.min.syntax.t004": "met", + "sf.functions.min.min.syntax.t005": "met", + "sf.functions.min.min.syntax.t006": "met", + "sf.functions.min.min.syntax.t007": "met", + "sf.functions.min.min.syntax.t008": "met", + "sf.functions.min.min.t001": "met", + "sf.functions.min.min.t002": "met", + "sf.functions.min.min.t003": "met", + "sf.functions.min.min.t004": "met", + "sf.functions.min.min.t005": "met", + "sf.functions.min.min.t006": "met", + "sf.functions.minhash-combine.minhash-combine-over.t001": "unmet", + "sf.functions.minhash-combine.minhash-combine-over.t002": "unmet", + "sf.functions.minhash-combine.minhash-combine-over.t003": "unmet", + "sf.functions.minhash-combine.minhash-combine.t001": "unmet", + "sf.functions.minhash-combine.minhash-combine.t002": "unmet", + "sf.functions.minhash-combine.minhash-combine.t003": "unmet", + "sf.functions.minhash.minhash-expr-over.t001": "unmet", + "sf.functions.minhash.minhash-expr-over.t002": "unmet", + "sf.functions.minhash.minhash-expr-over.t003": "unmet", + "sf.functions.minhash.minhash-over.t001": "unmet", + "sf.functions.minhash.minhash-over.t002": "unmet", + "sf.functions.mod.t001": "met", + "sf.functions.mod.t002": "met", + "sf.functions.mod.t003": "met", + "sf.functions.mod.t004": "unmet", + "sf.functions.mod.t005": "met", + "sf.functions.mod.t006": "met", + "sf.functions.mod.t007": "met", + "sf.functions.mod.t008": "met", + "sf.functions.mod.t009": "met", + "sf.functions.mode.mode-over.t001": "unmet", + "sf.functions.mode.mode-over.t002": "unmet", + "sf.functions.mode.mode-over.t003": "unmet", + "sf.functions.mode.mode-over.t004": "unmet", + "sf.functions.mode.mode-over.t005": "unmet", + "sf.functions.mode.mode.t001": "met", + "sf.functions.mode.mode.t002": "met", + "sf.functions.mode.mode.t003": "met", + "sf.functions.mode.mode.t004": "met", + "sf.functions.mode.mode.t005": "unmet", + "sf.functions.mode.mode.t006": "unmet", + "sf.functions.monthname.t001": "unmet", + "sf.functions.monthname.t002": "unmet", + "sf.functions.monthname.t003": "unmet", + "sf.functions.months-between.t001": "unmet", + "sf.functions.months-between.t002": "unmet", + "sf.functions.months-between.t003": "unmet", + "sf.functions.months-between.t004": "unmet", + "sf.functions.months-between.t005": "unmet", + "sf.functions.months-between.t006": "unmet", + "sf.functions.months-between.t007": "unmet", + "sf.functions.next-day.t001": "unmet", + "sf.functions.next-day.t002": "unmet", + "sf.functions.next-day.t003": "unmet", + "sf.functions.next-day.t004": "unmet", + "sf.functions.next-day.t005": "unmet", + "sf.functions.next-day.t006": "unmet", + "sf.functions.next-day.t007": "unmet", + "sf.functions.normal.t001": "unmet", + "sf.functions.normal.t002": "unmet", + "sf.functions.nth-value.t001": "unmet", + "sf.functions.nth-value.t002": "unmet", + "sf.functions.nth-value.t003": "unmet", + "sf.functions.nth-value.t004": "unmet", + "sf.functions.nth-value.t005": "unmet", + "sf.functions.ntile.t001": "met", + "sf.functions.ntile.t002": "met", + "sf.functions.ntile.t003": "unmet", + "sf.functions.ntile.t004": "met", + "sf.functions.nullif.t001": "met", + "sf.functions.nullif.t002": "met", + "sf.functions.nullif.t003": "held", + "sf.functions.nullif.t004": "met", + "sf.functions.nullifzero.t001": "met", + "sf.functions.nullifzero.t002": "met", + "sf.functions.nullifzero.t003": "met", + "sf.functions.nvl.t001": "met", + "sf.functions.nvl.t002": "met", + "sf.functions.nvl.t003": "met", + "sf.functions.nvl.t004": "met", + "sf.functions.nvl.t005": "met", + "sf.functions.nvl2.t001": "unmet", + "sf.functions.nvl2.t002": "unmet", + "sf.functions.nvl2.t003": "unmet", + "sf.functions.nvl2.t004": "unmet", + "sf.functions.object-agg.object-agg-over.t001": "unmet", + "sf.functions.object-agg.object-agg-over.t002": "unmet", + "sf.functions.object-agg.object-agg-over.t003": "unmet", + "sf.functions.object-agg.object-agg-over.t004": "unmet", + "sf.functions.object-agg.object-agg.t001": "met", + "sf.functions.object-agg.object-agg.t002": "met", + "sf.functions.object-agg.object-agg.t003": "unmet", + "sf.functions.object-agg.object-agg.t004": "met", + "sf.functions.object-agg.object-agg.t005": "met", + "sf.functions.object-agg.object-agg.t006": "met", + "sf.functions.object-construct-keep-null-structured.t001": "unmet", + "sf.functions.object-construct-keep-null-structured.t002": "unmet", + "sf.functions.object-construct-keep-null-structured.t003": "unmet", + "sf.functions.object-construct-keep-null.t001": "met", + "sf.functions.object-construct-keep-null.t002": "met", + "sf.functions.object-construct-keep-null.t003": "met", + "sf.functions.object-construct.t001": "met", + "sf.functions.object-construct.t002": "met", + "sf.functions.object-construct.t003": "met", + "sf.functions.object-construct.t004": "met", + "sf.functions.object-delete.t001": "unmet", + "sf.functions.object-delete.t002": "met", + "sf.functions.object-delete.t003": "unmet", + "sf.functions.object-insert.t001": "met", + "sf.functions.object-insert.t002": "met", + "sf.functions.object-insert.t003": "unmet", + "sf.functions.object-insert.t004": "met", + "sf.functions.object-keys.t001": "met", + "sf.functions.object-keys.t002": "met", + "sf.functions.object-keys.t003": "met", + "sf.functions.object-pick.t001": "unmet", + "sf.functions.object-pick.t002": "unmet", + "sf.functions.object-pick.t003": "unmet", + "sf.functions.octet-length.t001": "unmet", + "sf.functions.octet-length.t002": "unmet", + "sf.functions.octet-length.t003": "unmet", + "sf.functions.octet-length.t004": "unmet", + "sf.functions.parse-ip.t001": "unmet", + "sf.functions.parse-ip.t002": "unmet", + "sf.functions.parse-ip.t003": "unmet", + "sf.functions.parse-ip.t004": "unmet", + "sf.functions.parse-ip.t005": "unmet", + "sf.functions.parse-ip.t006": "unmet", + "sf.functions.parse-json.t001": "unmet", + "sf.functions.parse-json.t002": "met", + "sf.functions.parse-json.t003": "met", + "sf.functions.parse-json.t004": "unmet", + "sf.functions.parse-json.t005": "unmet", + "sf.functions.parse-json.t006": "unmet", + "sf.functions.parse-json.t007": "met", + "sf.functions.parse-url.t001": "unmet", + "sf.functions.parse-url.t002": "unmet", + "sf.functions.parse-url.t003": "unmet", + "sf.functions.parse-url.t004": "unmet", + "sf.functions.parse-url.t005": "unmet", + "sf.functions.parse-xml.parse-xml-str.t001": "unmet", + "sf.functions.parse-xml.parse-xml-str.t002": "unmet", + "sf.functions.parse-xml.parse-xml-str.t003": "unmet", + "sf.functions.parse-xml.parse-xml-str.t004": "unmet", + "sf.functions.parse-xml.parse-xml.t001": "unmet", + "sf.functions.parse-xml.parse-xml.t002": "unmet", + "sf.functions.parse-xml.parse-xml.t003": "unmet", + "sf.functions.parse-xml.parse-xml.t004": "unmet", + "sf.functions.percent-rank.t001": "unmet", + "sf.functions.percent-rank.t002": "unmet", + "sf.functions.percent-rank.t003": "unmet", + "sf.functions.percentile-cont.by-over.t001": "unmet", + "sf.functions.percentile-cont.by-over.t002": "unmet", + "sf.functions.percentile-cont.by-over.t003": "unmet", + "sf.functions.percentile-cont.by-over.t004": "unmet", + "sf.functions.percentile-cont.by.t001": "unmet", + "sf.functions.percentile-cont.by.t002": "unmet", + "sf.functions.percentile-cont.by.t003": "unmet", + "sf.functions.percentile-cont.by.t004": "unmet", + "sf.functions.percentile-cont.by.t005": "unmet", + "sf.functions.percentile-cont.by.t006": "unmet", + "sf.functions.percentile-disc.by-over.t001": "met", + "sf.functions.percentile-disc.by-over.t002": "unmet", + "sf.functions.percentile-disc.by-over.t003": "met", + "sf.functions.percentile-disc.by-over.t004": "met", + "sf.functions.percentile-disc.by.t001": "met", + "sf.functions.percentile-disc.by.t002": "unmet", + "sf.functions.percentile-disc.by.t003": "met", + "sf.functions.percentile-disc.by.t004": "unmet", + "sf.functions.percentile-disc.by.t005": "met", + "sf.functions.percentile-disc.by.t006": "met", + "sf.functions.period-begin.t001": "unmet", + "sf.functions.period-begin.t002": "unmet", + "sf.functions.period-construct.t001": "unmet", + "sf.functions.period-construct.t002": "unmet", + "sf.functions.period-construct.t003": "unmet", + "sf.functions.period-construct.t004": "unmet", + "sf.functions.period-construct.t005": "unmet", + "sf.functions.period-contains.t001": "unmet", + "sf.functions.period-contains.t002": "unmet", + "sf.functions.period-contains.t003": "unmet", + "sf.functions.period-end.t001": "unmet", + "sf.functions.period-end.t002": "unmet", + "sf.functions.period-equals.t001": "unmet", + "sf.functions.period-equals.t002": "unmet", + "sf.functions.period-immediately-precedes.t001": "unmet", + "sf.functions.period-immediately-precedes.t002": "unmet", + "sf.functions.period-immediately-succeeds.t001": "unmet", + "sf.functions.period-immediately-succeeds.t002": "unmet", + "sf.functions.period-intersect.t001": "unmet", + "sf.functions.period-intersect.t002": "unmet", + "sf.functions.period-ldiff.t001": "unmet", + "sf.functions.period-ldiff.t002": "unmet", + "sf.functions.period-meets.t001": "unmet", + "sf.functions.period-meets.t002": "unmet", + "sf.functions.period-overlaps.t001": "unmet", + "sf.functions.period-overlaps.t002": "unmet", + "sf.functions.period-precedes.t001": "unmet", + "sf.functions.period-precedes.t002": "unmet", + "sf.functions.period-rdiff.t001": "unmet", + "sf.functions.period-rdiff.t002": "unmet", + "sf.functions.period-succeeds.t001": "unmet", + "sf.functions.period-succeeds.t002": "unmet", + "sf.functions.pi.t001": "unmet", + "sf.functions.position.position-in.t001": "met", + "sf.functions.position.position-in.t002": "unmet", + "sf.functions.position.position-in.t003": "met", + "sf.functions.position.position-in.t004": "met", + "sf.functions.position.position-in.t005": "met", + "sf.functions.position.position.t001": "met", + "sf.functions.position.position.t002": "unmet", + "sf.functions.position.position.t003": "unmet", + "sf.functions.position.position.t004": "met", + "sf.functions.position.position.t005": "met", + "sf.functions.position.position.t006": "met", + "sf.functions.position.position.t007": "unmet", + "sf.functions.position.position.t008": "unmet", + "sf.functions.position.position.t009": "unmet", + "sf.functions.pow.pow.t001": "unmet", + "sf.functions.pow.pow.t002": "unmet", + "sf.functions.pow.pow.t003": "unmet", + "sf.functions.pow.pow.t004": "unmet", + "sf.functions.pow.pow.t005": "unmet", + "sf.functions.pow.pow.t006": "unmet", + "sf.functions.pow.pow.t007": "unmet", + "sf.functions.pow.pow.t008": "unmet", + "sf.functions.pow.pow.t009": "unmet", + "sf.functions.pow.power.t001": "unmet", + "sf.functions.pow.power.t002": "unmet", + "sf.functions.pow.power.t003": "unmet", + "sf.functions.pow.power.t004": "unmet", + "sf.functions.pow.power.t005": "unmet", + "sf.functions.pow.power.t006": "unmet", + "sf.functions.pow.power.t007": "unmet", + "sf.functions.pow.power.t008": "unmet", + "sf.functions.pow.power.t009": "unmet", + "sf.functions.pow.power.t010": "met", + "sf.functions.pow.power.t011": "met", + "sf.functions.pow.power.t012": "met", + "sf.functions.pow.power.t013": "met", + "sf.functions.pow.power.t014": "met", + "sf.functions.previous-day.t001": "unmet", + "sf.functions.previous-day.t002": "unmet", + "sf.functions.previous-day.t003": "unmet", + "sf.functions.previous-day.t004": "unmet", + "sf.functions.previous-day.t005": "unmet", + "sf.functions.previous-day.t006": "unmet", + "sf.functions.previous-day.t007": "unmet", + "sf.functions.radians.t001": "unmet", + "sf.functions.radians.t002": "unmet", + "sf.functions.radians.t003": "unmet", + "sf.functions.radians.t004": "unmet", + "sf.functions.random.t001": "unmet", + "sf.functions.random.t002": "unmet", + "sf.functions.random.t003": "unmet", + "sf.functions.randstr.t001": "unmet", + "sf.functions.randstr.t002": "unmet", + "sf.functions.randstr.t003": "unmet", + "sf.functions.rank.t001": "met", + "sf.functions.rank.t002": "met", + "sf.functions.rank.t003": "met", + "sf.functions.rank.t004": "met", + "sf.functions.ratio-to-report.t001": "met", + "sf.functions.ratio-to-report.t002": "unmet", + "sf.functions.ratio-to-report.t003": "met", + "sf.functions.ratio-to-report.t004": "met", + "sf.functions.reduce.t001": "unmet", + "sf.functions.reduce.t002": "unmet", + "sf.functions.reduce.t003": "unmet", + "sf.functions.reduce.t004": "unmet", + "sf.functions.regexp-count.t001": "unmet", + "sf.functions.regexp-count.t002": "unmet", + "sf.functions.regexp-count.t003": "unmet", + "sf.functions.regexp-count.t004": "unmet", + "sf.functions.regexp-count.t005": "unmet", + "sf.functions.regexp-count.t006": "unmet", + "sf.functions.regexp-count.t007": "unmet", + "sf.functions.regexp-count.t008": "unmet", + "sf.functions.regexp-count.t009": "unmet", + "sf.functions.regexp-instr.t001": "unmet", + "sf.functions.regexp-instr.t002": "unmet", + "sf.functions.regexp-instr.t003": "unmet", + "sf.functions.regexp-instr.t004": "unmet", + "sf.functions.regexp-instr.t005": "unmet", + "sf.functions.regexp-instr.t006": "met", + "sf.functions.regexp-instr.t007": "unmet", + "sf.functions.regexp-instr.t008": "unmet", + "sf.functions.regexp-instr.t009": "unmet", + "sf.functions.regexp-instr.t010": "unmet", + "sf.functions.regexp-instr.t011": "unmet", + "sf.functions.regexp-instr.t012": "unmet", + "sf.functions.regexp-instr.t013": "unmet", + "sf.functions.regexp-like.t001": "met", + "sf.functions.regexp-like.t002": "met", + "sf.functions.regexp-like.t003": "met", + "sf.functions.regexp-like.t004": "met", + "sf.functions.regexp-like.t005": "met", + "sf.functions.regexp-like.t006": "met", + "sf.functions.regexp-like.t007": "unmet", + "sf.functions.regexp-like.t008": "unmet", + "sf.functions.regexp-like.t009": "unmet", + "sf.functions.regexp-replace.t001": "unmet", + "sf.functions.regexp-replace.t002": "met", + "sf.functions.regexp-replace.t003": "met", + "sf.functions.regexp-replace.t004": "unmet", + "sf.functions.regexp-replace.t005": "met", + "sf.functions.regexp-replace.t006": "met", + "sf.functions.regexp-replace.t007": "met", + "sf.functions.regexp-replace.t008": "unmet", + "sf.functions.regexp-replace.t009": "unmet", + "sf.functions.regexp-replace.t010": "unmet", + "sf.functions.regexp-replace.t011": "unmet", + "sf.functions.regexp-replace.t012": "met", + "sf.functions.regexp-substr-all.t001": "unmet", + "sf.functions.regexp-substr-all.t002": "unmet", + "sf.functions.regexp-substr-all.t003": "unmet", + "sf.functions.regexp-substr-all.t004": "met", + "sf.functions.regexp-substr-all.t005": "met", + "sf.functions.regexp-substr-all.t006": "unmet", + "sf.functions.regexp-substr-all.t007": "unmet", + "sf.functions.regexp-substr-all.t008": "unmet", + "sf.functions.regexp-substr-all.t009": "unmet", + "sf.functions.regexp-substr-all.t010": "unmet", + "sf.functions.regexp-substr-all.t011": "met", + "sf.functions.regexp-substr.t001": "met", + "sf.functions.regexp-substr.t002": "unmet", + "sf.functions.regexp-substr.t003": "unmet", + "sf.functions.regexp-substr.t004": "met", + "sf.functions.regexp-substr.t005": "met", + "sf.functions.regexp-substr.t006": "met", + "sf.functions.regexp-substr.t007": "unmet", + "sf.functions.regexp-substr.t008": "unmet", + "sf.functions.regexp-substr.t009": "unmet", + "sf.functions.regexp-substr.t010": "unmet", + "sf.functions.regexp-substr.t011": "met", + "sf.functions.regexp-substr.t012": "unmet", + "sf.functions.regexp.t001": "met", + "sf.functions.regexp.t002": "met", + "sf.functions.regexp.t003": "met", + "sf.functions.regexp.t004": "met", + "sf.functions.regexp.t005": "met", + "sf.functions.regexp.t006": "met", + "sf.functions.regexp.t007": "unmet", + "sf.functions.regexp.t008": "met", + "sf.functions.regr-avgx.regr-avgx.t001": "unmet", + "sf.functions.regr-avgx.regr-avgx.t002": "unmet", + "sf.functions.regr-avgx.regr-avgx.t003": "unmet", + "sf.functions.regr-avgx.regr-avgx.t004": "unmet", + "sf.functions.regr-avgx.regr-avgx.t005": "unmet", + "sf.functions.regr-avgx.x-over.t001": "unmet", + "sf.functions.regr-avgx.x-over.t002": "unmet", + "sf.functions.regr-avgx.x-over.t003": "unmet", + "sf.functions.regr-avgx.x-over.t004": "unmet", + "sf.functions.regr-avgy.regr-avgy.t001": "unmet", + "sf.functions.regr-avgy.regr-avgy.t002": "unmet", + "sf.functions.regr-avgy.regr-avgy.t003": "unmet", + "sf.functions.regr-avgy.regr-avgy.t004": "unmet", + "sf.functions.regr-avgy.regr-avgy.t005": "unmet", + "sf.functions.regr-avgy.x-over.t001": "unmet", + "sf.functions.regr-avgy.x-over.t002": "unmet", + "sf.functions.regr-avgy.x-over.t003": "unmet", + "sf.functions.regr-avgy.x-over.t004": "unmet", + "sf.functions.regr-count.regr-count.t001": "unmet", + "sf.functions.regr-count.regr-count.t002": "unmet", + "sf.functions.regr-count.regr-count.t003": "unmet", + "sf.functions.regr-count.regr-count.t004": "unmet", + "sf.functions.regr-count.regr-count.t005": "unmet", + "sf.functions.regr-count.x-over.t001": "unmet", + "sf.functions.regr-count.x-over.t002": "unmet", + "sf.functions.regr-count.x-over.t003": "unmet", + "sf.functions.regr-count.x-over.t004": "unmet", + "sf.functions.regr-intercept.regr-intercept.t001": "unmet", + "sf.functions.regr-intercept.regr-intercept.t002": "unmet", + "sf.functions.regr-intercept.regr-intercept.t003": "unmet", + "sf.functions.regr-intercept.regr-intercept.t004": "unmet", + "sf.functions.regr-intercept.regr-intercept.t005": "unmet", + "sf.functions.regr-intercept.regr-intercept.t006": "unmet", + "sf.functions.regr-intercept.x-over.t001": "unmet", + "sf.functions.regr-intercept.x-over.t002": "unmet", + "sf.functions.regr-intercept.x-over.t003": "unmet", + "sf.functions.regr-intercept.x-over.t004": "unmet", + "sf.functions.regr-r2.regr-r2.t001": "unmet", + "sf.functions.regr-r2.regr-r2.t002": "unmet", + "sf.functions.regr-r2.regr-r2.t003": "unmet", + "sf.functions.regr-r2.regr-r2.t004": "unmet", + "sf.functions.regr-r2.regr-r2.t005": "unmet", + "sf.functions.regr-r2.regr-r2.t006": "unmet", + "sf.functions.regr-r2.regr-r2.t007": "unmet", + "sf.functions.regr-r2.x-over.t001": "unmet", + "sf.functions.regr-r2.x-over.t002": "unmet", + "sf.functions.regr-r2.x-over.t003": "unmet", + "sf.functions.regr-r2.x-over.t004": "unmet", + "sf.functions.regr-slope.regr-slope.t001": "unmet", + "sf.functions.regr-slope.regr-slope.t002": "unmet", + "sf.functions.regr-slope.regr-slope.t003": "unmet", + "sf.functions.regr-slope.regr-slope.t004": "unmet", + "sf.functions.regr-slope.regr-slope.t005": "unmet", + "sf.functions.regr-slope.regr-slope.t006": "unmet", + "sf.functions.regr-slope.x-over.t001": "unmet", + "sf.functions.regr-slope.x-over.t002": "unmet", + "sf.functions.regr-slope.x-over.t003": "unmet", + "sf.functions.regr-slope.x-over.t004": "unmet", + "sf.functions.regr-sxx.regr-sxx.t001": "unmet", + "sf.functions.regr-sxx.regr-sxx.t002": "unmet", + "sf.functions.regr-sxx.regr-sxx.t003": "unmet", + "sf.functions.regr-sxx.regr-sxx.t004": "unmet", + "sf.functions.regr-sxx.regr-sxx.t005": "unmet", + "sf.functions.regr-sxx.x-over.t001": "unmet", + "sf.functions.regr-sxx.x-over.t002": "unmet", + "sf.functions.regr-sxx.x-over.t003": "unmet", + "sf.functions.regr-sxx.x-over.t004": "unmet", + "sf.functions.regr-sxy.regr-sxy.t001": "unmet", + "sf.functions.regr-sxy.regr-sxy.t002": "unmet", + "sf.functions.regr-sxy.regr-sxy.t003": "unmet", + "sf.functions.regr-sxy.regr-sxy.t004": "unmet", + "sf.functions.regr-sxy.regr-sxy.t005": "unmet", + "sf.functions.regr-sxy.x-over.t001": "unmet", + "sf.functions.regr-sxy.x-over.t002": "unmet", + "sf.functions.regr-sxy.x-over.t003": "unmet", + "sf.functions.regr-sxy.x-over.t004": "unmet", + "sf.functions.regr-syy.regr-syy.t001": "unmet", + "sf.functions.regr-syy.regr-syy.t002": "unmet", + "sf.functions.regr-syy.regr-syy.t003": "unmet", + "sf.functions.regr-syy.regr-syy.t004": "unmet", + "sf.functions.regr-syy.regr-syy.t005": "unmet", + "sf.functions.regr-syy.x.t001": "unmet", + "sf.functions.regr-syy.x.t002": "unmet", + "sf.functions.regr-syy.x.t003": "unmet", + "sf.functions.regr-syy.x.t004": "unmet", + "sf.functions.regr-valx.t001": "unmet", + "sf.functions.regr-valx.t002": "unmet", + "sf.functions.regr-valx.t003": "unmet", + "sf.functions.regr-valx.t004": "unmet", + "sf.functions.regr-valy.t001": "unmet", + "sf.functions.regr-valy.t002": "unmet", + "sf.functions.regr-valy.t003": "unmet", + "sf.functions.regr-valy.t004": "unmet", + "sf.functions.repeat.t001": "met", + "sf.functions.repeat.t002": "met", + "sf.functions.repeat.t003": "met", + "sf.functions.repeat.t004": "met", + "sf.functions.repeat.t005": "met", + "sf.functions.replace.t001": "met", + "sf.functions.replace.t002": "met", + "sf.functions.replace.t003": "met", + "sf.functions.replace.t004": "met", + "sf.functions.replace.t005": "met", + "sf.functions.replace.t006": "met", + "sf.functions.replace.t007": "met", + "sf.functions.reverse.t001": "unmet", + "sf.functions.reverse.t002": "unmet", + "sf.functions.reverse.t003": "unmet", + "sf.functions.reverse.t004": "unmet", + "sf.functions.right.t001": "met", + "sf.functions.right.t002": "unmet", + "sf.functions.right.t003": "met", + "sf.functions.right.t004": "met", + "sf.functions.right.t005": "met", + "sf.functions.rlike.rlike.syntax.t001": "met", + "sf.functions.rlike.rlike.syntax.t002": "met", + "sf.functions.rlike.rlike.syntax.t003": "met", + "sf.functions.rlike.rlike.syntax.t004": "met", + "sf.functions.rlike.rlike.syntax.t005": "met", + "sf.functions.rlike.rlike.syntax.t006": "met", + "sf.functions.rlike.rlike.syntax.t007": "unmet", + "sf.functions.rlike.rlike.syntax.t008": "met", + "sf.functions.rlike.rlike.t001": "unmet", + "sf.functions.rlike.rlike.t002": "unmet", + "sf.functions.rlike.rlike.t003": "unmet", + "sf.functions.rlike.rlike.t004": "unmet", + "sf.functions.rlike.rlike.t005": "unmet", + "sf.functions.rlike.rlike.t006": "unmet", + "sf.functions.rlike.rlike.t007": "unmet", + "sf.functions.rlike.rlike.t008": "unmet", + "sf.functions.rlike.rlike.t009": "unmet", + "sf.functions.round.round-expr-scale.t001": "unmet", + "sf.functions.round.round-expr-scale.t002": "unmet", + "sf.functions.round.round-expr-scale.t003": "unmet", + "sf.functions.round.round-expr-scale.t004": "unmet", + "sf.functions.round.round-expr-scale.t005": "unmet", + "sf.functions.round.round-expr-scale.t006": "unmet", + "sf.functions.round.round-expr-scale.t007": "unmet", + "sf.functions.round.round-expr-scale.t008": "unmet", + "sf.functions.round.round-expr-scale.t009": "unmet", + "sf.functions.round.round-expr-scale.t010": "unmet", + "sf.functions.round.round-expr-scale.t011": "unmet", + "sf.functions.round.round-expr-scale.t012": "unmet", + "sf.functions.round.round-expr-scale.t013": "unmet", + "sf.functions.round.round.t001": "unmet", + "sf.functions.round.round.t002": "met", + "sf.functions.round.round.t003": "met", + "sf.functions.round.round.t004": "unmet", + "sf.functions.round.round.t005": "met", + "sf.functions.round.round.t006": "met", + "sf.functions.round.round.t007": "met", + "sf.functions.round.round.t008": "unmet", + "sf.functions.round.round.t009": "unmet", + "sf.functions.round.round.t010": "met", + "sf.functions.round.round.t011": "unmet", + "sf.functions.round.round.t012": "unmet", + "sf.functions.row-number.t001": "met", + "sf.functions.row-number.t002": "met", + "sf.functions.row-number.t003": "met", + "sf.functions.rpad.t001": "met", + "sf.functions.rpad.t002": "met", + "sf.functions.rpad.t003": "met", + "sf.functions.rpad.t004": "unmet", + "sf.functions.rpad.t005": "met", + "sf.functions.rpad.t006": "met", + "sf.functions.rpad.t007": "met", + "sf.functions.rpad.t008": "met", + "sf.functions.rpad.t009": "met", + "sf.functions.rtrim.t001": "met", + "sf.functions.rtrim.t002": "met", + "sf.functions.rtrim.t003": "met", + "sf.functions.rtrim.t004": "met", + "sf.functions.rtrim.t005": "met", + "sf.functions.rtrimmed-length.t001": "unmet", + "sf.functions.rtrimmed-length.t002": "unmet", + "sf.functions.rtrimmed-length.t003": "unmet", + "sf.functions.sanitize-webhook-content.t001": "unmet", + "sf.functions.sanitize-webhook-content.t002": "unmet", + "sf.functions.search-ip.t001": "unmet", + "sf.functions.search-ip.t002": "unmet", + "sf.functions.search-ip.t003": "unmet", + "sf.functions.search-ip.t004": "unmet", + "sf.functions.search-ip.t005": "unmet", + "sf.functions.search.t001": "unmet", + "sf.functions.search.t002": "unmet", + "sf.functions.search.t003": "unmet", + "sf.functions.search.t004": "unmet", + "sf.functions.search.t005": "unmet", + "sf.functions.seq1.seq1.t001": "unmet", + "sf.functions.seq1.seq1.t002": "unmet", + "sf.functions.seq1.seq1.t003": "unmet", + "sf.functions.seq1.seq2.t001": "unmet", + "sf.functions.seq1.seq2.t002": "unmet", + "sf.functions.seq1.seq2.t003": "unmet", + "sf.functions.seq1.seq4.t001": "met", + "sf.functions.seq1.seq4.t002": "unmet", + "sf.functions.seq1.seq4.t003": "unmet", + "sf.functions.seq1.seq8.t001": "met", + "sf.functions.seq1.seq8.t002": "unmet", + "sf.functions.seq1.seq8.t003": "unmet", + "sf.functions.sha1-binary.t001": "unmet", + "sf.functions.sha1-binary.t002": "unmet", + "sf.functions.sha1-binary.t003": "unmet", + "sf.functions.sha1.sha1-hex.t001": "unmet", + "sf.functions.sha1.sha1-hex.t002": "unmet", + "sf.functions.sha1.sha1-hex.t003": "unmet", + "sf.functions.sha1.sha1.t001": "unmet", + "sf.functions.sha1.sha1.t002": "unmet", + "sf.functions.sha1.sha1.t003": "unmet", + "sf.functions.sha2-binary.t001": "unmet", + "sf.functions.sha2-binary.t002": "unmet", + "sf.functions.sha2-binary.t003": "unmet", + "sf.functions.sha2-binary.t004": "unmet", + "sf.functions.sha2-binary.t005": "unmet", + "sf.functions.sha2-binary.t006": "unmet", + "sf.functions.sha2.sha2-hex.t001": "unmet", + "sf.functions.sha2.sha2-hex.t002": "unmet", + "sf.functions.sha2.sha2-hex.t003": "unmet", + "sf.functions.sha2.sha2-hex.t004": "unmet", + "sf.functions.sha2.sha2-hex.t005": "unmet", + "sf.functions.sha2.sha2-hex.t006": "unmet", + "sf.functions.sha2.sha2.t001": "met", + "sf.functions.sha2.sha2.t002": "unmet", + "sf.functions.sha2.sha2.t003": "met", + "sf.functions.sha2.sha2.t004": "unmet", + "sf.functions.sha2.sha2.t005": "met", + "sf.functions.sha2.sha2.t006": "unmet", + "sf.functions.sign.t001": "met", + "sf.functions.sign.t002": "met", + "sf.functions.sign.t003": "met", + "sf.functions.sign.t004": "met", + "sf.functions.sign.t005": "met", + "sf.functions.sin.t001": "unmet", + "sf.functions.sin.t002": "unmet", + "sf.functions.sin.t003": "unmet", + "sf.functions.sin.t004": "unmet", + "sf.functions.sinh.t001": "unmet", + "sf.functions.sinh.t002": "unmet", + "sf.functions.sinh.t003": "unmet", + "sf.functions.sinh.t004": "unmet", + "sf.functions.skew.t001": "unmet", + "sf.functions.skew.t002": "unmet", + "sf.functions.skew.t003": "unmet", + "sf.functions.skew.t004": "unmet", + "sf.functions.skew.t005": "unmet", + "sf.functions.soundex-p123.t001": "unmet", + "sf.functions.soundex-p123.t002": "unmet", + "sf.functions.soundex.t001": "unmet", + "sf.functions.soundex.t002": "unmet", + "sf.functions.soundex.t003": "unmet", + "sf.functions.space.t001": "unmet", + "sf.functions.space.t002": "unmet", + "sf.functions.space.t003": "unmet", + "sf.functions.space.t004": "unmet", + "sf.functions.split-part.t001": "unmet", + "sf.functions.split-part.t002": "met", + "sf.functions.split-part.t003": "met", + "sf.functions.split-part.t004": "unmet", + "sf.functions.split-part.t005": "met", + "sf.functions.split-part.t006": "unmet", + "sf.functions.split-part.t007": "met", + "sf.functions.split-to-table.t001": "unmet", + "sf.functions.split-to-table.t002": "unmet", + "sf.functions.split-to-table.t003": "unmet", + "sf.functions.split-to-table.t004": "unmet", + "sf.functions.split.t001": "met", + "sf.functions.split.t002": "met", + "sf.functions.split.t003": "met", + "sf.functions.split.t004": "met", + "sf.functions.sqrt.t001": "met", + "sf.functions.sqrt.t002": "met", + "sf.functions.sqrt.t003": "unmet", + "sf.functions.sqrt.t004": "met", + "sf.functions.sqrt.t005": "met", + "sf.functions.sqrt.t006": "met", + "sf.functions.square.t001": "unmet", + "sf.functions.square.t002": "unmet", + "sf.functions.square.t003": "unmet", + "sf.functions.square.t004": "unmet", + "sf.functions.square.t005": "unmet", + "sf.functions.square.t006": "unmet", + "sf.functions.st-area.t001": "unmet", + "sf.functions.st-area.t002": "unmet", + "sf.functions.st-area.t003": "unmet", + "sf.functions.st-asewkb.t001": "unmet", + "sf.functions.st-asewkb.t002": "unmet", + "sf.functions.st-asewkt.t001": "unmet", + "sf.functions.st-asewkt.t002": "unmet", + "sf.functions.st-asewkt.t003": "unmet", + "sf.functions.st-asgeojson.t001": "unmet", + "sf.functions.st-asgeojson.t002": "unmet", + "sf.functions.st-asgeojson.t003": "unmet", + "sf.functions.st-aswkb.st-asbinary.t001": "unmet", + "sf.functions.st-aswkb.st-asbinary.t002": "unmet", + "sf.functions.st-aswkb.st-asbinary.t003": "unmet", + "sf.functions.st-aswkb.st-aswkb.t001": "unmet", + "sf.functions.st-aswkb.st-aswkb.t002": "unmet", + "sf.functions.st-aswkb.st-aswkb.t003": "unmet", + "sf.functions.st-aswkt.st-astext.t001": "unmet", + "sf.functions.st-aswkt.st-astext.t002": "unmet", + "sf.functions.st-aswkt.st-astext.t003": "unmet", + "sf.functions.st-aswkt.st-aswkt.t001": "unmet", + "sf.functions.st-aswkt.st-aswkt.t002": "unmet", + "sf.functions.st-aswkt.st-aswkt.t003": "unmet", + "sf.functions.st-azimuth.t001": "unmet", + "sf.functions.st-azimuth.t002": "unmet", + "sf.functions.st-azimuth.t003": "unmet", + "sf.functions.st-azimuth.t004": "unmet", + "sf.functions.st-buffer.t001": "unmet", + "sf.functions.st-buffer.t002": "unmet", + "sf.functions.st-buffer.t003": "unmet", + "sf.functions.st-buffer.t004": "unmet", + "sf.functions.st-centroid.t001": "unmet", + "sf.functions.st-centroid.t002": "unmet", + "sf.functions.st-centroid.t003": "unmet", + "sf.functions.st-collect.st-collect.t001": "unmet", + "sf.functions.st-collect.st-collect.t002": "unmet", + "sf.functions.st-contains.t001": "unmet", + "sf.functions.st-contains.t002": "unmet", + "sf.functions.st-contains.t003": "unmet", + "sf.functions.st-contains.t004": "unmet", + "sf.functions.st-coveredby.t001": "unmet", + "sf.functions.st-coveredby.t002": "unmet", + "sf.functions.st-coveredby.t003": "unmet", + "sf.functions.st-coveredby.t004": "unmet", + "sf.functions.st-covers.t001": "unmet", + "sf.functions.st-covers.t002": "unmet", + "sf.functions.st-covers.t003": "unmet", + "sf.functions.st-covers.t004": "unmet", + "sf.functions.st-difference.t001": "unmet", + "sf.functions.st-difference.t002": "unmet", + "sf.functions.st-difference.t003": "unmet", + "sf.functions.st-dimension.t001": "unmet", + "sf.functions.st-dimension.t002": "unmet", + "sf.functions.st-disjoint.t001": "unmet", + "sf.functions.st-disjoint.t002": "unmet", + "sf.functions.st-disjoint.t003": "unmet", + "sf.functions.st-disjoint.t004": "unmet", + "sf.functions.st-distance.t001": "unmet", + "sf.functions.st-distance.t002": "unmet", + "sf.functions.st-distance.t003": "unmet", + "sf.functions.st-distance.t004": "unmet", + "sf.functions.st-dwithin.t001": "unmet", + "sf.functions.st-dwithin.t002": "unmet", + "sf.functions.st-endpoint.t001": "unmet", + "sf.functions.st-endpoint.t002": "unmet", + "sf.functions.st-endpoint.t003": "unmet", + "sf.functions.st-envelope.t001": "unmet", + "sf.functions.st-envelope.t002": "unmet", + "sf.functions.st-envelope.t003": "unmet", + "sf.functions.st-geogfromgeohash.t001": "unmet", + "sf.functions.st-geogfromgeohash.t002": "unmet", + "sf.functions.st-geogfromgeohash.t003": "unmet", + "sf.functions.st-geogfromgeohash.t004": "unmet", + "sf.functions.st-geogfromgeohash.t005": "unmet", + "sf.functions.st-geogpointfromgeohash.t001": "unmet", + "sf.functions.st-geogpointfromgeohash.t002": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromewkb.t001": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromewkb.t002": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromewkb.t003": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromewkb.t004": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromewkb.t005": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromewkb.t006": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromwkb.t001": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromwkb.t002": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromwkb.t003": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromwkb.t004": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromwkb.t005": "unmet", + "sf.functions.st-geographyfromwkb.st-geogfromwkb.t006": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromewkb.t001": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromewkb.t002": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromewkb.t003": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromewkb.t004": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromewkb.t005": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromewkb.t006": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromwkb.t001": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromwkb.t002": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromwkb.t003": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromwkb.t004": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromwkb.t005": "unmet", + "sf.functions.st-geographyfromwkb.st-geographyfromwkb.t006": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromewkt.t001": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromewkt.t002": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromewkt.t003": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromewkt.t004": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromewkt.t005": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromewkt.t006": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromtext.t001": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromtext.t002": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromtext.t003": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromtext.t004": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromtext.t005": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromtext.t006": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromwkt.t001": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromwkt.t002": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromwkt.t003": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromwkt.t004": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromwkt.t005": "unmet", + "sf.functions.st-geographyfromwkt.st-geogfromwkt.t006": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromewkt.t001": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromewkt.t002": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromewkt.t003": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromewkt.t004": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromewkt.t005": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromewkt.t006": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromtext.t001": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromtext.t002": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromtext.t003": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromtext.t004": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromtext.t005": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromtext.t006": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromwkt.t001": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromwkt.t002": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromwkt.t003": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromwkt.t004": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromwkt.t005": "unmet", + "sf.functions.st-geographyfromwkt.st-geographyfromwkt.t006": "unmet", + "sf.functions.st-geohash.t001": "unmet", + "sf.functions.st-geohash.t002": "unmet", + "sf.functions.st-geohash.t003": "unmet", + "sf.functions.st-geohash.t004": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromewkb.t001": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromewkb.t002": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromewkb.t003": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromewkb.t004": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromewkb.t005": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromewkb.t006": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromwkb.t001": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromwkb.t002": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromwkb.t003": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromwkb.t004": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromwkb.t005": "unmet", + "sf.functions.st-geometryfromwkb.st-geometryfromwkb.t006": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromewkb.t001": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromewkb.t002": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromewkb.t003": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromewkb.t004": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromewkb.t005": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromewkb.t006": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromwkb.t001": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromwkb.t002": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromwkb.t003": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromwkb.t004": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromwkb.t005": "unmet", + "sf.functions.st-geometryfromwkb.st-geomfromwkb.t006": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromewkt.t001": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromewkt.t002": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromewkt.t003": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromewkt.t004": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromewkt.t005": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromewkt.t006": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromtext.t001": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromtext.t002": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromtext.t003": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromtext.t004": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromtext.t005": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromtext.t006": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromwkt.t001": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromwkt.t002": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromwkt.t003": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromwkt.t004": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromwkt.t005": "unmet", + "sf.functions.st-geometryfromwkt.st-geometryfromwkt.t006": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromewkt.t001": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromewkt.t002": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromewkt.t003": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromewkt.t004": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromewkt.t005": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromewkt.t006": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromtext.t001": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromtext.t002": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromtext.t003": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromtext.t004": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromtext.t005": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromtext.t006": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromwkt.t001": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromwkt.t002": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromwkt.t003": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromwkt.t004": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromwkt.t005": "unmet", + "sf.functions.st-geometryfromwkt.st-geomfromwkt.t006": "unmet", + "sf.functions.st-geomfromgeohash.t001": "unmet", + "sf.functions.st-geomfromgeohash.t002": "unmet", + "sf.functions.st-geomfromgeohash.t003": "unmet", + "sf.functions.st-geomfromgeohash.t004": "unmet", + "sf.functions.st-geompointfromgeohash.t001": "unmet", + "sf.functions.st-geompointfromgeohash.t002": "unmet", + "sf.functions.st-hausdorffdistance.t001": "unmet", + "sf.functions.st-hausdorffdistance.t002": "unmet", + "sf.functions.st-interpolate.t001": "unmet", + "sf.functions.st-interpolate.t002": "unmet", + "sf.functions.st-intersection-agg.t001": "unmet", + "sf.functions.st-intersection-agg.t002": "unmet", + "sf.functions.st-intersection.t001": "unmet", + "sf.functions.st-intersection.t002": "unmet", + "sf.functions.st-intersection.t003": "unmet", + "sf.functions.st-intersects.t001": "unmet", + "sf.functions.st-intersects.t002": "unmet", + "sf.functions.st-intersects.t003": "unmet", + "sf.functions.st-intersects.t004": "unmet", + "sf.functions.st-isvalid.t001": "unmet", + "sf.functions.st-isvalid.t002": "unmet", + "sf.functions.st-length.t001": "unmet", + "sf.functions.st-length.t002": "unmet", + "sf.functions.st-length.t003": "unmet", + "sf.functions.st-makegeompoint.t001": "unmet", + "sf.functions.st-makegeompoint.t002": "unmet", + "sf.functions.st-makeline.t001": "unmet", + "sf.functions.st-makeline.t002": "unmet", + "sf.functions.st-makeline.t003": "unmet", + "sf.functions.st-makeline.t004": "unmet", + "sf.functions.st-makepoint.t001": "unmet", + "sf.functions.st-makepoint.t002": "unmet", + "sf.functions.st-makepolygon.t001": "unmet", + "sf.functions.st-makepolygon.t002": "unmet", + "sf.functions.st-makepolygon.t003": "unmet", + "sf.functions.st-makepolygon.t004": "unmet", + "sf.functions.st-makepolygonoriented.t001": "unmet", + "sf.functions.st-makepolygonoriented.t002": "unmet", + "sf.functions.st-npoints.t001": "unmet", + "sf.functions.st-npoints.t002": "unmet", + "sf.functions.st-perimeter.t001": "unmet", + "sf.functions.st-perimeter.t002": "unmet", + "sf.functions.st-perimeter.t003": "unmet", + "sf.functions.st-pointn.t001": "unmet", + "sf.functions.st-pointn.t002": "unmet", + "sf.functions.st-pointn.t003": "unmet", + "sf.functions.st-pointn.t004": "unmet", + "sf.functions.st-setsrid.t001": "unmet", + "sf.functions.st-setsrid.t002": "unmet", + "sf.functions.st-simplify.t001": "unmet", + "sf.functions.st-simplify.t002": "unmet", + "sf.functions.st-simplify.t003": "unmet", + "sf.functions.st-simplify.t004": "unmet", + "sf.functions.st-srid.t001": "unmet", + "sf.functions.st-srid.t002": "unmet", + "sf.functions.st-startpoint.t001": "unmet", + "sf.functions.st-startpoint.t002": "unmet", + "sf.functions.st-startpoint.t003": "unmet", + "sf.functions.st-symdifference.t001": "unmet", + "sf.functions.st-symdifference.t002": "unmet", + "sf.functions.st-symdifference.t003": "unmet", + "sf.functions.st-transform.t001": "unmet", + "sf.functions.st-transform.t002": "unmet", + "sf.functions.st-transform.t003": "unmet", + "sf.functions.st-transform.t004": "unmet", + "sf.functions.st-union-agg.t001": "unmet", + "sf.functions.st-union-agg.t002": "unmet", + "sf.functions.st-union.t001": "unmet", + "sf.functions.st-union.t002": "unmet", + "sf.functions.st-within.t001": "unmet", + "sf.functions.st-within.t002": "unmet", + "sf.functions.st-within.t003": "unmet", + "sf.functions.st-x.t001": "unmet", + "sf.functions.st-x.t002": "unmet", + "sf.functions.st-x.t003": "unmet", + "sf.functions.st-xmax.t001": "unmet", + "sf.functions.st-xmax.t002": "unmet", + "sf.functions.st-xmax.t003": "unmet", + "sf.functions.st-xmin.t001": "unmet", + "sf.functions.st-xmin.t002": "unmet", + "sf.functions.st-xmin.t003": "unmet", + "sf.functions.st-y.t001": "unmet", + "sf.functions.st-y.t002": "unmet", + "sf.functions.st-y.t003": "unmet", + "sf.functions.st-ymax.t001": "unmet", + "sf.functions.st-ymax.t002": "unmet", + "sf.functions.st-ymax.t003": "unmet", + "sf.functions.st-ymin.t001": "unmet", + "sf.functions.st-ymin.t002": "unmet", + "sf.functions.st-ymin.t003": "unmet", + "sf.functions.startswith.t001": "met", + "sf.functions.startswith.t002": "met", + "sf.functions.startswith.t003": "met", + "sf.functions.startswith.t004": "met", + "sf.functions.stddev-pop.stddev-pop-over.t001": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t002": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t003": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t004": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t005": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t006": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t007": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t008": "unmet", + "sf.functions.stddev-pop.stddev-pop-over.t009": "unmet", + "sf.functions.stddev-pop.stddev-pop.t001": "unmet", + "sf.functions.stddev-pop.stddev-pop.t002": "unmet", + "sf.functions.stddev-pop.stddev-pop.t003": "unmet", + "sf.functions.stddev-pop.stddev-pop.t004": "unmet", + "sf.functions.stddev-pop.stddev-pop.t005": "unmet", + "sf.functions.stddev-pop.stddev-pop.t006": "unmet", + "sf.functions.stddev.stddev-over.t001": "unmet", + "sf.functions.stddev.stddev-over.t002": "unmet", + "sf.functions.stddev.stddev-over.t003": "unmet", + "sf.functions.stddev.stddev-over.t004": "unmet", + "sf.functions.stddev.stddev-over.t005": "unmet", + "sf.functions.stddev.stddev-over.t006": "unmet", + "sf.functions.stddev.stddev-over.t007": "unmet", + "sf.functions.stddev.stddev-over.t008": "unmet", + "sf.functions.stddev.stddev-over.t009": "unmet", + "sf.functions.stddev.stddev-samp-over.t001": "unmet", + "sf.functions.stddev.stddev-samp-over.t002": "unmet", + "sf.functions.stddev.stddev-samp-over.t003": "unmet", + "sf.functions.stddev.stddev-samp-over.t004": "unmet", + "sf.functions.stddev.stddev-samp-over.t005": "unmet", + "sf.functions.stddev.stddev-samp-over.t006": "unmet", + "sf.functions.stddev.stddev-samp-over.t007": "unmet", + "sf.functions.stddev.stddev-samp-over.t008": "unmet", + "sf.functions.stddev.stddev-samp-over.t009": "unmet", + "sf.functions.stddev.stddev-samp.t001": "unmet", + "sf.functions.stddev.stddev-samp.t002": "unmet", + "sf.functions.stddev.stddev-samp.t003": "unmet", + "sf.functions.stddev.stddev-samp.t004": "unmet", + "sf.functions.stddev.stddev-samp.t005": "unmet", + "sf.functions.stddev.stddev-samp.t006": "unmet", + "sf.functions.stddev.stddev.t001": "unmet", + "sf.functions.stddev.stddev.t002": "unmet", + "sf.functions.stddev.stddev.t003": "unmet", + "sf.functions.stddev.stddev.t004": "unmet", + "sf.functions.stddev.stddev.t005": "unmet", + "sf.functions.stddev.stddev.t006": "unmet", + "sf.functions.strip-null-value.t001": "met", + "sf.functions.strip-null-value.t002": "met", + "sf.functions.strip-null-value.t003": "met", + "sf.functions.strtok-split-to-table.t001": "unmet", + "sf.functions.strtok-split-to-table.t002": "unmet", + "sf.functions.strtok-split-to-table.t003": "unmet", + "sf.functions.strtok-split-to-table.t004": "unmet", + "sf.functions.strtok-split-to-table.t005": "unmet", + "sf.functions.strtok-to-array.t001": "unmet", + "sf.functions.strtok-to-array.t002": "unmet", + "sf.functions.strtok-to-array.t003": "unmet", + "sf.functions.strtok-to-array.t004": "unmet", + "sf.functions.strtok-to-array.t005": "unmet", + "sf.functions.strtok.t001": "unmet", + "sf.functions.strtok.t002": "unmet", + "sf.functions.strtok.t003": "unmet", + "sf.functions.strtok.t004": "unmet", + "sf.functions.strtok.t005": "unmet", + "sf.functions.strtok.t006": "unmet", + "sf.functions.strtok.t007": "unmet", + "sf.functions.substr.substr.t001": "met", + "sf.functions.substr.substr.t002": "met", + "sf.functions.substr.substr.t003": "unmet", + "sf.functions.substr.substr.t004": "met", + "sf.functions.substr.substr.t005": "met", + "sf.functions.substr.substr.t006": "met", + "sf.functions.substr.substr.t007": "met", + "sf.functions.substr.substr.t008": "met", + "sf.functions.substr.substr.t009": "met", + "sf.functions.substr.substring.t001": "met", + "sf.functions.substr.substring.t002": "met", + "sf.functions.substr.substring.t003": "unmet", + "sf.functions.substr.substring.t004": "met", + "sf.functions.substr.substring.t005": "met", + "sf.functions.substr.substring.t006": "met", + "sf.functions.substr.substring.t007": "met", + "sf.functions.substr.substring.t008": "met", + "sf.functions.substr.substring.t009": "met", + "sf.functions.sum.sum-over.t001": "met", + "sf.functions.sum.sum-over.t002": "met", + "sf.functions.sum.sum-over.t003": "met", + "sf.functions.sum.sum-over.t004": "met", + "sf.functions.sum.sum-over.t005": "met", + "sf.functions.sum.sum-over.t006": "met", + "sf.functions.sum.sum-over.t007": "met", + "sf.functions.sum.sum-over.t008": "unmet", + "sf.functions.sum.sum-over.t009": "unmet", + "sf.functions.sum.sum.t001": "met", + "sf.functions.sum.sum.t002": "met", + "sf.functions.sum.sum.t003": "unmet", + "sf.functions.sum.sum.t004": "unmet", + "sf.functions.sum.sum.t005": "met", + "sf.functions.sum.sum.t006": "met", + "sf.functions.sum.sum.t007": "met", + "sf.functions.sysdate.t001": "unmet", + "sf.functions.sysdate.t002": "unmet", + "sf.functions.sysdate.t003": "unmet", + "sf.functions.system-typeof.t001": "unmet", + "sf.functions.system-typeof.t002": "unmet", + "sf.functions.system-typeof.t003": "unmet", + "sf.functions.systimestamp.t001": "unmet", + "sf.functions.systimestamp.t002": "unmet", + "sf.functions.systimestamp.t003": "unmet", + "sf.functions.tan.t001": "unmet", + "sf.functions.tan.t002": "unmet", + "sf.functions.tan.t003": "unmet", + "sf.functions.tan.t004": "unmet", + "sf.functions.tanh.t001": "unmet", + "sf.functions.tanh.t002": "unmet", + "sf.functions.tanh.t003": "unmet", + "sf.functions.tanh.t004": "unmet", + "sf.functions.text-html.t001": "unmet", + "sf.functions.text-html.t002": "unmet", + "sf.functions.text-html.t003": "unmet", + "sf.functions.text-plain.t001": "unmet", + "sf.functions.text-plain.t002": "unmet", + "sf.functions.text-plain.t003": "unmet", + "sf.functions.time-from-parts.t001": "unmet", + "sf.functions.time-from-parts.t002": "unmet", + "sf.functions.time-from-parts.t003": "unmet", + "sf.functions.time-from-parts.t004": "unmet", + "sf.functions.time-from-parts.t005": "unmet", + "sf.functions.time-from-parts.t006": "unmet", + "sf.functions.time-from-parts.t007": "unmet", + "sf.functions.time-slice.t001": "unmet", + "sf.functions.time-slice.t002": "unmet", + "sf.functions.time-slice.t003": "unmet", + "sf.functions.time-slice.t004": "unmet", + "sf.functions.time-slice.t005": "unmet", + "sf.functions.time-slice.t006": "unmet", + "sf.functions.time-slice.t007": "unmet", + "sf.functions.timeadd.t001": "met", + "sf.functions.timeadd.t002": "unmet", + "sf.functions.timeadd.t003": "met", + "sf.functions.timeadd.t004": "met", + "sf.functions.timeadd.t005": "unmet", + "sf.functions.timeadd.t006": "met", + "sf.functions.timeadd.t007": "met", + "sf.functions.timeadd.t008": "met", + "sf.functions.timeadd.t009": "met", + "sf.functions.timeadd.t010": "unmet", + "sf.functions.timeadd.t011": "unmet", + "sf.functions.timediff.t001": "met", + "sf.functions.timediff.t002": "met", + "sf.functions.timediff.t003": "met", + "sf.functions.timediff.t004": "unmet", + "sf.functions.timediff.t005": "met", + "sf.functions.timediff.t006": "met", + "sf.functions.timediff.t007": "met", + "sf.functions.timediff.t008": "unmet", + "sf.functions.timediff.t009": "met", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t001": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t002": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t003": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t004": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t005": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t006": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t007": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t008": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t009": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t010": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t011": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t012": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t013": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t014": "unmet", + "sf.functions.timestamp-from-parts.timestamp-from-parts.t015": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t001": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t002": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t003": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t004": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t005": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t006": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t007": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t008": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t009": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t010": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ltz-from-parts.t011": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t001": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t002": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t003": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t004": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t005": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t006": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t007": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t008": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t009": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t010": "unmet", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t011": "met", + "sf.functions.timestamp-from-parts.timestamp-ntz-from-parts.t012": "met", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t001": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t002": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t003": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t004": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t005": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t006": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t007": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t008": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t009": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t010": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t011": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t012": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t013": "unmet", + "sf.functions.timestamp-from-parts.timestamp-tz-from-parts.t014": "unmet", + "sf.functions.timestampadd.t001": "met", + "sf.functions.timestampadd.t002": "unmet", + "sf.functions.timestampadd.t003": "met", + "sf.functions.timestampadd.t004": "met", + "sf.functions.timestampadd.t005": "unmet", + "sf.functions.timestampadd.t006": "met", + "sf.functions.timestampadd.t007": "met", + "sf.functions.timestampadd.t008": "met", + "sf.functions.timestampadd.t009": "met", + "sf.functions.timestampadd.t010": "unmet", + "sf.functions.timestampadd.t011": "unmet", + "sf.functions.timestampdiff.t001": "met", + "sf.functions.timestampdiff.t002": "met", + "sf.functions.timestampdiff.t003": "met", + "sf.functions.timestampdiff.t004": "unmet", + "sf.functions.timestampdiff.t005": "met", + "sf.functions.timestampdiff.t006": "met", + "sf.functions.timestampdiff.t007": "met", + "sf.functions.timestampdiff.t008": "unmet", + "sf.functions.timestampdiff.t009": "met", + "sf.functions.to-array.t001": "met", + "sf.functions.to-array.t002": "met", + "sf.functions.to-array.t003": "met", + "sf.functions.to-array.t004": "met", + "sf.functions.to-binary.t001": "unmet", + "sf.functions.to-binary.t002": "unmet", + "sf.functions.to-binary.t003": "unmet", + "sf.functions.to-binary.t004": "unmet", + "sf.functions.to-boolean.t001": "met", + "sf.functions.to-boolean.t002": "unmet", + "sf.functions.to-boolean.t003": "met", + "sf.functions.to-boolean.t004": "unmet", + "sf.functions.to-boolean.t005": "met", + "sf.functions.to-char.to-char.t001": "unmet", + "sf.functions.to-char.to-char.t002": "met", + "sf.functions.to-char.to-char.t003": "unmet", + "sf.functions.to-char.to-char.t004": "unmet", + "sf.functions.to-char.to-char.t005": "met", + "sf.functions.to-char.to-char.t006": "met", + "sf.functions.to-char.to-char.t007": "met", + "sf.functions.to-char.to-char.t008": "unmet", + "sf.functions.to-char.to-char.t009": "met", + "sf.functions.to-char.to-char.t010": "unmet", + "sf.functions.to-char.to-varchar.t001": "unmet", + "sf.functions.to-char.to-varchar.t002": "met", + "sf.functions.to-char.to-varchar.t003": "unmet", + "sf.functions.to-char.to-varchar.t004": "met", + "sf.functions.to-char.to-varchar.t005": "met", + "sf.functions.to-date.date.t001": "met", + "sf.functions.to-date.date.t002": "met", + "sf.functions.to-date.date.t003": "met", + "sf.functions.to-date.date.t004": "unmet", + "sf.functions.to-date.date.t005": "met", + "sf.functions.to-date.date.t006": "met", + "sf.functions.to-date.date.t007": "unmet", + "sf.functions.to-date.date.t008": "met", + "sf.functions.to-date.date.t009": "met", + "sf.functions.to-date.to-date.t001": "met", + "sf.functions.to-date.to-date.t002": "met", + "sf.functions.to-date.to-date.t003": "met", + "sf.functions.to-date.to-date.t004": "unmet", + "sf.functions.to-date.to-date.t005": "met", + "sf.functions.to-date.to-date.t006": "met", + "sf.functions.to-date.to-date.t007": "unmet", + "sf.functions.to-date.to-date.t008": "met", + "sf.functions.to-date.to-date.t009": "met", + "sf.functions.to-decfloat.t001": "unmet", + "sf.functions.to-decfloat.t002": "unmet", + "sf.functions.to-decfloat.t003": "unmet", + "sf.functions.to-decfloat.t004": "unmet", + "sf.functions.to-decimal.to-decimal.t001": "met", + "sf.functions.to-decimal.to-decimal.t002": "unmet", + "sf.functions.to-decimal.to-decimal.t003": "met", + "sf.functions.to-decimal.to-decimal.t004": "met", + "sf.functions.to-decimal.to-decimal.t005": "met", + "sf.functions.to-decimal.to-number.t001": "met", + "sf.functions.to-decimal.to-number.t002": "unmet", + "sf.functions.to-decimal.to-number.t003": "met", + "sf.functions.to-decimal.to-number.t004": "met", + "sf.functions.to-decimal.to-number.t005": "met", + "sf.functions.to-decimal.to-numeric.t001": "met", + "sf.functions.to-decimal.to-numeric.t002": "unmet", + "sf.functions.to-decimal.to-numeric.t003": "met", + "sf.functions.to-decimal.to-numeric.t004": "met", + "sf.functions.to-decimal.to-numeric.t005": "met", + "sf.functions.to-double.t001": "met", + "sf.functions.to-double.t002": "unmet", + "sf.functions.to-double.t003": "met", + "sf.functions.to-double.t004": "met", + "sf.functions.to-geography.t001": "unmet", + "sf.functions.to-geography.t002": "unmet", + "sf.functions.to-geography.t003": "unmet", + "sf.functions.to-geography.t004": "unmet", + "sf.functions.to-geography.t005": "unmet", + "sf.functions.to-geography.t006": "unmet", + "sf.functions.to-geography.t007": "unmet", + "sf.functions.to-geography.t008": "unmet", + "sf.functions.to-geometry.t001": "unmet", + "sf.functions.to-geometry.t002": "unmet", + "sf.functions.to-geometry.t003": "unmet", + "sf.functions.to-geometry.t004": "unmet", + "sf.functions.to-geometry.t005": "unmet", + "sf.functions.to-geometry.t006": "unmet", + "sf.functions.to-geometry.t007": "unmet", + "sf.functions.to-ipaddress.t001": "unmet", + "sf.functions.to-ipaddress.t002": "unmet", + "sf.functions.to-ipaddress.t003": "unmet", + "sf.functions.to-json.t001": "met", + "sf.functions.to-json.t002": "met", + "sf.functions.to-json.t003": "met", + "sf.functions.to-object.t001": "unmet", + "sf.functions.to-object.t002": "unmet", + "sf.functions.to-object.t003": "unmet", + "sf.functions.to-object.t004": "unmet", + "sf.functions.to-query.t001": "unmet", + "sf.functions.to-query.t002": "unmet", + "sf.functions.to-query.t003": "unmet", + "sf.functions.to-time.time.t001": "unmet", + "sf.functions.to-time.time.t002": "met", + "sf.functions.to-time.time.t003": "unmet", + "sf.functions.to-time.time.t004": "unmet", + "sf.functions.to-time.time.t005": "unmet", + "sf.functions.to-time.time.t006": "unmet", + "sf.functions.to-time.to-time.t001": "unmet", + "sf.functions.to-time.to-time.t002": "unmet", + "sf.functions.to-time.to-time.t003": "met", + "sf.functions.to-time.to-time.t004": "unmet", + "sf.functions.to-time.to-time.t005": "unmet", + "sf.functions.to-time.to-time.t006": "met", + "sf.functions.to-time.to-time.t007": "met", + "sf.functions.to-time.to-time.t008": "unmet", + "sf.functions.to-timestamp.t001": "met", + "sf.functions.to-timestamp.t002": "met", + "sf.functions.to-timestamp.t003": "met", + "sf.functions.to-timestamp.t004": "unmet", + "sf.functions.to-timestamp.t005": "met", + "sf.functions.to-timestamp.t006": "unmet", + "sf.functions.to-timestamp.t007": "met", + "sf.functions.to-timestamp.t008": "met", + "sf.functions.to-timestamp.t009": "met", + "sf.functions.to-uuid.t001": "unmet", + "sf.functions.to-uuid.t002": "unmet", + "sf.functions.to-uuid.t003": "unmet", + "sf.functions.to-variant.t001": "unmet", + "sf.functions.to-variant.t002": "met", + "sf.functions.to-xml.t001": "unmet", + "sf.functions.to-xml.t002": "unmet", + "sf.functions.to-xml.t003": "unmet", + "sf.functions.transform.t001": "unmet", + "sf.functions.transform.t002": "unmet", + "sf.functions.transform.t003": "unmet", + "sf.functions.translate.t001": "unmet", + "sf.functions.translate.t002": "met", + "sf.functions.translate.t003": "unmet", + "sf.functions.translate.t004": "unmet", + "sf.functions.translate.t005": "met", + "sf.functions.translate.t006": "unmet", + "sf.functions.trim.t001": "met", + "sf.functions.trim.t002": "met", + "sf.functions.trim.t003": "met", + "sf.functions.trim.t004": "met", + "sf.functions.trim.t005": "met", + "sf.functions.trunc.trunc.t001": "unmet", + "sf.functions.trunc.trunc.t002": "met", + "sf.functions.trunc.trunc.t003": "met", + "sf.functions.trunc.trunc.t004": "unmet", + "sf.functions.trunc.trunc.t005": "unmet", + "sf.functions.trunc.trunc.t006": "unmet", + "sf.functions.trunc.trunc.t007": "unmet", + "sf.functions.trunc.trunc.t008": "met", + "sf.functions.trunc.truncate.t001": "unmet", + "sf.functions.trunc.truncate.t002": "met", + "sf.functions.trunc.truncate.t003": "met", + "sf.functions.trunc.truncate.t004": "unmet", + "sf.functions.trunc.truncate.t005": "unmet", + "sf.functions.trunc.truncate.t006": "unmet", + "sf.functions.trunc.truncate.t007": "unmet", + "sf.functions.trunc.truncate.t008": "met", + "sf.functions.trunc2.t001": "met", + "sf.functions.trunc2.t002": "unmet", + "sf.functions.trunc2.t003": "unmet", + "sf.functions.trunc2.t004": "unmet", + "sf.functions.trunc2.t005": "met", + "sf.functions.trunc2.t006": "unmet", + "sf.functions.trunc2.t007": "unmet", + "sf.functions.try-base64-decode-binary.t001": "unmet", + "sf.functions.try-base64-decode-binary.t002": "unmet", + "sf.functions.try-base64-decode-binary.t003": "unmet", + "sf.functions.try-base64-decode-binary.t004": "unmet", + "sf.functions.try-base64-decode-binary.t005": "unmet", + "sf.functions.try-base64-decode-binary.t006": "unmet", + "sf.functions.try-base64-decode-string.t001": "unmet", + "sf.functions.try-base64-decode-string.t002": "unmet", + "sf.functions.try-base64-decode-string.t003": "unmet", + "sf.functions.try-base64-decode-string.t004": "unmet", + "sf.functions.try-base64-decode-string.t005": "unmet", + "sf.functions.try-base64-decode-string.t006": "unmet", + "sf.functions.try-cast.t001": "met", + "sf.functions.try-cast.t002": "met", + "sf.functions.try-cast.t003": "met", + "sf.functions.try-cast.t004": "unmet", + "sf.functions.try-cast.t005": "met", + "sf.functions.try-decrypt-raw.t001": "unmet", + "sf.functions.try-decrypt-raw.t002": "unmet", + "sf.functions.try-decrypt-raw.t003": "unmet", + "sf.functions.try-decrypt.t001": "unmet", + "sf.functions.try-decrypt.t002": "unmet", + "sf.functions.try-decrypt.t003": "unmet", + "sf.functions.try-hex-decode-binary.t001": "unmet", + "sf.functions.try-hex-decode-binary.t002": "unmet", + "sf.functions.try-hex-decode-binary.t003": "unmet", + "sf.functions.try-hex-decode-binary.t004": "unmet", + "sf.functions.try-hex-decode-string.t001": "met", + "sf.functions.try-hex-decode-string.t002": "met", + "sf.functions.try-hex-decode-string.t003": "met", + "sf.functions.try-hex-decode-string.t004": "met", + "sf.functions.try-parse-json.t001": "met", + "sf.functions.try-parse-json.t002": "unmet", + "sf.functions.try-parse-json.t003": "unmet", + "sf.functions.try-parse-json.t004": "met", + "sf.functions.try-to-binary.t001": "unmet", + "sf.functions.try-to-binary.t002": "unmet", + "sf.functions.try-to-binary.t003": "unmet", + "sf.functions.try-to-boolean.t001": "met", + "sf.functions.try-to-boolean.t002": "met", + "sf.functions.try-to-boolean.t003": "met", + "sf.functions.try-to-date.t001": "met", + "sf.functions.try-to-date.t002": "met", + "sf.functions.try-to-date.t003": "met", + "sf.functions.try-to-date.t004": "met", + "sf.functions.try-to-decfloat.t001": "unmet", + "sf.functions.try-to-decfloat.t002": "unmet", + "sf.functions.try-to-decfloat.t003": "unmet", + "sf.functions.try-to-decimal.try-to-decimal.t001": "met", + "sf.functions.try-to-decimal.try-to-decimal.t002": "met", + "sf.functions.try-to-decimal.try-to-decimal.t003": "unmet", + "sf.functions.try-to-decimal.try-to-decimal.t004": "met", + "sf.functions.try-to-decimal.try-to-number.t001": "met", + "sf.functions.try-to-decimal.try-to-number.t002": "met", + "sf.functions.try-to-decimal.try-to-number.t003": "unmet", + "sf.functions.try-to-decimal.try-to-number.t004": "met", + "sf.functions.try-to-decimal.try-to-numeric.t001": "met", + "sf.functions.try-to-decimal.try-to-numeric.t002": "met", + "sf.functions.try-to-decimal.try-to-numeric.t003": "unmet", + "sf.functions.try-to-decimal.try-to-numeric.t004": "met", + "sf.functions.try-to-double.t001": "met", + "sf.functions.try-to-double.t002": "met", + "sf.functions.try-to-double.t003": "unmet", + "sf.functions.try-to-double.t004": "met", + "sf.functions.try-to-geography.t001": "unmet", + "sf.functions.try-to-geography.t002": "unmet", + "sf.functions.try-to-geography.t003": "unmet", + "sf.functions.try-to-geography.t004": "unmet", + "sf.functions.try-to-geometry.t001": "unmet", + "sf.functions.try-to-geometry.t002": "unmet", + "sf.functions.try-to-geometry.t003": "unmet", + "sf.functions.try-to-geometry.t004": "unmet", + "sf.functions.try-to-ipaddress.t001": "unmet", + "sf.functions.try-to-ipaddress.t002": "unmet", + "sf.functions.try-to-ipaddress.t003": "unmet", + "sf.functions.try-to-time.t001": "unmet", + "sf.functions.try-to-time.t002": "unmet", + "sf.functions.try-to-time.t003": "unmet", + "sf.functions.try-to-time.t004": "unmet", + "sf.functions.try-to-timestamp.t001": "met", + "sf.functions.try-to-timestamp.t002": "held", + "sf.functions.try-to-timestamp.t003": "unmet", + "sf.functions.try-to-timestamp.t004": "met", + "sf.functions.try-to-timestamp.t005": "met", + "sf.functions.try-to-uuid.t001": "unmet", + "sf.functions.try-to-uuid.t002": "unmet", + "sf.functions.try-to-uuid.t003": "unmet", + "sf.functions.typeof.t001": "unmet", + "sf.functions.typeof.t002": "unmet", + "sf.functions.typeof.t003": "met", + "sf.functions.unicode.t001": "unmet", + "sf.functions.unicode.t002": "unmet", + "sf.functions.unicode.t003": "unmet", + "sf.functions.uniform.t001": "unmet", + "sf.functions.uniform.t002": "unmet", + "sf.functions.uniform.t003": "unmet", + "sf.functions.uniform.t004": "unmet", + "sf.functions.upper.t001": "met", + "sf.functions.upper.t002": "unmet", + "sf.functions.upper.t003": "met", + "sf.functions.upper.t004": "met", + "sf.functions.uuid-string.t001": "unmet", + "sf.functions.uuid-string.t002": "unmet", + "sf.functions.uuid-string.t003": "unmet", + "sf.functions.var-pop.var-pop-over.t001": "unmet", + "sf.functions.var-pop.var-pop-over.t002": "unmet", + "sf.functions.var-pop.var-pop-over.t003": "unmet", + "sf.functions.var-pop.var-pop-over.t004": "unmet", + "sf.functions.var-pop.var-pop-over.t005": "unmet", + "sf.functions.var-pop.var-pop-over.t006": "unmet", + "sf.functions.var-pop.var-pop-over.t007": "unmet", + "sf.functions.var-pop.var-pop-over.t008": "unmet", + "sf.functions.var-pop.var-pop-over.t009": "unmet", + "sf.functions.var-pop.var-pop.t001": "unmet", + "sf.functions.var-pop.var-pop.t002": "unmet", + "sf.functions.var-pop.var-pop.t003": "unmet", + "sf.functions.var-pop.var-pop.t004": "unmet", + "sf.functions.var-pop.var-pop.t005": "unmet", + "sf.functions.var-pop.var-pop.t006": "unmet", + "sf.functions.var-samp.var-samp-over.t001": "unmet", + "sf.functions.var-samp.var-samp-over.t002": "unmet", + "sf.functions.var-samp.var-samp-over.t003": "unmet", + "sf.functions.var-samp.var-samp-over.t004": "unmet", + "sf.functions.var-samp.var-samp-over.t005": "unmet", + "sf.functions.var-samp.var-samp-over.t006": "unmet", + "sf.functions.var-samp.var-samp-over.t007": "unmet", + "sf.functions.var-samp.var-samp-over.t008": "unmet", + "sf.functions.var-samp.var-samp.t001": "unmet", + "sf.functions.var-samp.var-samp.t002": "unmet", + "sf.functions.var-samp.var-samp.t003": "unmet", + "sf.functions.var-samp.var-samp.t004": "unmet", + "sf.functions.var-samp.var-samp.t005": "unmet", + "sf.functions.var-samp.var-samp.t006": "unmet", + "sf.functions.variance-pop.variance-pop-over.t001": "unmet", + "sf.functions.variance-pop.variance-pop-over.t002": "unmet", + "sf.functions.variance-pop.variance-pop-over.t003": "unmet", + "sf.functions.variance-pop.variance-pop-over.t004": "unmet", + "sf.functions.variance-pop.variance-pop-over.t005": "unmet", + "sf.functions.variance-pop.variance-pop-over.t006": "unmet", + "sf.functions.variance-pop.variance-pop-over.t007": "unmet", + "sf.functions.variance-pop.variance-pop-over.t008": "unmet", + "sf.functions.variance-pop.variance-pop-over.t009": "unmet", + "sf.functions.variance-pop.variance-pop.t001": "unmet", + "sf.functions.variance-pop.variance-pop.t002": "unmet", + "sf.functions.variance-pop.variance-pop.t003": "unmet", + "sf.functions.variance-pop.variance-pop.t004": "unmet", + "sf.functions.variance-pop.variance-pop.t005": "unmet", + "sf.functions.variance-pop.variance-pop.t006": "unmet", + "sf.functions.variance.variance-over.t001": "unmet", + "sf.functions.variance.variance-over.t002": "unmet", + "sf.functions.variance.variance-over.t003": "unmet", + "sf.functions.variance.variance-over.t004": "unmet", + "sf.functions.variance.variance-over.t005": "unmet", + "sf.functions.variance.variance-over.t006": "unmet", + "sf.functions.variance.variance-over.t007": "unmet", + "sf.functions.variance.variance-over.t008": "unmet", + "sf.functions.variance.variance.t001": "unmet", + "sf.functions.variance.variance.t002": "unmet", + "sf.functions.variance.variance.t003": "unmet", + "sf.functions.variance.variance.t004": "unmet", + "sf.functions.variance.variance.t005": "unmet", + "sf.functions.variance.variance.t006": "unmet", + "sf.functions.vector-avg.t001": "unmet", + "sf.functions.vector-avg.t002": "unmet", + "sf.functions.vector-avg.t003": "unmet", + "sf.functions.vector-avg.t004": "unmet", + "sf.functions.vector-cosine-similarity.t001": "unmet", + "sf.functions.vector-cosine-similarity.t002": "unmet", + "sf.functions.vector-cosine-similarity.t003": "unmet", + "sf.functions.vector-cosine-similarity.t004": "unmet", + "sf.functions.vector-inner-product.t001": "unmet", + "sf.functions.vector-inner-product.t002": "unmet", + "sf.functions.vector-inner-product.t003": "unmet", + "sf.functions.vector-inner-product.t004": "unmet", + "sf.functions.vector-l1-distance.t001": "unmet", + "sf.functions.vector-l1-distance.t002": "unmet", + "sf.functions.vector-l1-distance.t003": "unmet", + "sf.functions.vector-l1-distance.t004": "unmet", + "sf.functions.vector-l2-distance.t001": "unmet", + "sf.functions.vector-l2-distance.t002": "unmet", + "sf.functions.vector-l2-distance.t003": "unmet", + "sf.functions.vector-l2-distance.t004": "unmet", + "sf.functions.vector-max.t001": "unmet", + "sf.functions.vector-max.t002": "unmet", + "sf.functions.vector-max.t003": "unmet", + "sf.functions.vector-max.t004": "unmet", + "sf.functions.vector-min.t001": "unmet", + "sf.functions.vector-min.t002": "unmet", + "sf.functions.vector-min.t003": "unmet", + "sf.functions.vector-min.t004": "unmet", + "sf.functions.vector-normalize.t001": "unmet", + "sf.functions.vector-normalize.t002": "unmet", + "sf.functions.vector-normalize.t003": "unmet", + "sf.functions.vector-sum.t001": "unmet", + "sf.functions.vector-sum.t002": "unmet", + "sf.functions.vector-sum.t003": "unmet", + "sf.functions.vector-sum.t004": "unmet", + "sf.functions.vector-truncate.t001": "unmet", + "sf.functions.vector-truncate.t002": "unmet", + "sf.functions.vector-truncate.t003": "unmet", + "sf.functions.width-bucket.t001": "unmet", + "sf.functions.width-bucket.t002": "unmet", + "sf.functions.width-bucket.t003": "unmet", + "sf.functions.width-bucket.t004": "unmet", + "sf.functions.width-bucket.t005": "unmet", + "sf.functions.width-bucket.t006": "unmet", + "sf.functions.width-bucket.t007": "unmet", + "sf.functions.width-bucket.t008": "unmet", + "sf.functions.width-bucket.t009": "unmet", + "sf.functions.width-bucket.t010": "unmet", + "sf.functions.width-bucket.t011": "unmet", + "sf.functions.xmlget.t001": "unmet", + "sf.functions.xmlget.t002": "unmet", + "sf.functions.xmlget.t003": "unmet", + "sf.functions.year.day.t001": "met", + "sf.functions.year.day.t002": "met", + "sf.functions.year.day.t003": "unmet", + "sf.functions.year.day.t004": "met", + "sf.functions.year.day.t005": "met", + "sf.functions.year.day.t006": "unmet", + "sf.functions.year.dayofmonth.t001": "unmet", + "sf.functions.year.dayofmonth.t002": "unmet", + "sf.functions.year.dayofmonth.t003": "unmet", + "sf.functions.year.dayofmonth.t004": "unmet", + "sf.functions.year.dayofmonth.t005": "unmet", + "sf.functions.year.dayofweek.t001": "unmet", + "sf.functions.year.dayofweek.t002": "unmet", + "sf.functions.year.dayofweek.t003": "unmet", + "sf.functions.year.dayofweek.t004": "unmet", + "sf.functions.year.dayofweek.t005": "unmet", + "sf.functions.year.dayofweekiso.t001": "met", + "sf.functions.year.dayofweekiso.t002": "met", + "sf.functions.year.dayofweekiso.t003": "unmet", + "sf.functions.year.dayofweekiso.t004": "met", + "sf.functions.year.dayofweekiso.t005": "met", + "sf.functions.year.dayofyear.t001": "unmet", + "sf.functions.year.dayofyear.t002": "unmet", + "sf.functions.year.dayofyear.t003": "unmet", + "sf.functions.year.dayofyear.t004": "unmet", + "sf.functions.year.dayofyear.t005": "unmet", + "sf.functions.year.month.t001": "met", + "sf.functions.year.month.t002": "met", + "sf.functions.year.month.t003": "unmet", + "sf.functions.year.month.t004": "met", + "sf.functions.year.month.t005": "met", + "sf.functions.year.month.t006": "unmet", + "sf.functions.year.quarter.t001": "met", + "sf.functions.year.quarter.t002": "met", + "sf.functions.year.quarter.t003": "unmet", + "sf.functions.year.quarter.t004": "met", + "sf.functions.year.quarter.t005": "met", + "sf.functions.year.week.t001": "unmet", + "sf.functions.year.week.t002": "unmet", + "sf.functions.year.week.t003": "unmet", + "sf.functions.year.week.t004": "unmet", + "sf.functions.year.week.t005": "unmet", + "sf.functions.year.weekiso.t001": "unmet", + "sf.functions.year.weekiso.t002": "unmet", + "sf.functions.year.weekiso.t003": "unmet", + "sf.functions.year.weekiso.t004": "unmet", + "sf.functions.year.weekiso.t005": "unmet", + "sf.functions.year.weekofyear.t001": "unmet", + "sf.functions.year.weekofyear.t002": "unmet", + "sf.functions.year.weekofyear.t003": "unmet", + "sf.functions.year.weekofyear.t004": "unmet", + "sf.functions.year.weekofyear.t005": "unmet", + "sf.functions.year.year.t001": "met", + "sf.functions.year.year.t002": "met", + "sf.functions.year.year.t003": "unmet", + "sf.functions.year.year.t004": "met", + "sf.functions.year.year.t005": "met", + "sf.functions.year.year.t006": "unmet", + "sf.functions.year.yearofweek.t001": "unmet", + "sf.functions.year.yearofweek.t002": "unmet", + "sf.functions.year.yearofweek.t003": "unmet", + "sf.functions.year.yearofweek.t004": "unmet", + "sf.functions.year.yearofweek.t005": "unmet", + "sf.functions.year.yearofweekiso.t001": "unmet", + "sf.functions.year.yearofweekiso.t002": "unmet", + "sf.functions.year.yearofweekiso.t003": "unmet", + "sf.functions.year.yearofweekiso.t004": "unmet", + "sf.functions.year.yearofweekiso.t005": "unmet", + "sf.functions.zeroifnull.t001": "met", + "sf.functions.zeroifnull.t002": "met", + "sf.functions.zeroifnull.t003": "met", + "sf.functions.zipf.t001": "unmet", + "sf.functions.zipf.t002": "unmet", + "sf.functions.zipf.t003": "unmet", + "sf.query.asof-join.t001": "met", + "sf.query.asof-join.t002": "met", + "sf.query.asof-join.t003": "met", + "sf.query.connect-by.t001": "met", + "sf.query.connect-by.t002": "met", + "sf.query.connect-by.t003": "met", + "sf.query.from.t001": "met", + "sf.query.from.t002": "met", + "sf.query.group-by-cube.t001": "unmet", + "sf.query.group-by-cube.t002": "unmet", + "sf.query.group-by-cube.t003": "unmet", + "sf.query.group-by-grouping-sets.t001": "held", + "sf.query.group-by-grouping-sets.t002": "held", + "sf.query.group-by-grouping-sets.t003": "held", + "sf.query.group-by-rollup.t001": "unmet", + "sf.query.group-by-rollup.t002": "unmet", + "sf.query.group-by-rollup.t003": "unmet", + "sf.query.group-by.all.t001": "met", + "sf.query.group-by.all.t002": "met", + "sf.query.group-by.groupitem.t001": "met", + "sf.query.group-by.groupitem.t002": "met", + "sf.query.group-by.groupitem.t003": "met", + "sf.query.having.t001": "met", + "sf.query.having.t002": "met", + "sf.query.having.t003": "met", + "sf.query.join-lateral.t001": "met", + "sf.query.join-lateral.t002": "met", + "sf.query.join.join-2.t001": "unmet", + "sf.query.join.join-2.t002": "met", + "sf.query.join.join-2.t003": "unmet", + "sf.query.join.join.syntax.t001": "unmet", + "sf.query.join.join.syntax.t002": "met", + "sf.query.join.join.t001": "met", + "sf.query.join.join.t002": "met", + "sf.query.join.join.t003": "met", + "sf.query.join.join.t004": "met", + "sf.query.join.join.t005": "met", + "sf.query.join.join.t006": "met", + "sf.query.limit.fetch.t001": "unmet", + "sf.query.limit.fetch.t002": "unmet", + "sf.query.limit.fetch.t003": "unmet", + "sf.query.limit.fetch.t004": "unmet", + "sf.query.limit.limit.t001": "met", + "sf.query.limit.limit.t002": "met", + "sf.query.limit.limit.t003": "unmet", + "sf.query.limit.limit.t004": "unmet", + "sf.query.operators-query.except.t001": "met", + "sf.query.operators-query.except.t002": "met", + "sf.query.operators-query.intersect-minus-except-union.t001": "met", + "sf.query.operators-query.intersect-minus-except-union.t002": "met", + "sf.query.operators-query.intersect-minus-except-union.t003": "unmet", + "sf.query.operators-query.intersect-minus-except-union.t004": "met", + "sf.query.operators-query.intersect.t001": "met", + "sf.query.operators-query.intersect.t002": "met", + "sf.query.operators-query.minus.t001": "met", + "sf.query.operators-query.minus.t002": "met", + "sf.query.operators-query.union.t001": "met", + "sf.query.operators-query.union.t002": "met", + "sf.query.operators-query.union.t003": "met", + "sf.query.operators-query.union.t004": "met", + "sf.query.order-by.orderitem.t001": "met", + "sf.query.order-by.orderitem.t002": "met", + "sf.query.order-by.orderitem.t003": "met", + "sf.query.order-by.orderitem.t004": "met", + "sf.query.order-by.orderitem.t005": "met", + "sf.query.order-by.orderitem.t006": "met", + "sf.query.pivot.t001": "unmet", + "sf.query.pivot.t002": "unmet", + "sf.query.pivot.t003": "unmet", + "sf.query.qualify.qualify.t001": "met", + "sf.query.qualify.qualify.t002": "met", + "sf.query.qualify.qualify.t003": "met", + "sf.query.qualify.select-from-qualify.t001": "met", + "sf.query.qualify.select-from-qualify.t002": "met", + "sf.query.qualify.select-from-qualify.t003": "met", + "sf.query.sample.t001": "unmet", + "sf.query.sample.t002": "unmet", + "sf.query.sample.t003": "unmet", + "sf.query.select.select.selecting-specific-columns.t001": "met", + "sf.query.select.select.selecting-specific-columns.t002": "met", + "sf.query.select.select.selecting-specific-columns.t003": "met", + "sf.query.select.select.selecting-specific-columns.t004": "met", + "sf.query.select.select.t001": "met", + "sf.query.select.select.t002": "unmet", + "sf.query.select.select.t003": "met", + "sf.query.select.select.t004": "met", + "sf.query.select.select.t005": "met", + "sf.query.select.select.t006": "unmet", + "sf.query.select.select.t007": "unmet", + "sf.query.select.select.t008": "unmet", + "sf.query.select.select.t009": "unmet", + "sf.query.select.select.t010": "unmet", + "sf.query.select.select.t011": "unmet", + "sf.query.select.select.t012": "unmet", + "sf.query.select.select.t013": "unmet", + "sf.query.select.select.t014": "unmet", + "sf.query.select.select.t015": "unmet", + "sf.query.select.select.t016": "unmet", + "sf.query.select.select.t017": "unmet", + "sf.query.select.select.t018": "unmet", + "sf.query.select.select.t019": "unmet", + "sf.query.top-n.t001": "unmet", + "sf.query.top-n.t002": "unmet", + "sf.query.top-n.t003": "unmet", + "sf.query.top-n.t004": "unmet", + "sf.query.unpivot.t001": "unmet", + "sf.query.unpivot.t002": "unmet", + "sf.query.values.t001": "met", + "sf.query.values.t002": "met", + "sf.query.values.t003": "met", + "sf.query.where.t001": "met", + "sf.query.where.t002": "met", + "sf.query.with.select.syntax.t001": "unmet", + "sf.query.with.select.syntax.t002": "unmet", + "sf.query.with.select.syntax.t003": "unmet", + "sf.query.with.select.t001": "met", + "sf.query.with.select.t002": "met" + }, + "retired": [ + "sf.query.group-by.t001", + "sf.query.group-by.t002", + "sf.query.group-by.t003", + "sf.query.join.t001", + "sf.query.join.t002", + "sf.query.order-by.t001", + "sf.query.order-by.t003", + "sf.query.qualify.t001", + "sf.query.qualify.t002", + "sf.query.qualify.t003", + "sf.query.select.select-exclude-rename.t001", + "sf.query.select.select-exclude-rename.t002", + "sf.query.select.select-exclude-replace-rename.t001", + "sf.query.select.select-exclude-replace-rename.t002", + "sf.query.select.select-exclude-replace.t001", + "sf.query.select.select-exclude-replace.t002", + "sf.query.select.select-ilike-rename.t001", + "sf.query.select.select-ilike-rename.t002", + "sf.query.select.select-ilike-replace-rename.t001", + "sf.query.select.select-ilike-replace-rename.t002", + "sf.query.select.select-ilike-replace.t001", + "sf.query.select.select-ilike-replace.t002", + "sf.query.select.select-replace-rename.t001", + "sf.query.select.select-replace-rename.t002" + ] }