Skip to content

Commit 56fa018

Browse files
committed
mk-oracle: Refactorings
- Fail on malformed instance info rows instead of dropping them silently. No change in behavior - No supported release produces such a row. - Drop unused string values from the `Tenant::new` parsing. Rename the method, so its purpose is clear. TESTS: Manual against 12.1, 19.3, 23.26, and 11.2 (failing with ORA-00904) on Docker. Change-Id: I5867f5bb767252cba7330cdfa27d85c88011ccb5
1 parent 2c360cb commit 56fa018

2 files changed

Lines changed: 59 additions & 36 deletions

File tree

packages/mk-oracle/src/ora_sql/system.rs

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,7 @@ fn _detect_version(spot: &OpenedSpot) -> Result<DetectedVersion> {
118118
fn _get_instances(spot: &OpenedSpot, custom_query: Option<&str>) -> Result<_InstanceEntries> {
119119
if let Some(query) = custom_query {
120120
// Replaces the probe entirely; the caller owns the column set.
121-
return Ok(_to_instance_entries(
122-
spot.query_table(&SqlQuery::new(query, &Vec::new())).0?,
123-
));
121+
return _to_instance_entries(spot.query_table(&SqlQuery::new(query, &Vec::new())).0?);
124122
}
125123

126124
let detected = _detect_version(spot)?;
@@ -143,7 +141,7 @@ fn _get_instances(spot: &OpenedSpot, custom_query: Option<&str>) -> Result<_Inst
143141
*version_column = detected.version().clone().into();
144142
}
145143
}
146-
Ok(_to_instance_entries(result))
144+
_to_instance_entries(result)
147145
}
148146

149147
fn _extract_version(result: Vec<String>) -> Option<String> {
@@ -158,25 +156,29 @@ fn _extract_version(result: Vec<String>) -> Option<String> {
158156
.map(str::to_string)
159157
}
160158

161-
fn _to_instance_entries(result: Vec<Vec<String>>) -> _InstanceEntries {
162-
let hashmap: _InstanceEntries = result
159+
/// Consumes columns 0, 2 and 4. Instance info we cannot interpret fails the
160+
/// endpoint, which surfaces as a FAILURE row, rather than guessing a tenancy
161+
/// that would silently reshape every section.
162+
fn _to_instance_entries(result: Vec<Vec<String>>) -> Result<_InstanceEntries> {
163+
result
163164
.into_iter()
164-
.filter_map(|x| {
165-
if x.len() < 2 {
166-
log::error!(
167-
"Unexpected result from v$instance: expected at least 2 columns, got {}",
168-
x.len()
165+
.map(|row| {
166+
let (Some(name), Some(version), Some(tenant)) = (row.first(), row.get(2), row.get(4))
167+
else {
168+
anyhow::bail!(
169+
"Unexpected result from v$instance: expected at least 5 columns, got {}",
170+
row.len()
169171
);
170-
None
171-
} else {
172-
Some((
173-
InstanceName::from(x[0].as_str()),
174-
(InstanceVersion::from(x[2].clone()), Tenant::new(&x[4])),
175-
))
176-
}
172+
};
173+
let tenant = Tenant::from_cdb_column(tenant).ok_or_else(|| {
174+
anyhow::anyhow!("Unexpected v$database.cdb value '{tenant}' for instance {name}")
175+
})?;
176+
Ok((
177+
InstanceName::from(name.as_str()),
178+
(InstanceVersion::from(version.clone()), tenant),
179+
))
177180
})
178-
.collect();
179-
hashmap
181+
.collect()
180182
}
181183
pub fn convert_to_num_version(version: &InstanceVersion) -> Option<InstanceNumVersion> {
182184
let tops = String::from(version.clone())
@@ -198,7 +200,7 @@ pub fn convert_to_num_version(version: &InstanceVersion) -> Option<InstanceNumVe
198200
mod tests {
199201
use super::*;
200202
use crate::config::ora_sql::Endpoint;
201-
use crate::ora_sql::backend::test_support::MiniOra;
203+
use crate::ora_sql::backend::test_support::{instance_row, MiniOra};
202204
use crate::ora_sql::backend::SpotBuilder;
203205

204206
/// Returns the derived (version, tenant) plus every query the run issued.
@@ -322,6 +324,30 @@ mod tests {
322324
.is_none());
323325
}
324326

327+
#[test]
328+
fn test_instance_entries_tenant_from_cdb_column() {
329+
for (cdb, expected) in [("NO", Tenant::NoCdb), ("YES", Tenant::Cdb)] {
330+
let entries =
331+
_to_instance_entries(vec![instance_row("ORCL", "19.28.0.0.0", cdb)]).unwrap();
332+
assert_eq!(
333+
entries.get(&InstanceName::from("ORCL")).unwrap().1,
334+
expected
335+
);
336+
}
337+
}
338+
339+
#[test]
340+
fn test_instance_entries_short_row_is_skipped_not_panic() {
341+
for row in [vec!["ORCL".to_string()], vec!["ORCL".into(), "0".into()]] {
342+
assert!(_to_instance_entries(vec![row]).is_err());
343+
}
344+
}
345+
346+
#[test]
347+
fn test_instance_entries_unknown_cdb_value_fails() {
348+
assert!(_to_instance_entries(vec![instance_row("ORCL", "19.28.0.0.0", "MAYBE")]).is_err());
349+
}
350+
325351
#[test]
326352
fn test_convert_to_num_version() {
327353
assert_eq!(

packages/mk-oracle/src/types.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,10 @@ pub struct InstanceVersion(String);
190190
#[derive(PartialEq, From, Clone, Copy, Debug, Display, Default, Into, PartialOrd)]
191191
pub struct InstanceNumVersion(u32);
192192

193+
/// Used to express CDB property of instances AND applicability of queries.
193194
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
194195
pub enum Tenant {
195-
All,
196+
All, // Only for queries: Query applies to both CDB and non-CDB instances.
196197
Cdb,
197198
NoCdb,
198199
}
@@ -204,12 +205,11 @@ pub enum AsmInstance {
204205
}
205206

206207
impl Tenant {
207-
pub fn new(tenant: &str) -> Self {
208-
match tenant.to_lowercase().as_str() {
209-
"all" => Tenant::All,
210-
"cdb" | "yes" => Tenant::Cdb,
211-
"nocdb" | "no" => Tenant::NoCdb,
212-
_ => panic!("Unknown tenant type: {}", tenant),
208+
pub fn from_cdb_column(cdb_column: &str) -> Option<Self> {
209+
match cdb_column.to_lowercase().as_str() {
210+
"yes" => Some(Tenant::Cdb),
211+
"no" => Some(Tenant::NoCdb),
212+
_ => None,
213213
}
214214
}
215215
}
@@ -361,14 +361,11 @@ mod tests {
361361

362362
#[test]
363363
fn test_tenant() {
364-
assert_eq!(Tenant::new("all"), Tenant::All);
365-
assert_eq!(Tenant::new("cdb"), Tenant::Cdb);
366-
assert_eq!(Tenant::new("nocdb"), Tenant::NoCdb);
367-
assert_eq!(Tenant::new("yEs"), Tenant::Cdb);
368-
assert_eq!(Tenant::new("no"), Tenant::NoCdb);
369-
// panic on unknown tenant
370-
let result = std::panic::catch_unwind(|| Tenant::new("unknown"));
371-
assert!(result.is_err());
364+
assert_eq!(Tenant::from_cdb_column("yEs"), Some(Tenant::Cdb));
365+
assert_eq!(Tenant::from_cdb_column("no"), Some(Tenant::NoCdb));
366+
assert!(Tenant::from_cdb_column("cdb").is_none());
367+
assert!(Tenant::from_cdb_column("unknown").is_none());
368+
assert!(Tenant::from_cdb_column("").is_none());
372369
}
373370

374371
#[test]

0 commit comments

Comments
 (0)