From: Ben Pfaff Date: Thu, 13 Jun 2013 07:03:51 +0000 (-0700) Subject: INPUT PROGRAM: Use a separate dataset for the input program. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3b07fccffef73bba4bb1839fced20554df75901e;p=pspp INPUT PROGRAM: Use a separate dataset for the input program. 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. --- diff --git a/src/data/session.c b/src/data/session.c index c6f5031a53..56aa31a91c 100644 --- a/src/data/session.c +++ b/src/data/session.c @@ -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 * diff --git a/src/data/session.h b/src/data/session.h index b61c394677..8b20b0019b 100644 --- a/src/data/session.h +++ b/src/data/session.h @@ -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 *); diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index 7229d56d48..a500df4117 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -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); diff --git a/src/ui/gui/psppire-data-window.c b/src/ui/gui/psppire-data-window.c index 23f89a3b8c..d9488b3549 100644 --- a/src/ui/gui/psppire-data-window.c +++ b/src/ui/gui/psppire-data-window.c @@ -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) { diff --git a/src/ui/terminal/main.c b/src/ui/terminal/main.c index 3f4139b85d..6e573d5cca 100644 --- a/src/ui/terminal/main.c +++ b/src/ui/terminal/main.c @@ -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 (); diff --git a/tests/language/data-io/inpt-pgm.at b/tests/language/data-io/inpt-pgm.at index 480c83f1b1..f5498855a7 100644 --- a/tests/language/data-io/inpt-pgm.at +++ b/tests/language/data-io/inpt-pgm.at @@ -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