Optimise the psql reader, by fetching more than one record at a time.
[pspp-builds.git] / src / language / data-io / get-data.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007, 2008 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20
21 #include <data/gnumeric-reader.h>
22 #include <data/psql-reader.h>
23
24 #include <data/dictionary.h>
25 #include <data/format.h>
26 #include <data/procedure.h>
27 #include <language/command.h>
28 #include <language/data-io/data-parser.h>
29 #include <language/data-io/data-reader.h>
30 #include <language/data-io/file-handle.h>
31 #include <language/data-io/placement-parser.h>
32 #include <language/lexer/format-parser.h>
33 #include <language/lexer/lexer.h>
34 #include <libpspp/message.h>
35
36 #include "gettext.h"
37 #define _(msgid) gettext (msgid)
38 #define N_(msgid) (msgid)
39
40 static int parse_get_gnm (struct lexer *lexer, struct dataset *);
41 static int parse_get_txt (struct lexer *lexer, struct dataset *);
42 static int parse_get_psql (struct lexer *lexer, struct dataset *);
43
44 int
45 cmd_get_data (struct lexer *lexer, struct dataset *ds)
46 {
47   lex_force_match (lexer, '/');
48
49   if (!lex_force_match_id (lexer, "TYPE"))
50     return CMD_FAILURE;
51
52   lex_force_match (lexer, '=');
53
54   if (lex_match_id (lexer, "GNM"))
55     return parse_get_gnm (lexer, ds);
56   else if (lex_match_id (lexer, "TXT"))
57     return parse_get_txt (lexer, ds);
58   else if (lex_match_id (lexer, "PSQL"))
59     return parse_get_psql (lexer, ds);
60
61   msg (SE, _("Unsupported TYPE %s"), lex_tokid (lexer));
62   return CMD_FAILURE;
63 }
64
65 static int
66 parse_get_psql (struct lexer *lexer, struct dataset *ds)
67 {
68   struct psql_read_info psql;
69   psql.allow_clear = false;
70   psql.conninfo = NULL;
71   psql.str_width = -1;
72   psql.bsize = -1;
73   ds_init_empty (&psql.sql);
74
75   lex_force_match (lexer, '/');
76
77   if (!lex_force_match_id (lexer, "CONNECT"))
78     goto error;
79
80   lex_force_match (lexer, '=');
81
82   if (!lex_force_string (lexer))
83     goto error;
84
85   psql.conninfo = strdup (ds_cstr (lex_tokstr (lexer)));
86
87   lex_get (lexer);
88
89   while (lex_match (lexer, '/') )
90     {
91       if ( lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
92         {
93           lex_match (lexer, '=');
94           psql.str_width = lex_integer (lexer);
95           lex_get (lexer);
96         }
97       else if ( lex_match_id (lexer, "BSIZE"))
98         {
99           lex_match (lexer, '=');
100           psql.bsize = lex_integer (lexer);
101           lex_get (lexer);
102         }
103       else if ( lex_match_id (lexer, "UNENCRYPTED"))
104         {
105           psql.allow_clear = true;
106         }
107       else if (lex_match_id (lexer, "SQL"))
108         {
109           lex_match (lexer, '=');
110           if ( ! lex_force_string (lexer) )
111             goto error;
112
113           ds_put_substring (&psql.sql,  lex_tokstr (lexer)->ss);
114           lex_get (lexer);
115         }
116      }
117   {
118     struct dictionary *dict = NULL;
119     struct casereader *reader = psql_open_reader (&psql, &dict);
120
121     if ( reader )
122       proc_set_active_file (ds, reader, dict);
123   }
124
125   ds_destroy (&psql.sql);
126   free (psql.conninfo);
127
128   return CMD_SUCCESS;
129
130  error:
131
132   ds_destroy (&psql.sql);
133   free (psql.conninfo);
134
135   return CMD_FAILURE;
136 }
137
138 static int
139 parse_get_gnm (struct lexer *lexer, struct dataset *ds)
140 {
141   struct gnumeric_read_info gri  = {NULL, NULL, NULL, 1, true, -1};
142
143   lex_force_match (lexer, '/');
144
145   if (!lex_force_match_id (lexer, "FILE"))
146     goto error;
147
148   lex_force_match (lexer, '=');
149
150   if (!lex_force_string (lexer))
151     goto error;
152
153   gri.file_name = strdup (ds_cstr (lex_tokstr (lexer)));
154
155   lex_get (lexer);
156
157   while (lex_match (lexer, '/') )
158     {
159       if ( lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
160         {
161           lex_match (lexer, '=');
162           gri.asw = lex_integer (lexer);
163         }
164       else if (lex_match_id (lexer, "SHEET"))
165         {
166           lex_match (lexer, '=');
167           if (lex_match_id (lexer, "NAME"))
168             {
169               if ( ! lex_force_string (lexer) )
170                 goto error;
171
172               gri.sheet_name = strdup (ds_cstr (lex_tokstr (lexer)));
173               gri.sheet_index = -1;
174             }
175           else if (lex_match_id (lexer, "INDEX"))
176             {
177               gri.sheet_index = lex_integer (lexer);
178             }
179           else
180             goto error;
181         }
182       else if (lex_match_id (lexer, "CELLRANGE"))
183         {
184           lex_match (lexer, '=');
185
186           if (lex_match_id (lexer, "FULL"))
187             {
188               gri.cell_range = NULL;
189               lex_put_back (lexer, T_ID);
190             }
191           else if (lex_match_id (lexer, "RANGE"))
192             {
193               if ( ! lex_force_string (lexer) )
194                 goto error;
195
196               gri.cell_range = strdup (ds_cstr (lex_tokstr (lexer)));
197             }
198           else
199             goto error;
200         }
201       else if (lex_match_id (lexer, "READNAMES"))
202         {
203           lex_match (lexer, '=');
204
205           if ( lex_match_id (lexer, "ON"))
206             {
207               gri.read_names = true;
208             }
209           else if (lex_match_id (lexer, "OFF"))
210             {
211               gri.read_names = false;
212             }
213           else
214             goto error;
215           lex_put_back (lexer, T_ID);
216         }
217       else
218         {
219           printf ("Unknown data file type \"\%s\"\n", lex_tokid (lexer));
220           goto error;
221         }
222       lex_get (lexer);
223     }
224
225   {
226     struct dictionary *dict = NULL;
227     struct casereader *reader = gnumeric_open_reader (&gri, &dict);
228
229     if ( reader )
230       proc_set_active_file (ds, reader, dict);
231   }
232
233   free (gri.file_name);
234   free (gri.sheet_name);
235   free (gri.cell_range);
236   return CMD_SUCCESS;
237
238  error:
239
240   free (gri.file_name);
241   free (gri.sheet_name);
242   free (gri.cell_range);
243   return CMD_FAILURE;
244 }
245
246 static bool
247 set_type (struct data_parser *parser, const char *subcommand,
248           enum data_parser_type type, bool *has_type)
249 {
250   if (!*has_type)
251     {
252       data_parser_set_type (parser, type);
253       *has_type = true;
254     }
255   else if (type != data_parser_get_type (parser))
256     {
257       msg (SE, _("%s is allowed only with %s arrangement, but %s arrangement "
258                  "was stated or implied earlier in this command."),
259            subcommand,
260            type == DP_FIXED ? "FIXED" : "DELIMITED",
261            type == DP_FIXED ? "DELIMITED" : "FIXED");
262       return false;
263     }
264   return true;
265 }
266
267 static int
268 parse_get_txt (struct lexer *lexer, struct dataset *ds)
269 {
270   struct data_parser *parser = NULL;
271   struct dictionary *dict = NULL;
272   struct file_handle *fh = NULL;
273   struct dfm_reader *reader = NULL;
274
275   int record;
276   enum data_parser_type type;
277   bool has_type;
278
279   lex_force_match (lexer, '/');
280
281   if (!lex_force_match_id (lexer, "FILE"))
282     goto error;
283   lex_force_match (lexer, '=');
284   fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE);
285   if (fh == NULL)
286     goto error;
287
288   parser = data_parser_create ();
289   has_type = false;
290   data_parser_set_type (parser, DP_DELIMITED);
291   data_parser_set_span (parser, false);
292   data_parser_set_quotes (parser, ss_empty ());
293   data_parser_set_empty_line_has_field (parser, true);
294
295   for (;;)
296     {
297       if (!lex_force_match (lexer, '/'))
298         goto error;
299
300       if (lex_match_id (lexer, "ARRANGEMENT"))
301         {
302           bool ok;
303
304           lex_match (lexer, '=');
305           if (lex_match_id (lexer, "FIXED"))
306             ok = set_type (parser, "ARRANGEMENT=FIXED", DP_FIXED, &has_type);
307           else if (lex_match_id (lexer, "DELIMITED"))
308             ok = set_type (parser, "ARRANGEMENT=DELIMITED",
309                            DP_DELIMITED, &has_type);
310           else
311             {
312               lex_error (lexer, _("expecting FIXED or DELIMITED"));
313               goto error;
314             }
315           if (!ok)
316             goto error;
317         }
318       else if (lex_match_id (lexer, "FIRSTCASE"))
319         {
320           lex_match (lexer, '=');
321           if (!lex_force_int (lexer))
322             goto error;
323           if (lex_integer (lexer) < 1)
324             {
325               msg (SE, _("Value of FIRSTCASE must be 1 or greater."));
326               goto error;
327             }
328           data_parser_set_skip (parser, lex_integer (lexer) - 1);
329           lex_get (lexer);
330         }
331       else if (lex_match_id_n (lexer, "DELCASE", 4))
332         {
333           if (!set_type (parser, "DELCASE", DP_DELIMITED, &has_type))
334             goto error;
335           lex_match (lexer, '=');
336           if (lex_match_id (lexer, "LINE"))
337             data_parser_set_span (parser, false);
338           else if (lex_match_id (lexer, "VARIABLES"))
339             {
340               data_parser_set_span (parser, true);
341
342               /* VARIABLES takes an integer argument, but for no
343                  good reason.  We just ignore it. */
344               if (!lex_force_int (lexer))
345                 goto error;
346               lex_get (lexer);
347             }
348           else
349             {
350               lex_error (lexer, _("expecting LINE or VARIABLES"));
351               goto error;
352             }
353         }
354       else if (lex_match_id (lexer, "FIXCASE"))
355         {
356           if (!set_type (parser, "FIXCASE", DP_FIXED, &has_type))
357             goto error;
358           lex_match (lexer, '=');
359           if (!lex_force_int (lexer))
360             goto error;
361           if (lex_integer (lexer) < 1)
362             {
363               msg (SE, _("Value of FIXCASE must be at least 1."));
364               goto error;
365             }
366           data_parser_set_records (parser, lex_integer (lexer));
367           lex_get (lexer);
368         }
369       else if (lex_match_id (lexer, "IMPORTCASES"))
370         {
371           lex_match (lexer, '=');
372           if (lex_match (lexer, T_ALL))
373             {
374               data_parser_set_case_limit (parser, -1);
375               data_parser_set_case_percent (parser, 100);
376             }
377           else if (lex_match_id (lexer, "FIRST"))
378             {
379               if (!lex_force_int (lexer))
380                 goto error;
381               if (lex_integer (lexer) < 1)
382                 {
383                   msg (SE, _("Value of FIRST must be at least 1."));
384                   goto error;
385                 }
386               data_parser_set_case_limit (parser, lex_integer (lexer));
387               lex_get (lexer);
388             }
389           else if (lex_match_id (lexer, "PERCENT"))
390             {
391               if (!lex_force_int (lexer))
392                 goto error;
393               if (lex_integer (lexer) < 1 || lex_integer (lexer) > 100)
394                 {
395                   msg (SE, _("Value of PERCENT must be between 1 and 100."));
396                   goto error;
397                 }
398               data_parser_set_case_percent (parser, lex_integer (lexer));
399               lex_get (lexer);
400             }
401         }
402       else if (lex_match_id_n (lexer, "DELIMITERS", 4))
403         {
404           struct string hard_seps = DS_EMPTY_INITIALIZER;
405           const char *soft_seps = "";
406           struct substring s;
407           int c;
408
409           if (!set_type (parser, "DELIMITERS", DP_DELIMITED, &has_type))
410             goto error;
411           lex_match (lexer, '=');
412
413           if (!lex_force_string (lexer))
414             goto error;
415
416           s = ds_ss (lex_tokstr (lexer));
417           if (ss_match_string (&s, ss_cstr ("\\t")))
418             ds_put_cstr (&hard_seps, "\t");
419           if (ss_match_string (&s, ss_cstr ("\\\\")))
420             ds_put_cstr (&hard_seps, "\\");
421           while ((c = ss_get_char (&s)) != EOF)
422             if (c == ' ')
423               soft_seps = " ";
424             else
425               ds_put_char (&hard_seps, c);
426           data_parser_set_soft_delimiters (parser, ss_cstr (soft_seps));
427           data_parser_set_hard_delimiters (parser, ds_ss (&hard_seps));
428           ds_destroy (&hard_seps);
429
430           lex_get (lexer);
431         }
432       else if (lex_match_id (lexer, "QUALIFIER"))
433         {
434           if (!set_type (parser, "QUALIFIER", DP_DELIMITED, &has_type))
435             goto error;
436           lex_match (lexer, '=');
437
438           if (!lex_force_string (lexer))
439             goto error;
440
441           data_parser_set_quotes (parser, ds_ss (lex_tokstr (lexer)));
442           lex_get (lexer);
443         }
444       else if (lex_match_id (lexer, "VARIABLES"))
445         break;
446       else
447         {
448           lex_error (lexer, _("expecting VARIABLES"));
449           goto error;
450         }
451     }
452   lex_match (lexer, '=');
453
454   dict = dict_create ();
455   record = 1;
456   type = data_parser_get_type (parser);
457   do
458     {
459       char name[VAR_NAME_LEN + 1];
460       struct fmt_spec input, output;
461       int fc, lc;
462       struct variable *v;
463
464       while (type == DP_FIXED && lex_match (lexer, '/'))
465         {
466           if (!lex_force_int (lexer))
467             goto error;
468           if (lex_integer (lexer) < record)
469             {
470               msg (SE, _("The record number specified, %ld, is at or "
471                          "before the previous record, %d.  Data "
472                          "fields must be listed in order of "
473                          "increasing record number."),
474                    lex_integer (lexer), record);
475               goto error;
476             }
477           if (lex_integer (lexer) > data_parser_get_records (parser))
478             {
479               msg (SE, _("The record number specified, %ld, exceeds "
480                          "the number of records per case specified "
481                          "on FIXCASE, %d."),
482                    lex_integer (lexer), data_parser_get_records (parser));
483               goto error;
484             }
485           record = lex_integer (lexer);
486           lex_get (lexer);
487         }
488
489       if (!lex_force_id (lexer))
490         goto error;
491       strcpy (name, lex_tokid (lexer));
492       lex_get (lexer);
493
494       if (type == DP_DELIMITED)
495         {
496           if (!parse_format_specifier (lexer, &input)
497               || !fmt_check_input (&input))
498             goto error;
499         }
500       else
501         {
502           if (!parse_column_range (lexer, 0, &fc, &lc, NULL))
503             goto error;
504           if (!parse_format_specifier_name (lexer, &input.type))
505             goto error;
506           input.w = lc - fc + 1;
507           input.d = 0;
508           if (!fmt_check_input (&input))
509             goto error;
510         }
511       output = fmt_for_output_from_input (&input);
512
513       v = dict_create_var (dict, name, fmt_var_width (&input));
514       if (v == NULL)
515         {
516           msg (SE, _("%s is a duplicate variable name."), name);
517           goto error;
518         }
519       var_set_both_formats (v, &output);
520
521       if (type == DP_DELIMITED)
522         data_parser_add_delimited_field (parser, &input,
523                                          var_get_case_index (v),
524                                          name);
525       else
526         data_parser_add_fixed_field (parser, &input, var_get_case_index (v),
527                                      name, record, fc);
528     }
529   while (lex_token (lexer) != '.');
530
531   reader = dfm_open_reader (fh, lexer);
532   if (reader == NULL)
533     goto error;
534
535   data_parser_make_active_file (parser, ds, reader, dict);
536   fh_unref (fh);
537   return CMD_SUCCESS;
538
539  error:
540   data_parser_destroy (parser);
541   dict_destroy (dict);
542   fh_unref (fh);
543   return CMD_CASCADING_FAILURE;
544 }