appears or not.
If @samp{INTO @var{dest_vars}} does not appear, then values will be recoded
-``in place´´. This means that the recoded values are written back to the
+``in place´´.
+This means that the recoded values are written back to the
source variables from whence the original values came.
In this case, the @var{dest_value} for every mapping must imply a value which
has the same type as the @var{src_value}.
For example, if the source value is a string value, it is not permissible for
@var{dest_value} to be @samp{SYSMIS} or another forms which implies a numeric
result.
+It is also not permissible for @var{dest_value} to be longer than the width
+of the source variable.
+
The following example two numeric variables @var{x} and @var{y} are recoded
in place.
Zero is recoded to 99, the values 1 to 10 inclusive are unchanged,
static void set_map_out_str (struct map_out *, struct pool *,
struct substring);
-static void enlarge_dst_widths (struct recode_trns *);
+static bool enlarge_dst_widths (struct recode_trns *);
static void create_dst_vars (struct recode_trns *, struct dictionary *);
static trns_proc_func recode_trns_proc;
/* Ensure that all the output strings are at least as wide
as the widest destination variable. */
if (trns->dst_type == VAL_STRING)
- enlarge_dst_widths (trns);
+ {
+ if ( ! enlarge_dst_widths (trns))
+ {
+ return CMD_FAILURE;
+ }
+ }
/* Create destination variables, if needed.
This must be the final step; otherwise we'd have to
/* Ensures that all the output values in TRNS are as wide as the
widest destination variable. */
-static void
+static bool
enlarge_dst_widths (struct recode_trns *trns)
{
size_t i;
-
+ const struct variable *narrow_var = NULL;
+ int min_dst_width = INT_MAX;
trns->max_dst_width = 0;
+
for (i = 0; i < trns->var_cnt; i++)
{
const struct variable *v = trns->dst_vars[i];
if (var_get_width (v) > trns->max_dst_width)
trns->max_dst_width = var_get_width (v);
+
+ if (var_get_width (v) < min_dst_width)
+ {
+ min_dst_width = var_get_width (v);
+ narrow_var = v;
+ }
}
for (i = 0; i < trns->map_cnt; i++)
{
struct map_out *out = &trns->mappings[i].out;
if (!out->copy_input)
- value_resize_pool (trns->pool, &out->value,
- out->width, trns->max_dst_width);
+ {
+ if (out->width > min_dst_width)
+ {
+ msg (ME,
+ _("Cannot recode because the variable %s would require a width of %d bytes or greater, but it has a width of only %d bytes."),
+ var_get_name (narrow_var), out->width, trns->max_dst_width);
+ return false;
+ }
+
+ value_resize_pool (trns->pool, &out->value,
+ out->width, trns->max_dst_width);
+ }
}
+
+ return true;
}
/* Creates destination variables that don't already exist. */
3,4,1
])
AT_CLEANUP
+
+
+
+AT_SETUP([RECODE increased string widths])
+
+AT_DATA([recode.sps],[dnl
+data list list /x (a1) y (a8) z *.
+begin data.
+a a 2
+a two 2
+b three 2
+c b 2
+end data.
+
+recode x y ("a" = "first") .
+
+list.
+])
+
+AT_CHECK([pspp -O format=csv recode.sps], [1], [dnl
+Table: Reading free-form data from INLINE.
+Variable,Format
+x,A1
+y,A8
+z,F8.0
+
+"error: Cannot recode in place, because the variable x would require a width of 5 bytes or greater, but it has a width of only 8 bytes."
+
+Table: Data List
+x,y,z
+a,a ,2.00
+a,two ,2.00
+b,three ,2.00
+c,b ,2.00
+])
+
+AT_CLEANUP