1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #include <data/any-writer.h>
24 #include <data/case-sink.h>
25 #include <data/case.h>
26 #include <data/casefile.h>
27 #include <data/dictionary.h>
28 #include <data/file-handle-def.h>
29 #include <data/format.h>
30 #include <data/procedure.h>
31 #include <data/settings.h>
32 #include <data/storage-stream.h>
33 #include <data/sys-file-writer.h>
34 #include <data/variable.h>
35 #include <language/command.h>
36 #include <language/data-io/file-handle.h>
37 #include <language/lexer/lexer.h>
38 #include <language/lexer/variable-parser.h>
39 #include <language/stats/sort-criteria.h>
40 #include <libpspp/alloc.h>
41 #include <libpspp/assertion.h>
42 #include <libpspp/message.h>
43 #include <libpspp/misc.h>
44 #include <libpspp/pool.h>
45 #include <libpspp/str.h>
46 #include <math/moments.h>
47 #include <math/sort.h>
52 #define _(msgid) gettext (msgid)
54 /* Argument for AGGREGATE function. */
57 double f; /* Numeric. */
58 char *c; /* Short or long string. */
61 /* Specifies how to make an aggregate variable. */
64 struct agr_var *next; /* Next in list. */
66 /* Collected during parsing. */
67 const struct variable *src; /* Source variable. */
68 struct variable *dest; /* Target variable. */
69 int function; /* Function. */
70 enum mv_class exclude; /* Classes of missing values to exclude. */
71 union agr_argument arg[2]; /* Arguments. */
73 /* Accumulated during AGGREGATE execution. */
78 struct moments1 *moments;
81 /* Aggregation functions. */
84 NONE, SUM, MEAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
85 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
86 N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS,
87 FUNC = 0x1f, /* Function mask. */
88 FSTRING = 1<<5, /* String function bit. */
91 /* Attributes of an aggregation function. */
94 const char *name; /* Aggregation function name. */
95 size_t n_args; /* Number of arguments. */
96 enum var_type alpha_type; /* When given ALPHA arguments, output type. */
97 struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */
100 /* Attributes of aggregation functions. */
101 static const struct agr_func agr_func_tab[] =
103 {"<NONE>", 0, -1, {0, 0, 0}},
104 {"SUM", 0, -1, {FMT_F, 8, 2}},
105 {"MEAN", 0, -1, {FMT_F, 8, 2}},
106 {"SD", 0, -1, {FMT_F, 8, 2}},
107 {"MAX", 0, VAR_STRING, {-1, -1, -1}},
108 {"MIN", 0, VAR_STRING, {-1, -1, -1}},
109 {"PGT", 1, VAR_NUMERIC, {FMT_F, 5, 1}},
110 {"PLT", 1, VAR_NUMERIC, {FMT_F, 5, 1}},
111 {"PIN", 2, VAR_NUMERIC, {FMT_F, 5, 1}},
112 {"POUT", 2, VAR_NUMERIC, {FMT_F, 5, 1}},
113 {"FGT", 1, VAR_NUMERIC, {FMT_F, 5, 3}},
114 {"FLT", 1, VAR_NUMERIC, {FMT_F, 5, 3}},
115 {"FIN", 2, VAR_NUMERIC, {FMT_F, 5, 3}},
116 {"FOUT", 2, VAR_NUMERIC, {FMT_F, 5, 3}},
117 {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
118 {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
119 {"NMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
120 {"NUMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
121 {"FIRST", 0, VAR_STRING, {-1, -1, -1}},
122 {"LAST", 0, VAR_STRING, {-1, -1, -1}},
123 {NULL, 0, -1, {-1, -1, -1}},
124 {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
125 {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
128 /* Missing value types. */
129 enum missing_treatment
131 ITEMWISE, /* Missing values item by item. */
132 COLUMNWISE /* Missing values column by column. */
135 /* An entire AGGREGATE procedure. */
138 /* We have either an output file or a sink. */
139 struct any_writer *writer; /* Output file, or null if none. */
140 struct case_sink *sink; /* Sink, or null if none. */
142 /* Break variables. */
143 struct sort_criteria *sort; /* Sort criteria. */
144 const struct variable **break_vars; /* Break variables. */
145 size_t break_var_cnt; /* Number of break variables. */
146 struct ccase break_case; /* Last values of break variables. */
148 enum missing_treatment missing; /* How to treat missing values. */
149 struct agr_var *agr_vars; /* First aggregate variable. */
150 struct dictionary *dict; /* Aggregate dictionary. */
151 const struct dictionary *src_dict; /* Dict of the source */
152 int case_cnt; /* Counts aggregated cases. */
153 struct ccase agr_case; /* Aggregate case for output. */
156 static void initialize_aggregate_info (struct agr_proc *,
157 const struct ccase *);
160 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
162 static void agr_destroy (struct agr_proc *);
163 static bool aggregate_single_case (struct agr_proc *agr,
164 const struct ccase *input,
165 struct ccase *output);
166 static void dump_aggregate_info (struct agr_proc *agr, struct ccase *output);
170 /* Parses and executes the AGGREGATE procedure. */
172 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
174 struct dictionary *dict = dataset_dict (ds);
176 struct file_handle *out_file = NULL;
178 bool copy_documents = false;
179 bool presorted = false;
182 memset(&agr, 0 , sizeof (agr));
183 agr.missing = ITEMWISE;
184 case_nullify (&agr.break_case);
186 agr.dict = dict_create ();
188 dict_set_label (agr.dict, dict_get_label (dict));
189 dict_set_documents (agr.dict, dict_get_documents (dict));
191 /* OUTFILE subcommand must be first. */
192 if (!lex_force_match_id (lexer, "OUTFILE"))
194 lex_match (lexer, '=');
195 if (!lex_match (lexer, '*'))
197 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
198 if (out_file == NULL)
202 /* Read most of the subcommands. */
205 lex_match (lexer, '/');
207 if (lex_match_id (lexer, "MISSING"))
209 lex_match (lexer, '=');
210 if (!lex_match_id (lexer, "COLUMNWISE"))
212 lex_error (lexer, _("while expecting COLUMNWISE"));
215 agr.missing = COLUMNWISE;
217 else if (lex_match_id (lexer, "DOCUMENT"))
218 copy_documents = true;
219 else if (lex_match_id (lexer, "PRESORTED"))
221 else if (lex_match_id (lexer, "BREAK"))
225 lex_match (lexer, '=');
226 agr.sort = sort_parse_criteria (lexer, dict,
227 &agr.break_vars, &agr.break_var_cnt,
228 &saw_direction, NULL);
229 if (agr.sort == NULL)
232 for (i = 0; i < agr.break_var_cnt; i++)
233 dict_clone_var_assert (agr.dict, agr.break_vars[i],
234 var_get_name (agr.break_vars[i]));
236 /* BREAK must follow the options. */
241 lex_error (lexer, _("expecting BREAK"));
245 if (presorted && saw_direction)
246 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
247 "with (A) or (D) has no effect. Output data will be sorted "
248 "the same way as the input data."));
250 /* Read in the aggregate functions. */
251 lex_match (lexer, '/');
252 if (!parse_aggregate_functions (lexer, dict, &agr))
255 /* Delete documents. */
257 dict_clear_documents (agr.dict);
259 /* Cancel SPLIT FILE. */
260 dict_set_split_vars (agr.dict, NULL, 0);
264 case_create (&agr.agr_case, dict_get_next_value_idx (agr.dict));
266 /* Output to active file or external file? */
267 if (out_file == NULL)
271 /* The active file will be replaced by the aggregated data,
272 so TEMPORARY is moot. */
273 proc_cancel_temporary_transformations (ds);
275 if (agr.sort != NULL && !presorted)
277 if (!sort_active_file_in_place (ds, agr.sort))
281 agr.sink = create_case_sink (&storage_sink_class, agr.dict,
282 dataset_get_casefile_factory (ds),
284 if (agr.sink->class->open != NULL)
285 agr.sink->class->open (agr.sink);
287 create_case_sink (&null_sink_class, dict,
288 dataset_get_casefile_factory (ds),
291 while (proc_read (ds, &c))
292 if (aggregate_single_case (&agr, c, &agr.agr_case))
293 if (!agr.sink->class->write (agr.sink, &agr.agr_case))
298 if (!proc_close (ds))
301 if (agr.case_cnt > 0)
303 dump_aggregate_info (&agr, &agr.agr_case);
304 if (!agr.sink->class->write (agr.sink, &agr.agr_case))
307 discard_variables (ds);
308 dataset_set_dict (ds, agr.dict);
310 proc_set_source (ds, agr.sink->class->make_source (agr.sink));
311 free_case_sink (agr.sink);
315 agr.writer = any_writer_open (out_file, agr.dict);
316 if (agr.writer == NULL)
319 if (agr.sort != NULL && !presorted)
321 /* Sorting is needed. */
322 struct casefile *dst;
323 struct casereader *reader;
327 dst = sort_active_file_to_casefile (ds, agr.sort);
330 reader = casefile_get_destructive_reader (dst);
331 while (ok && casereader_read_xfer (reader, &c))
333 if (aggregate_single_case (&agr, &c, &agr.agr_case))
334 ok = any_writer_write (agr.writer, &agr.agr_case);
337 casereader_destroy (reader);
339 ok = !casefile_error (dst);
340 casefile_destroy (dst);
346 /* Active file is already sorted. */
350 while (proc_read (ds, &c))
351 if (aggregate_single_case (&agr, c, &agr.agr_case))
352 if (!any_writer_write (agr.writer, &agr.agr_case))
357 if (!proc_close (ds))
361 if (agr.case_cnt > 0)
363 dump_aggregate_info (&agr, &agr.agr_case);
364 any_writer_write (agr.writer, &agr.agr_case);
366 if (any_writer_error (agr.writer))
375 return CMD_CASCADING_FAILURE;
378 /* Parse all the aggregate functions. */
380 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, struct agr_proc *agr)
382 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
384 /* Parse everything. */
391 struct string function_name;
393 enum mv_class exclude;
394 const struct agr_func *function;
397 union agr_argument arg[2];
399 const struct variable **src;
412 ds_init_empty (&function_name);
414 /* Parse the list of target variables. */
415 while (!lex_match (lexer, '='))
417 size_t n_dest_prev = n_dest;
419 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
420 PV_APPEND | PV_SINGLE | PV_NO_SCRATCH))
423 /* Assign empty labels. */
427 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
428 for (j = n_dest_prev; j < n_dest; j++)
429 dest_label[j] = NULL;
434 if (lex_token (lexer) == T_STRING)
437 ds_init_string (&label, lex_tokstr (lexer));
439 ds_truncate (&label, 255);
440 dest_label[n_dest - 1] = ds_xstrdup (&label);
446 /* Get the name of the aggregation function. */
447 if (lex_token (lexer) != T_ID)
449 lex_error (lexer, _("expecting aggregation function"));
455 ds_assign_string (&function_name, lex_tokstr (lexer));
457 ds_chomp (&function_name, '.');
459 if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
462 for (function = agr_func_tab; function->name; function++)
463 if (!strcasecmp (function->name, ds_cstr (&function_name)))
465 if (NULL == function->name)
467 msg (SE, _("Unknown aggregation function %s."),
468 ds_cstr (&function_name));
471 ds_destroy (&function_name);
472 func_index = function - agr_func_tab;
475 /* Check for leading lparen. */
476 if (!lex_match (lexer, '('))
479 func_index = N_NO_VARS;
480 else if (func_index == NU)
481 func_index = NU_NO_VARS;
484 lex_error (lexer, _("expecting `('"));
490 /* Parse list of source variables. */
492 int pv_opts = PV_NO_SCRATCH;
494 if (func_index == SUM || func_index == MEAN || func_index == SD)
495 pv_opts |= PV_NUMERIC;
496 else if (function->n_args)
497 pv_opts |= PV_SAME_TYPE;
499 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
503 /* Parse function arguments, for those functions that
504 require arguments. */
505 if (function->n_args != 0)
506 for (i = 0; i < function->n_args; i++)
510 lex_match (lexer, ',');
511 if (lex_token (lexer) == T_STRING)
513 arg[i].c = ds_xstrdup (lex_tokstr (lexer));
516 else if (lex_is_number (lexer))
518 arg[i].f = lex_tokval (lexer);
523 msg (SE, _("Missing argument %d to %s."),
524 (int) i + 1, function->name);
530 if (type != var_get_type (src[0]))
532 msg (SE, _("Arguments to %s must be of same type as "
533 "source variables."),
539 /* Trailing rparen. */
540 if (!lex_match (lexer, ')'))
542 lex_error (lexer, _("expecting `)'"));
546 /* Now check that the number of source variables match
547 the number of target variables. If we check earlier
548 than this, the user can get very misleading error
549 message, i.e. `AGGREGATE x=SUM(y t).' will get this
550 error message when a proper message would be more
551 like `unknown variable t'. */
554 msg (SE, _("Number of source variables (%u) does not match "
555 "number of target variables (%u)."),
556 (unsigned) n_src, (unsigned) n_dest);
560 if ((func_index == PIN || func_index == POUT
561 || func_index == FIN || func_index == FOUT)
562 && (var_is_numeric (src[0])
563 ? arg[0].f > arg[1].f
564 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
566 union agr_argument t = arg[0];
570 msg (SW, _("The value arguments passed to the %s function "
571 "are out-of-order. They will be treated as if "
572 "they had been specified in the correct order."),
577 /* Finally add these to the linked list of aggregation
579 for (i = 0; i < n_dest; i++)
581 struct agr_var *v = xmalloc (sizeof *v);
583 /* Add variable to chain. */
584 if (agr->agr_vars != NULL)
592 /* Create the target variable in the aggregate
595 struct variable *destvar;
597 v->function = func_index;
603 if (var_is_alpha (src[i]))
605 v->function |= FSTRING;
606 v->string = xmalloc (var_get_width (src[i]));
609 if (function->alpha_type == VAR_STRING)
610 destvar = dict_clone_var (agr->dict, v->src, dest[i]);
613 assert (var_is_numeric (v->src)
614 || function->alpha_type == VAR_NUMERIC);
615 destvar = dict_create_var (agr->dict, dest[i], 0);
619 if ((func_index == N || func_index == NMISS)
620 && dict_get_weight (dict) != NULL)
621 f = fmt_for_output (FMT_F, 8, 2);
623 f = function->format;
624 var_set_both_formats (destvar, &f);
630 destvar = dict_create_var (agr->dict, dest[i], 0);
631 if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL)
632 f = fmt_for_output (FMT_F, 8, 2);
634 f = function->format;
635 var_set_both_formats (destvar, &f);
640 msg (SE, _("Variable name %s is not unique within the "
641 "aggregate file dictionary, which contains "
642 "the aggregate variables and the break "
650 var_set_label (destvar, dest_label[i]);
655 v->exclude = exclude;
661 if (var_is_numeric (v->src))
662 for (j = 0; j < function->n_args; j++)
663 v->arg[j].f = arg[j].f;
665 for (j = 0; j < function->n_args; j++)
666 v->arg[j].c = xstrdup (arg[j].c);
670 if (src != NULL && var_is_alpha (src[0]))
671 for (i = 0; i < function->n_args; i++)
681 if (!lex_match (lexer, '/'))
683 if (lex_token (lexer) == '.')
686 lex_error (lexer, "expecting end of command");
692 ds_destroy (&function_name);
693 for (i = 0; i < n_dest; i++)
696 free (dest_label[i]);
702 if (src && n_src && var_is_alpha (src[0]))
703 for (i = 0; i < function->n_args; i++)
716 agr_destroy (struct agr_proc *agr)
718 struct agr_var *iter, *next;
720 any_writer_close (agr->writer);
721 if (agr->sort != NULL)
722 sort_destroy_criteria (agr->sort);
723 free (agr->break_vars);
724 case_destroy (&agr->break_case);
725 for (iter = agr->agr_vars; iter; iter = next)
729 if (iter->function & FSTRING)
734 n_args = agr_func_tab[iter->function & FUNC].n_args;
735 for (i = 0; i < n_args; i++)
736 free (iter->arg[i].c);
739 else if (iter->function == SD)
740 moments1_destroy (iter->moments);
743 if (agr->dict != NULL)
744 dict_destroy (agr->dict);
746 case_destroy (&agr->agr_case);
751 static void accumulate_aggregate_info (struct agr_proc *,
752 const struct ccase *);
753 static void dump_aggregate_info (struct agr_proc *, struct ccase *);
755 /* Processes a single case INPUT for aggregation. If output is
756 warranted, writes it to OUTPUT and returns true.
757 Otherwise, returns false and OUTPUT is unmodified. */
759 aggregate_single_case (struct agr_proc *agr,
760 const struct ccase *input, struct ccase *output)
762 bool finished_group = false;
764 if (agr->case_cnt++ == 0)
765 initialize_aggregate_info (agr, input);
766 else if (case_compare (&agr->break_case, input,
767 agr->break_vars, agr->break_var_cnt))
769 dump_aggregate_info (agr, output);
770 finished_group = true;
772 initialize_aggregate_info (agr, input);
775 accumulate_aggregate_info (agr, input);
776 return finished_group;
779 /* Accumulates aggregation data from the case INPUT. */
781 accumulate_aggregate_info (struct agr_proc *agr,
782 const struct ccase *input)
784 struct agr_var *iter;
786 bool bad_warn = true;
788 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
790 for (iter = agr->agr_vars; iter; iter = iter->next)
793 const union value *v = case_data (input, iter->src);
794 int src_width = var_get_width (iter->src);
796 if (var_is_value_missing (iter->src, v, iter->exclude))
798 switch (iter->function)
801 case NMISS | FSTRING:
802 iter->dbl[0] += weight;
805 case NUMISS | FSTRING:
809 iter->saw_missing = true;
813 /* This is horrible. There are too many possibilities. */
814 switch (iter->function)
817 iter->dbl[0] += v->f * weight;
821 iter->dbl[0] += v->f * weight;
822 iter->dbl[1] += weight;
825 moments1_add (iter->moments, v->f, weight);
828 iter->dbl[0] = MAX (iter->dbl[0], v->f);
832 if (memcmp (iter->string, v->s, src_width) < 0)
833 memcpy (iter->string, v->s, src_width);
837 iter->dbl[0] = MIN (iter->dbl[0], v->f);
841 if (memcmp (iter->string, v->s, src_width) > 0)
842 memcpy (iter->string, v->s, src_width);
847 if (v->f > iter->arg[0].f)
848 iter->dbl[0] += weight;
849 iter->dbl[1] += weight;
853 if (memcmp (iter->arg[0].c, v->s, src_width) < 0)
854 iter->dbl[0] += weight;
855 iter->dbl[1] += weight;
859 if (v->f < iter->arg[0].f)
860 iter->dbl[0] += weight;
861 iter->dbl[1] += weight;
865 if (memcmp (iter->arg[0].c, v->s, src_width) > 0)
866 iter->dbl[0] += weight;
867 iter->dbl[1] += weight;
871 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
872 iter->dbl[0] += weight;
873 iter->dbl[1] += weight;
877 if (memcmp (iter->arg[0].c, v->s, src_width) <= 0
878 && memcmp (iter->arg[1].c, v->s, src_width) >= 0)
879 iter->dbl[0] += weight;
880 iter->dbl[1] += weight;
884 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
885 iter->dbl[0] += weight;
886 iter->dbl[1] += weight;
890 if (memcmp (iter->arg[0].c, v->s, src_width) > 0
891 || memcmp (iter->arg[1].c, v->s, src_width) < 0)
892 iter->dbl[0] += weight;
893 iter->dbl[1] += weight;
897 iter->dbl[0] += weight;
910 case FIRST | FSTRING:
913 memcpy (iter->string, v->s, src_width);
922 memcpy (iter->string, v->s, src_width);
926 case NMISS | FSTRING:
928 case NUMISS | FSTRING:
929 /* Our value is not missing or it would have been
930 caught earlier. Nothing to do. */
936 switch (iter->function)
939 iter->dbl[0] += weight;
950 /* We've come to a record that differs from the previous in one or
951 more of the break variables. Make an output record from the
952 accumulated statistics in the OUTPUT case. */
954 dump_aggregate_info (struct agr_proc *agr, struct ccase *output)
960 for (i = 0; i < agr->break_var_cnt; i++)
962 const struct variable *v = agr->break_vars[i];
963 size_t value_cnt = var_get_value_cnt (v);
964 memcpy (case_data_rw_idx (output, value_idx),
965 case_data (&agr->break_case, v),
966 sizeof (union value) * value_cnt);
967 value_idx += value_cnt;
974 for (i = agr->agr_vars; i; i = i->next)
976 union value *v = case_data_rw (output, i->dest);
978 if (agr->missing == COLUMNWISE && i->saw_missing
979 && (i->function & FUNC) != N && (i->function & FUNC) != NU
980 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
982 if (var_is_alpha (i->dest))
983 memset (v->s, ' ', var_get_width (i->dest));
992 v->f = i->int1 ? i->dbl[0] : SYSMIS;
995 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
1001 /* FIXME: we should use two passes. */
1002 moments1_calculate (i->moments, NULL, NULL, &variance,
1004 if (variance != SYSMIS)
1005 v->f = sqrt (variance);
1012 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1017 memcpy (v->s, i->string, var_get_width (i->dest));
1019 memset (v->s, ' ', var_get_width (i->dest));
1028 case FOUT | FSTRING:
1029 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1038 case POUT | FSTRING:
1039 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1051 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1053 case FIRST | FSTRING:
1054 case LAST | FSTRING:
1056 memcpy (v->s, i->string, var_get_width (i->dest));
1058 memset (v->s, ' ', var_get_width (i->dest));
1067 case NMISS | FSTRING:
1071 case NUMISS | FSTRING:
1081 /* Resets the state for all the aggregate functions. */
1083 initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
1085 struct agr_var *iter;
1087 case_destroy (&agr->break_case);
1088 case_clone (&agr->break_case, input);
1090 for (iter = agr->agr_vars; iter; iter = iter->next)
1092 iter->saw_missing = false;
1093 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1094 iter->int1 = iter->int2 = 0;
1095 switch (iter->function)
1098 iter->dbl[0] = DBL_MAX;
1101 memset (iter->string, 255, var_get_width (iter->src));
1104 iter->dbl[0] = -DBL_MAX;
1107 memset (iter->string, 0, var_get_width (iter->src));
1110 if (iter->moments == NULL)
1111 iter->moments = moments1_create (MOMENT_VARIANCE);
1113 moments1_clear (iter->moments);