Variables: a CSV header that names one variable twice is refused

dataset.import read two header cells that named one variable (City
and City, or Shown and #Shown) into the same column, so each row kept
only the last non-blank cell and the other value was dropped without a
word. The import is now refused with the two column numbers, and the
message has a row in every complete-message catalog.
This commit is contained in:
dotCooCoo
2026-11-02 12:03:40 +07:00
committed by bflatastic
parent 386bfc881e
commit 06221ce545
26 changed files with 71 additions and 4 deletions
+1 -1
View File
@@ -731,7 +731,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Import Data Sets…",
["Window", "Variables"],
None,
"{path? | data? | dataBase64? | csv?} load datasets from CSV, comma- or tab-separated (header: name, then variable names; one row per dataset; without the name column every header is a variable and the rows take the first free names Data Set 1, 2…). A header that names no variable defines one, unbound: `#Name` defines a visibility variable, `@Name` defines an image variable, and a header without a prefix defines a text variable. A prefixed header whose name is a variable of another kind, and a `%` header that isn't a variable's exact name (graph data files), are refused, and so is a header that would define a variable while the variables are locked. Rows whose name already exists are replaced → {imported, updated, names, defined}",
"{path? | data? | dataBase64? | csv?} load datasets from CSV, comma- or tab-separated (header: name, then variable names; one row per dataset; without the name column every header is a variable and the rows take the first free names Data Set 1, 2…). A header that names no variable defines one, unbound: `#Name` defines a visibility variable, `@Name` defines an image variable, and a header without a prefix defines a text variable. A prefixed header whose name is a variable of another kind, and a `%` header that isn't a variable's exact name (graph data files), are refused, and so are two headers that name one variable and a header that would define a variable while the variables are locked. Rows whose name already exists are replaced → {imported, updated, names, defined}",
has_doc,
dataset_import
),
+6 -2
View File
@@ -252,8 +252,8 @@ fn header_variable(
/// names; the other headers name variables, as [`header_variable`] reads them, and the
/// variables the document doesn't define yet are defined, unbound. Without the `name` column,
/// every header names a variable and the rows take the first free names "Data Set 1", "Data
/// Set 2" and so on. Existing rows of the same name are replaced; new names are appended. One
/// undo step.
/// Set 2" and so on. Two headers that name one variable are refused. Existing rows of the same
/// name are replaced; new names are appended. One undo step.
pub(super) fn dataset_import(s: &mut Session, p: &Value) -> Result<Value> {
const C: &str = "dataset.import";
let bytes = datasets_csv_bytes(p, C)?;
@@ -277,6 +277,10 @@ pub(super) fn dataset_import(s: &mut Session, p: &Value) -> Result<Value> {
return Err(bad(C, format!("empty header in column {}", i + 1)));
}
let (name, kind) = header_variable(cell, i + 1, &kinds, &mut defined, C)?;
if let Some(&(first, ..)) = columns.iter().find(|(_, n, _)| *n == name) {
let (first, column) = (first + 1, i + 1);
return Err(bad(C, format!("columns {first} and {column} both name the variable `{name}`")));
}
columns.push((i, name, kind));
}
// Lock Variables refuses New Variable, so the import is refused when a header would define one.