INPUT PROGRAM: Use a separate dataset for the input program. 20130613010503/pspp 20130614010504/pspp 20130615010505/pspp 20130616010503/pspp
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 13 Jun 2013 07:03:51 +0000 (00:03 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 13 Jun 2013 07:07:13 +0000 (00:07 -0700)
Without this change, INPUT PROGRAM uses the same dataset as the following
syntax.  This usually is fine, but there's at least one case where it
doesn't work: if the INPUT PROGRAM defines a vector, then a following
proc_execute() without any intervening transformations causes
proc_execute() to follow a "fast path" where it skips running the procedure
but instead just does a few things, like clearing the set of vectors.
Unfortunately, this means that later when the input program is really run,
  it doesn't have the vectors and accesses freed memory.

This commit switches to a different tactic.  INPUT PROGRAM creates a
special session and dataset that are used only for the input program.  This
keeps the dataset and the transformations used for the input program
separate from those used after the input program.

Bug #39097.
Reported by John Darrington.

src/data/session.c
src/data/session.h
src/language/data-io/inpt-pgm.c
src/ui/gui/psppire-data-window.c
src/ui/terminal/main.c
tests/language/data-io/inpt-pgm.at

index c6f5031a5379e79a33cd84e6428b3d8ed2eeca1a..56aa31a91cd581036890e312c04bb83bdd30de5b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011, 2012, 2013 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
@@ -33,6 +33,7 @@
 
 struct session
   {
+    struct session *parent;
     struct hmapx datasets;
     struct dataset *active;
     char *syntax_encoding;      /* Default encoding for syntax files. */
@@ -43,14 +44,16 @@ static struct hmapx_node *session_lookup_dataset__ (const struct session *,
                                                     const char *name);
 
 struct session *
-session_create (void)
+session_create (struct session *parent)
 {
   struct session *s;
 
   s = xmalloc (sizeof *s);
+  s->parent = parent;
   hmapx_init (&s->datasets);
   s->active = NULL;
-  s->syntax_encoding = xstrdup ("Auto");
+  s->syntax_encoding = xstrdup (s->parent != NULL
+                                ? s->parent->syntax_encoding : "Auto");
   s->n_dataset_names = 0;
   return s;
 }
@@ -115,7 +118,9 @@ struct dataset *
 session_lookup_dataset (const struct session *s, const char *name)
 {
   struct hmapx_node *node = session_lookup_dataset__ (s, name);
-  return node != NULL ? node->data : NULL;
+  return (node != NULL ? node->data
+          : s->parent != NULL ? session_lookup_dataset (s->parent, name)
+          : NULL);
 }
 
 struct dataset *
index b61c3946772ca8af99653f289d0bd05f4a72aa42..8b20b0019b8ea7181796fcffab3e547eea99dced 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011, 2012, 2013 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
@@ -21,7 +21,7 @@
 
 struct dataset;
 
-struct session *session_create (void);
+struct session *session_create (struct session *parent);
 void session_destroy (struct session *);
 
 struct dataset *session_active_dataset (struct session *);
index 7229d56d485ee164f5fc75ff96865c4a71f956b8..a500df4117130f4ae0ce808b3a1ccd6a209f8b28 100644 (file)
@@ -24,6 +24,7 @@
 #include "data/casereader-provider.h"
 #include "data/dataset.h"
 #include "data/dictionary.h"
+#include "data/session.h"
 #include "data/transformations.h"
 #include "data/variable.h"
 #include "language/command.h"
@@ -46,6 +47,8 @@
 /* Indicates how a `union value' should be initialized. */
 struct input_program_pgm
   {
+    struct session *session;
+    struct dataset *ds;
     struct trns_chain *trns_chain;
     enum trns_result restart;
 
@@ -88,11 +91,12 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
   bool saw_END_FILE = false;
   bool saw_DATA_LIST = false;
 
-  dataset_clear (ds);
   if (!lex_match (lexer, T_ENDCMD))
     return lex_end_of_command (lexer);
 
   inp = xmalloc (sizeof *inp);
+  inp->session = session_create (dataset_session (ds));
+  inp->ds = dataset_create (inp->session, "INPUT PROGRAM");
   inp->trns_chain = NULL;
   inp->init = NULL;
   inp->proto = NULL;
@@ -102,7 +106,7 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
     {
       enum cmd_result result;
 
-      result = cmd_parse_in_state (lexer, ds, CMD_STATE_INPUT_PROGRAM);
+      result = cmd_parse_in_state (lexer, inp->ds, CMD_STATE_INPUT_PROGRAM);
       switch (result)
         {
         case CMD_DATA_LIST:
@@ -110,7 +114,7 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
           break;
 
         case CMD_END_CASE:
-          emit_END_CASE (ds, inp);
+          emit_END_CASE (inp->ds, inp);
           saw_END_CASE = true;
           break;
 
@@ -128,41 +132,39 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
               if (result == CMD_EOF)
                 msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
               inside_input_program = false;
-              dataset_clear (ds);
               destroy_input_program (inp);
               return result;
             }
         }
     }
   if (!saw_END_CASE)
-    emit_END_CASE (ds, inp);
+    emit_END_CASE (inp->ds, inp);
   inside_input_program = false;
 
   if (!saw_DATA_LIST && !saw_END_FILE)
     {
       msg (SE, _("Input program must contain DATA LIST or END FILE."));
-      dataset_clear (ds);
       destroy_input_program (inp);
       return CMD_FAILURE;
     }
-  if (dict_get_next_value_idx (dataset_dict (ds)) == 0)
+  if (dict_get_next_value_idx (dataset_dict (inp->ds)) == 0)
     {
       msg (SE, _("Input program did not create any variables."));
-      dataset_clear (ds);
       destroy_input_program (inp);
       return CMD_FAILURE;
     }
 
-  inp->trns_chain = proc_capture_transformations (ds);
+  inp->trns_chain = proc_capture_transformations (inp->ds);
   trns_chain_finalize (inp->trns_chain);
 
   inp->restart = TRNS_CONTINUE;
 
   /* Figure out how to initialize each input case. */
   inp->init = caseinit_create ();
-  caseinit_mark_for_init (inp->init, dataset_dict (ds));
-  inp->proto = caseproto_ref (dict_get_proto (dataset_dict (ds)));
+  caseinit_mark_for_init (inp->init, dataset_dict (inp->ds));
+  inp->proto = caseproto_ref (dict_get_proto (dataset_dict (inp->ds)));
 
+  dataset_set_dict (ds, dict_clone (dataset_dict (inp->ds)));
   dataset_set_source (
     ds, casereader_create_sequential (NULL, inp->proto, CASENUMBER_MAX,
                                       &input_program_casereader_class, inp));
@@ -227,6 +229,7 @@ destroy_input_program (struct input_program_pgm *pgm)
 {
   if (pgm != NULL)
     {
+      session_destroy (pgm->session);
       trns_chain_destroy (pgm->trns_chain);
       caseinit_destroy (pgm->init);
       caseproto_unref (pgm->proto);
index 23f89a3b8c5fb76559087519f341d7b9420a29bd..d9488b354990c6b4135a7db9cbe7d75a0de9402a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010, 2011, 2012  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013  Free Software Foundation
 
    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
@@ -1239,7 +1239,7 @@ psppire_data_window_new (struct dataset *ds)
   GtkWidget *dw;
 
   if (the_session == NULL)
-    the_session = session_create ();
+    the_session = session_create (NULL);
 
   if (ds == NULL)
     {
index 3f4139b85d377dc8b5dc3254a5c0d5e4a166df2f..6e573d5cca90bd770e0eac4e33a24ccc1a7cf530 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-2000, 2006-2007, 2009-2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-2000, 2006-2007, 2009-2013 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
@@ -96,7 +96,7 @@ main (int argc, char **argv)
   random_init ();
 
   lexer = lex_create ();
-  the_session = session_create ();
+  the_session = session_create (NULL);
   dataset_create (the_session, "");
 
   parser = argv_parser_create ();
index 480c83f1b12b48c39225ba938d42b52950ae561d..f5498855a75ea63365540ca45a00d71e7bcf8f87 100644 (file)
@@ -46,3 +46,37 @@ input-program.sps:3: error: Input program must contain DATA LIST or END FILE.
 input-program.sps:4: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined.
 ])
 AT_CLEANUP
+
+dnl Tests for bug #39097, a bug when an INPUT PROGRAM used VECTOR, was
+dnl followed immediately by a call to proc_execute() (here via DATASET
+dnl COPY), and then the input was actually used.
+AT_SETUP([INPUT PROGRAM with VECTOR and EXECUTE])
+AT_DATA([input-program.sps], [dnl
+INPUT PROGRAM.
+VECTOR vec(5).
+LOOP #c = 1 to 10.
+ LOOP #v = 1 to 5.
+  COMPUTE vec(#v) = #v.
+ END LOOP.
+ END CASE.
+END LOOP.
+END FILE.
+END INPUT PROGRAM.
+DATASET COPY x.
+LIST.
+])
+AT_CHECK([pspp -O format=csv input-program.sps], [0], [dnl
+Table: Data List
+vec1,vec2,vec3,vec4,vec5
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+1.00,2.00,3.00,4.00,5.00
+])
+AT_CLEANUP