From: Ben Pfaff Date: Sat, 7 Aug 2010 20:47:33 +0000 (-0700) Subject: SAVE: Fix UNSELECTED=RETAIN with a filter variable. X-Git-Tag: sav-api~113 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=a7b5ed72c52e462c75a2fed485ed65aaf09a1d39 SAVE: Fix UNSELECTED=RETAIN with a filter variable. Apparently this had never been tested. It assert-failed consistently because the filter variable being saved was from the dictionary before reading the data, but the dictionary after reading the data was different due to the temporary transformation used to drop the filtered data. --- diff --git a/src/data/procedure.c b/src/data/procedure.c index c79e784e8b..fa52806f60 100644 --- a/src/data/procedure.c +++ b/src/data/procedure.c @@ -163,10 +163,14 @@ proc_execute (struct dataset *ds) static const struct casereader_class proc_casereader_class; -/* Opens dataset DS for reading cases with proc_read. +/* Opens dataset DS for reading cases with proc_read. If FILTER is true, then + cases filtered out with FILTER BY will not be included in the casereader + (which is usually desirable). If FILTER is false, all cases will be + included regardless of FILTER BY settings. + proc_commit must be called when done. */ struct casereader * -proc_open (struct dataset *ds) +proc_open_filtering (struct dataset *ds, bool filter) { struct casereader *reader; @@ -179,7 +183,8 @@ proc_open (struct dataset *ds) /* Finish up the collection of transformations. */ add_case_limit_trns (ds); - add_filter_trns (ds); + if (filter) + add_filter_trns (ds); trns_chain_finalize (ds->cur_trns_chain); /* Make permanent_dict refer to the dictionary right before @@ -237,6 +242,14 @@ proc_open (struct dataset *ds) return reader; } +/* Opens dataset DS for reading cases with proc_read. + proc_commit must be called when done. */ +struct casereader * +proc_open (struct dataset *ds) +{ + return proc_open_filtering (ds, true); +} + /* Returns true if a procedure is in progress, that is, if proc_open has been called but proc_commit has not. */ bool diff --git a/src/data/procedure.h b/src/data/procedure.h index 09d44eeef6..bb4dad2b14 100644 --- a/src/data/procedure.h +++ b/src/data/procedure.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007, 2009 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -72,6 +72,7 @@ void proc_discard_output (struct dataset *ds); bool proc_execute (struct dataset *ds); time_t time_of_last_procedure (struct dataset *ds); +struct casereader *proc_open_filtering (struct dataset *, bool filter); struct casereader *proc_open (struct dataset *); bool proc_is_open (const struct dataset *); bool proc_commit (struct dataset *); diff --git a/src/language/data-io/save.c b/src/language/data-io/save.c index c34d446225..91fbc2fd3b 100644 --- a/src/language/data-io/save.c +++ b/src/language/data-io/save.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -105,7 +105,6 @@ parse_output_proc (struct lexer *lexer, struct dataset *ds, enum writer_type writer_type) { bool retain_unselected; - struct variable *saved_filter_variable; struct casewriter *output; bool ok; @@ -114,16 +113,10 @@ parse_output_proc (struct lexer *lexer, struct dataset *ds, if (output == NULL) return CMD_CASCADING_FAILURE; - saved_filter_variable = dict_get_filter (dataset_dict (ds)); - if (retain_unselected) - dict_set_filter (dataset_dict (ds), NULL); - - casereader_transfer (proc_open (ds), output); + casereader_transfer (proc_open_filtering (ds, !retain_unselected), output); ok = casewriter_destroy (output); ok = proc_commit (ds) && ok; - dict_set_filter (dataset_dict (ds), saved_filter_variable); - return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE; } diff --git a/tests/automake.mk b/tests/automake.mk index 1d2473517c..a2ceef6be9 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -419,6 +419,7 @@ EXTRA_DIST += \ TESTSUITE_AT = \ tests/data/calendar.at \ tests/language/data-io/data-list.at \ + tests/language/data-io/save.at \ tests/language/dictionary/mrsets.at \ tests/language/expressions/evaluate.at \ tests/language/stats/aggregate.at \ diff --git a/tests/language/data-io/save.at b/tests/language/data-io/save.at new file mode 100644 index 0000000000..28a186ffba --- /dev/null +++ b/tests/language/data-io/save.at @@ -0,0 +1,31 @@ +AT_BANNER([SAVE]) + +# UNSELECTED=DELETE used to cause a crash if there was actually a +# filter variable. +AT_SETUP([SAVE -- delete unselected]) +AT_DATA([data.txt], [dnl +0 '1 9:30:05' 1/2/2003 "25/8/1995 15:30:00" "'a,b,c'",0 +, '-0 5:17' 10/31/2010 "9/4/2008 9:29:00" " xxx ",1 +1.625,'0 12:00',,,xyzzy,1 +]) +AT_DATA([save.pspp], [dnl +SET DECIMAL=DOT. +DATA LIST LIST NOTABLE FILE="data.txt" + /number(F8.3) time(DTIME10) date(ADATE10) datetime(DATETIME20) string(A8) + filter(F1.0). +MISSING VALUES number(0) time('0 12:00') string('xyzzy'). +FILTER BY filter. +SAVE /OUTFILE="data.sav" /UNSELECTED=DELETE. +]) +AT_DATA([get.pspp], [dnl +GET FILE='data.sav'. +LIST. +]) +AT_CHECK([pspp -O format=csv save.pspp]) +AT_CHECK([pspp -O format=csv get.pspp], [0], [dnl +Table: Data List +number,time,date,datetime,string,filter +. ,-0 05:17,10/31/2010,09-APR-2008 09:29:00,xxx ,1 +1.625,0 12:00:00,.,.,xyzzy ,1 +]) +AT_CLEANUP