SAVE: Fix UNSELECTED=RETAIN with a filter variable.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 7 Aug 2010 20:47:33 +0000 (13:47 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 9 Aug 2010 17:59:05 +0000 (10:59 -0700)
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.

src/data/procedure.c
src/data/procedure.h
src/language/data-io/save.c
tests/automake.mk
tests/language/data-io/save.at [new file with mode: 0644]

index c79e784e8b70f4d7ced4cabf5414cd76d8baca8c..fa52806f60f6795154234af340b8226f95f5172d 100644 (file)
@@ -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
index 09d44eeef612bdda52072acbf8be40a8982f9a46..bb4dad2b14ac91528c13be0e5455c6bcf7e1f362 100644 (file)
@@ -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 *);
index c34d446225bd250a76687ef736aeed697d7027be..91fbc2fd3bfcb6f6a55ff202698f9c237f52e853 100644 (file)
@@ -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;
 }
 
index 1d2473517c3e81ac9e039e7a96ee9fdd1fda0271..a2ceef6be9707c84e8c669cd7a945586e3e9b169 100644 (file)
@@ -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 (file)
index 0000000..28a186f
--- /dev/null
@@ -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