1 /* -*- mode: C -*-
2  *
3  *       File:         rec-rset.c
4  *       Date:         Thu Mar  5 18:12:10 2009
5  *
6  *       GNU recutils - Record Sets
7  *
8  */
9 
10 /* Copyright (C) 2009-2019 Jose E. Marchesi */
11 
12 /* This program is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include <config.h>
27 
28 #include <stdlib.h>
29 #include <stdint.h>
30 #include <errno.h>
31 #include <locale.h>
32 #include <string.h>
33 #include <parse-datetime.h>
34 
35 #if defined UUID_TYPE
36 #  include <uuid/uuid.h>
37 #endif
38 
39 #include <rec.h>
40 #include <rec-utils.h>
41 
42 /* Record Set Data Structures.
43  *
44  * A record set is a set of zero or more non-special records
45  * intermixed with comments, maybe preceded by a record descriptor.
46  */
47 
48 /* The fprops structure contains useful properties associated with
49    fields.  Those properties are usually extracted from the record
50    descriptor of the rset.  */
51 
52 struct rec_rset_fprops_s
53 {
54   char *fname;
55 
56   bool key_p;          /* Primary key  */
57   bool auto_p;         /* Auto-field.  */
58 #if defined REC_CRYPT_SUPPORT
59   bool confidential_p; /* Confidential field.  */
60 #endif
61   rec_type_t type; /* The field has an anonymous type.  */
62   char *type_name; /* The field has a type in the types registry.  */
63 
64   struct rec_rset_fprops_s *next;
65 };
66 
67 typedef struct rec_rset_fprops_s *rec_rset_fprops_t;
68 
69 /* The rec_rset_s structure contains the data associated with a record
70    set.  */
71 
72 struct rec_rset_s
73 {
74   rec_record_t descriptor;
75   size_t descriptor_pos; /* Position of the descriptor into the record
76                             set.  Some comments can appear before the
77                             record descriptor in the rec file, so we
78                             need to track it in order to write back
79                             the record properly.  */
80 
81   /* Field properties.  */
82   rec_rset_fprops_t field_props;
83 
84   /* Type registry.  */
85   rec_type_reg_t type_reg;
86 
87   /* Simple fex containing the fields to use for ordering the records
88      of this record descriptor.  */
89   rec_fex_t order_by_fields;
90 
91   /* Size constraints.  */
92   size_t min_size;
93   size_t max_size;
94 
95   /* Sex-driven constraints.  */
96   rec_sex_t *constraints;
97   size_t num_constraints;
98 
99   /* Storage for records and comments.  */
100   int record_type;
101   int comment_type;
102   rec_mset_t mset;
103 };
104 
105 /* Static functions implemented below.  */
106 
107 static void rec_rset_init (rec_rset_t rset);
108 
109 static void rec_rset_update_types (rec_rset_t rset);
110 static void rec_rset_update_field_props (rec_rset_t rset);
111 static void rec_rset_update_size_constraints (rec_rset_t rset);
112 static void rec_rset_update_sex_constraints (rec_rset_t rset);
113 
114 static bool rec_rset_record_equal_fn (void *data1, void *data2);
115 static void rec_rset_record_disp_fn (void *data);
116 static void *rec_rset_record_dup_fn (void *data);
117 static int  rec_rset_record_compare_fn (void *data1, void *data2, int type1);
118 
119 static bool rec_rset_comment_equal_fn (void *data1, void *data2);
120 static void rec_rset_comment_disp_fn (void *data);
121 static void *rec_rset_comment_dup_fn (void *data);
122 static int  rec_rset_comment_compare_fn (void *data1, void *data2, int type2);
123 
124 static bool rec_rset_type_field_p (const char *str);
125 static rec_fex_t rec_rset_type_field_fex (const char *str);
126 static char *rec_rset_type_field_type (const char *str);
127 
128 static rec_rset_fprops_t rec_rset_get_props (rec_rset_t rset,
129                                              const char *fname,
130                                              bool create_p);
131 
132 static bool rec_rset_add_auto_field_int (rec_rset_t rset,
133                                          const char *field_name,
134                                          rec_record_t record);
135 static bool rec_rset_add_auto_field_date (rec_rset_t rset,
136                                           const char *field_name,
137                                           rec_record_t record);
138 
139 #if defined UUID_TYPE
140 static bool rec_rset_add_auto_field_uuid (rec_rset_t rset,
141                                           const char *field_name,
142                                           rec_record_t record);
143 #endif
144 
145 static rec_record_t rec_rset_merge_records (rec_record_t to_record,
146                                             rec_record_t from_record,
147                                             rec_fex_t excluded_fields);
148 
149 static int rec_rset_compare_typed_records (rec_rset_t rset,
150                                            rec_record_t record1,
151                                            rec_record_t record2,
152                                            rec_fex_t fields);
153 
154 
155 /* The following macro is used by some functions to reduce
156    verbosity.  */
157 
158 #define FNAME(id) rec_std_field_name ((id))
159 
160 /*
161  * Public functions.
162  */
163 
164 rec_rset_t
rec_rset_new(void)165 rec_rset_new (void)
166 {
167   rec_rset_t rset;
168 
169   rset = malloc (sizeof (struct rec_rset_s));
170   if (rset)
171     {
172       rec_rset_init (rset);
173 
174       /* Create the mset.  */
175       rset->mset = rec_mset_new ();
176       if (rset->mset)
177         {
178           /* No descriptor, initially.  */
179           rset->descriptor = NULL;
180           rset->descriptor_pos = 0;
181           rset->min_size = 0;
182           rset->max_size = SIZE_MAX;
183           rset->constraints = NULL;
184           rset->num_constraints = 0;
185 
186           /* Create an empty type registry.  */
187           rset->type_reg = rec_type_reg_new ();
188           if (!rset->type_reg)
189             {
190               /* Out of memory.  */
191               rec_rset_destroy (rset);
192               return NULL;
193             }
194 
195           /* No field properties, initially.  */
196           rset->field_props = NULL;
197 
198           /* No order by field, initially.  */
199           rset->order_by_fields = NULL;
200 
201           /* register the types.  See rec.h for the definition of
202              MSET_COMMENT and MSET_RECORD.  */
203 
204           rset->record_type = rec_mset_register_type (rset->mset,
205                                                       "record",
206                                                       rec_rset_record_disp_fn,
207                                                       rec_rset_record_equal_fn,
208                                                       rec_rset_record_dup_fn,
209                                                       rec_rset_record_compare_fn);
210           rset->comment_type = rec_mset_register_type (rset->mset,
211                                                        "comment",
212                                                        rec_rset_comment_disp_fn,
213                                                        rec_rset_comment_equal_fn,
214                                                        rec_rset_comment_dup_fn,
215                                                        rec_rset_comment_compare_fn);
216         }
217       else
218         {
219           /* Out of memory.  */
220 
221           rec_rset_destroy (rset);
222           rset = NULL;
223         }
224     }
225 
226   return rset;
227 }
228 
229 void
rec_rset_destroy(rec_rset_t rset)230 rec_rset_destroy (rec_rset_t rset)
231 {
232   rec_rset_fprops_t props, aux = NULL;
233   size_t i = 0;
234 
235   if (rset)
236     {
237       rec_record_destroy (rset->descriptor);
238       rec_type_reg_destroy (rset->type_reg);
239 
240       for (i = 0; i < rset->num_constraints; i++)
241         {
242           rec_sex_destroy (rset->constraints[i]);
243         }
244       free (rset->constraints);
245 
246       props = rset->field_props;
247       while (props)
248         {
249           aux = props;
250 
251           if (aux->type)
252             {
253               rec_type_destroy (aux->type);
254             }
255           free (aux->fname);
256           free (aux->type_name);
257           props = props->next;
258           free (aux);
259         }
260 
261       rec_fex_destroy (rset->order_by_fields);
262 
263       rec_mset_destroy (rset->mset);
264       free (rset);
265     }
266 }
267 
268 rec_rset_t
rec_rset_dup(rec_rset_t rset)269 rec_rset_dup (rec_rset_t rset)
270 {
271   rec_rset_t new = NULL;
272 
273   new = malloc (sizeof (struct rec_rset_s));
274   if (new)
275     {
276       rec_rset_init (new);
277 
278       new->record_type = rset->record_type;
279       new->comment_type = rset->comment_type;
280       new->mset = NULL;
281       new->min_size = rset->min_size;
282       new->max_size = rset->max_size;
283       /* XXX: make copies of the following structures.  */
284       new->type_reg = NULL;
285       new->field_props = NULL;
286       new->constraints = NULL;
287       new->num_constraints = 0;
288 
289       if (rset->order_by_fields)
290         {
291           new->order_by_fields = rec_fex_dup (rset->order_by_fields);
292           if (!new->order_by_fields)
293             {
294               /* Out of memory.  */
295               rec_rset_destroy (new);
296               return NULL;
297             }
298         }
299     }
300 
301   new->mset = rec_mset_dup (rset->mset);
302   if (!new->mset)
303     {
304       /* Out of memory.  */
305       rec_rset_destroy (new);
306       return NULL;
307     }
308 
309   return new;
310 }
311 
312 rec_mset_t
rec_rset_mset(rec_rset_t rset)313 rec_rset_mset (rec_rset_t rset)
314 {
315   return rset->mset;
316 }
317 
318 size_t
rec_rset_num_elems(rec_rset_t rset)319 rec_rset_num_elems (rec_rset_t rset)
320 {
321   return rec_mset_count (rset->mset, MSET_ANY);
322 }
323 
324 size_t
rec_rset_num_records(rec_rset_t rset)325 rec_rset_num_records (rec_rset_t rset)
326 {
327   return rec_mset_count (rset->mset, rset->record_type);
328 }
329 
330 size_t
rec_rset_num_comments(rec_rset_t rset)331 rec_rset_num_comments (rec_rset_t rset)
332 {
333   return rec_mset_count (rset->mset, rset->comment_type);
334 }
335 
336 rec_record_t
rec_rset_descriptor(rec_rset_t rset)337 rec_rset_descriptor (rec_rset_t rset)
338 {
339   return rset->descriptor;
340 }
341 
342 void
rec_rset_set_descriptor(rec_rset_t rset,rec_record_t record)343 rec_rset_set_descriptor (rec_rset_t rset, rec_record_t record)
344 {
345   if (rset->descriptor)
346     {
347       rec_record_destroy (rset->descriptor);
348       rset->descriptor = NULL;
349     }
350   rset->descriptor = record;
351 
352   /* Update the types registry and the auto fields.  */
353   rec_rset_update_types (rset);
354   rec_rset_update_field_props (rset);
355   rec_rset_update_size_constraints (rset);
356   rec_rset_update_sex_constraints (rset);
357 }
358 
359 size_t
rec_rset_descriptor_pos(rec_rset_t rset)360 rec_rset_descriptor_pos (rec_rset_t rset)
361 {
362   return rset->descriptor_pos;
363 }
364 
365 void
rec_rset_set_descriptor_pos(rec_rset_t rset,size_t position)366 rec_rset_set_descriptor_pos (rec_rset_t rset,
367                              size_t position)
368 {
369   rset->descriptor_pos = position;
370 }
371 
372 void
rec_rset_set_type(rec_rset_t rset,const char * type)373 rec_rset_set_type (rec_rset_t rset,
374                    const char *type)
375 {
376   rec_field_t rec_field;
377 
378   if (!type)
379     {
380       /* This is a no-op for the default record set.  */
381       return;
382     }
383 
384   if (!rset->descriptor)
385     {
386       /* Create a record descriptor.  */
387       rset->descriptor = rec_record_new ();
388 
389     }
390 
391   rec_field = rec_record_get_field_by_name (rset->descriptor,
392                                             FNAME(REC_FIELD_REC),
393                                             0);
394 
395   if (rec_field)
396     {
397       rec_field_set_value (rec_field, type);
398     }
399   else
400     {
401       rec_field = rec_field_new (FNAME(REC_FIELD_REC), type);
402       rec_mset_append (rec_record_mset (rset->descriptor), MSET_FIELD, (void *) rec_field, MSET_FIELD);
403     }
404 }
405 
406 char *
rec_rset_type(rec_rset_t rset)407 rec_rset_type (rec_rset_t rset)
408 {
409   char *res;
410   rec_field_t field;
411 
412   res = NULL;
413   if (rset->descriptor)
414     {
415       field = rec_record_get_field_by_name (rset->descriptor,
416                                             FNAME(REC_FIELD_REC),
417                                             0);
418       if (field)
419         {
420           res = rec_extract_type (rec_field_value (field));
421         }
422     }
423 
424   return res;
425 }
426 
427 char *
rec_rset_url(rec_rset_t rset)428 rec_rset_url (rec_rset_t rset)
429 {
430   char *res;
431   rec_field_t field;
432 
433   res = NULL;
434   if (rset->descriptor)
435     {
436       field = rec_record_get_field_by_name (rset->descriptor,
437                                             FNAME(REC_FIELD_REC),
438                                             0);
439       if (field)
440         {
441           res = rec_extract_url (rec_field_value (field));
442         }
443     }
444 
445   return res;
446 }
447 
448 rec_type_reg_t
rec_rset_get_type_reg(rec_rset_t rset)449 rec_rset_get_type_reg (rec_rset_t rset)
450 {
451   return rset->type_reg;
452 }
453 
454 void
rec_rset_rename_field(rec_rset_t rset,const char * field_name,const char * new_field_name)455 rec_rset_rename_field (rec_rset_t rset,
456                        const char *field_name,
457                        const char *new_field_name)
458 {
459   size_t j;
460   rec_record_t descriptor;
461   rec_fex_t fex;
462   char *fex_str;
463   char *type_str;
464   rec_buf_t buf;
465   char *result;
466   size_t result_size;
467   rec_fex_elem_t fex_elem;
468   const char *fex_fname;
469 
470   descriptor = rec_rset_descriptor (rset);
471   if (descriptor)
472     {
473       rec_mset_t descriptor_mset = rec_record_mset (descriptor);
474       rec_mset_iterator_t iter = rec_mset_iterator (descriptor_mset);
475       rec_field_t field;
476 
477       while (rec_mset_iterator_next (&iter, MSET_FIELD, (void *) &field, NULL))
478         {
479           if (rec_field_name_equal_p (rec_field_name (field), FNAME(REC_FIELD_TYPE)))
480             {
481               /* Process a %type entry.  Invalid entries are
482                  skipped.  */
483               if (!rec_rset_type_field_p (rec_field_value (field)))
484                 {
485                   continue;
486                 }
487 
488               fex = rec_rset_type_field_fex (rec_field_value (field));
489               if (fex)
490                 {
491                   for (j = 0; j < rec_fex_size (fex); j++)
492                     {
493                       fex_elem = rec_fex_get (fex, j);
494                       fex_fname = rec_fex_elem_field_name (fex_elem);
495                       if (rec_field_name_equal_p (field_name, fex_fname))
496                         {
497                           /* Replace it with new_field_name.  */
498                           rec_fex_elem_set_field_name (fex_elem, new_field_name);
499                         }
500                     }
501 
502                   fex_str = rec_fex_str (fex, REC_FEX_CSV);
503                   type_str = rec_rset_type_field_type (rec_field_value (field));
504 
505                   buf = rec_buf_new (&result, &result_size);
506                   rec_buf_puts (fex_str, buf);
507                   rec_buf_putc (' ', buf);
508                   rec_buf_puts (type_str, buf);
509                   rec_buf_close (buf);
510 
511                   rec_field_set_value (field, result);
512 
513                   free (fex_str);
514                   free (type_str);
515                   rec_fex_destroy (fex);
516                 }
517             }
518           else if (rec_field_name_equal_p (rec_field_name (field), FNAME(REC_FIELD_KEY))
519                    || rec_field_name_equal_p (rec_field_name (field), FNAME(REC_FIELD_MANDATORY))
520                    || rec_field_name_equal_p (rec_field_name (field), FNAME(REC_FIELD_UNIQUE))
521                    || rec_field_name_equal_p (rec_field_name (field), FNAME(REC_FIELD_PROHIBIT))
522 #if defined REC_CRYPT_SUPPORT
523                    || rec_field_name_equal_p (rec_field_name (field), FNAME(REC_FIELD_CONFIDENTIAL))
524 #endif
525                    || rec_field_name_equal_p (rec_field_name (field), FNAME(REC_FIELD_SORT)))
526             {
527               /* Rename the field in the fex expression that is the
528                  value of the field.  Skip invalid entries.  */
529               fex = rec_fex_new (rec_field_value (field), REC_FEX_SIMPLE);
530               if (fex)
531                 {
532                   for (j = 0; j < rec_fex_size (fex); j++)
533                     {
534                       fex_elem = rec_fex_get (fex, j);
535 
536                       fex_fname = rec_fex_elem_field_name (fex_elem);
537                       if (rec_field_name_equal_p (field_name, fex_fname))
538                         {
539                           /* Replace it with new_field_name.  */
540                           rec_fex_elem_set_field_name (fex_elem, new_field_name);
541                         }
542                     }
543 
544                   fex_str = rec_fex_str (fex, REC_FEX_SIMPLE);
545                   rec_field_set_value (field, fex_str);
546                   free (fex_str);
547                 }
548             }
549         }
550 
551       rec_mset_iterator_free (&iter);
552     }
553 
554   /* Update the types registry.  */
555   rec_rset_update_field_props (rset);
556 }
557 
558 const char *
rec_rset_key(rec_rset_t rset)559 rec_rset_key (rec_rset_t rset)
560 {
561   const char *key = NULL;
562   rec_rset_fprops_t props = rset->field_props;
563 
564   while (props)
565     {
566       if (props->key_p)
567         {
568           /* There must be only one field marked as key.  */
569           key = props->fname;
570           break;
571         }
572       props = props->next;
573     }
574 
575   return key;
576 }
577 
578 rec_fex_t
rec_rset_auto(rec_rset_t rset)579 rec_rset_auto (rec_rset_t rset)
580 {
581   rec_fex_t fex;
582   rec_rset_fprops_t props;
583 
584   fex = rec_fex_new (NULL, REC_FEX_SIMPLE);
585 
586   props = rset->field_props;
587   while (props)
588     {
589       if (props->auto_p)
590         {
591           rec_fex_append (fex,
592                           props->fname,
593                           -1, -1);
594         }
595       props = props->next;
596     }
597 
598   return fex;
599 }
600 
601 #if defined REC_CRYPT_SUPPORT
602 
603 bool
rec_rset_field_confidential_p(rec_rset_t rset,const char * field_name)604 rec_rset_field_confidential_p (rec_rset_t rset,
605                                const char *field_name)
606 {
607   rec_fex_t fex;
608   size_t fex_size;
609   size_t i;
610   bool result = false;
611   const char *fex_field_name;
612 
613   fex = rec_rset_confidential (rset);
614   fex_size = rec_fex_size (fex);
615 
616   for (i = 0; i < fex_size; i++)
617     {
618       fex_field_name = rec_fex_elem_field_name (rec_fex_get (fex, i));
619       if (rec_field_name_equal_p (field_name, fex_field_name))
620         {
621           result = true;
622           break;
623         }
624     }
625 
626   return result;
627 }
628 
629 rec_fex_t
rec_rset_confidential(rec_rset_t rset)630 rec_rset_confidential (rec_rset_t rset)
631 {
632   rec_fex_t fex;
633   rec_rset_fprops_t props;
634 
635   fex = rec_fex_new (NULL, REC_FEX_SIMPLE);
636 
637   props = rset->field_props;
638   while (props)
639     {
640       if (props->confidential_p)
641         {
642           rec_fex_append (fex,
643                           props->fname,
644                           -1, -1);
645         }
646 
647       props = props->next;
648     }
649 
650   return fex;
651 }
652 
653 #endif /* REC_CRYPT_SUPPORT */
654 
655 rec_type_t
rec_rset_get_field_type(rec_rset_t rset,const char * field_name)656 rec_rset_get_field_type (rec_rset_t rset,
657                          const char *field_name)
658 {
659   rec_type_t type = NULL;
660   rec_rset_fprops_t props = NULL;
661 
662   props = rec_rset_get_props (rset, field_name, false);
663   if (props)
664     {
665       type = props->type;
666       if (!type && props->type_name)
667         {
668           type = rec_type_reg_get (rset->type_reg, props->type_name);
669         }
670     }
671 
672   return type;
673 }
674 
675 size_t
rec_rset_min_records(rec_rset_t rset)676 rec_rset_min_records (rec_rset_t rset)
677 {
678   return rset->min_size;
679 }
680 
681 size_t
rec_rset_max_records(rec_rset_t rset)682 rec_rset_max_records (rec_rset_t rset)
683 {
684   return rset->max_size;
685 }
686 
687 char *
rec_rset_source(rec_rset_t rset)688 rec_rset_source (rec_rset_t rset)
689 {
690   rec_record_t record;
691 
692   /* The source of the record set is considered to be the source of
693      its first record: either the descriptor or some other record.  */
694 
695   record = rec_rset_descriptor (rset);
696   if (!record)
697     {
698       record = (rec_record_t) rec_mset_get_at (rset->mset, MSET_RECORD, 0);
699     }
700 
701   return rec_record_source (record);
702 }
703 
704 
705 bool
rec_rset_set_order_by_fields(rec_rset_t rset,rec_fex_t field_names)706 rec_rset_set_order_by_fields (rec_rset_t rset,
707                               rec_fex_t field_names)
708 {
709   rec_fex_destroy (rset->order_by_fields);
710   rset->order_by_fields = rec_fex_dup (field_names);
711   return (rset->order_by_fields != NULL);
712 }
713 
714 rec_fex_t
rec_rset_order_by_fields(rec_rset_t rset)715 rec_rset_order_by_fields (rec_rset_t rset)
716 {
717   return rset->order_by_fields;
718 }
719 
720 rec_rset_t
rec_rset_sort(rec_rset_t rset,rec_fex_t sort_by)721 rec_rset_sort (rec_rset_t rset,
722                rec_fex_t sort_by)
723 {
724   if (sort_by)
725     {
726       rec_rset_set_order_by_fields (rset, sort_by);
727     }
728 
729   if (rset->order_by_fields)
730     {
731       /* Duplicate the multi-set indicating that the elements must be
732          sorted.  */
733 
734       if (!rec_mset_sort (rset->mset))
735         {
736           /* Out of memory.  */
737           return NULL;
738         }
739 
740       /* Update field properties, in case order_by_fields was changed
741          above.  */
742 
743       rec_rset_update_field_props (rset);
744     }
745 
746   return rset;
747 }
748 
749 rec_rset_t
rec_rset_group(rec_rset_t rset,rec_fex_t group_by)750 rec_rset_group (rec_rset_t rset,
751                 rec_fex_t group_by)
752 {
753   rec_mset_iterator_t iter;
754   rec_record_t record;
755   rec_mset_elem_t elem;
756   size_t map_size;
757   bool *deletion_map;
758   size_t num_record;
759 
760   /* Create and initialize the deletion map.  */
761 
762   map_size = sizeof(bool) * rec_rset_num_records (rset);
763   deletion_map = malloc (map_size);
764   if (!deletion_map)
765     {
766       /* Out of memory.  */
767       return NULL;
768     }
769 
770   memset (deletion_map, false, map_size);
771 
772   /* Iterate on the records of RSET, grouping records and marking the
773      grouped records for deletion.  */
774 
775   num_record = 0;
776   iter = rec_mset_iterator (rec_rset_mset (rset));
777   while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **)&record, NULL))
778     {
779       if (!deletion_map[num_record])
780         {
781           size_t num_record_2 = num_record;
782           rec_mset_iterator_t iter2 = iter;
783           rec_record_t record2;
784 
785           while (rec_mset_iterator_next (&iter2, MSET_RECORD, (const void**)&record2, NULL))
786             {
787               num_record_2++;
788 
789               if (rec_rset_compare_typed_records (rset, record, record2, group_by) != 0)
790                 {
791                   break;
792                 }
793               else
794                 {
795                   /* Insert all the elements of record2 into record,
796                      but not the group-by fields.  Also, remove any
797                      duplicated field created in record2 as the result
798                      of the operation.  */
799 
800                   if (!rec_rset_merge_records (record,
801                                                record2,
802                                                group_by))
803                     {
804                       /* Out of memory.  */
805                       return NULL;
806                     }
807 
808                   /* Mark record2 for removal.  */
809                   deletion_map[num_record_2] = true;
810                 }
811             }
812         }
813 
814       num_record++;
815     }
816   rec_mset_iterator_free (&iter);
817 
818   /* Delete the records marked for deletion.  */
819 
820   num_record = 0;
821   iter = rec_mset_iterator (rec_rset_mset (rset));
822   while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &record, &elem))
823     {
824       if (deletion_map[num_record])
825         {
826           rec_mset_remove_elem (rec_rset_mset (rset), elem);
827         }
828 
829       num_record++;
830     }
831   rec_mset_iterator_free (&iter);
832 
833   free (deletion_map);
834 
835   return rset;
836 }
837 
838 rec_rset_t
rec_rset_add_auto_fields(rec_rset_t rset,rec_record_t record)839 rec_rset_add_auto_fields (rec_rset_t rset,
840                           rec_record_t record)
841 {
842   rec_fex_t auto_fields;
843   rec_type_t type;
844   size_t i;
845 
846   if ((auto_fields = rec_rset_auto (rset)))
847     {
848       size_t num_auto_fields = rec_fex_size (auto_fields);
849 
850       for (i = 0; i < num_auto_fields; i++)
851         {
852           const char *auto_field_name =
853             rec_fex_elem_field_name (rec_fex_get (auto_fields, i));
854 
855           if (!rec_record_field_p (record, auto_field_name))
856             {
857               /* The auto field is not already present in record, so
858                  add one automatically.  Depending on its type the
859                  value is calculated differently.  If the record does
860                  not have a type, or the type is incorrect, ignore
861                  it.  */
862 
863               type = rec_rset_get_field_type (rset, auto_field_name);
864               if (type)
865                 {
866                   switch (rec_type_kind (type))
867                     {
868                     case REC_TYPE_INT:
869                     case REC_TYPE_RANGE:
870                       {
871                         if (!rec_rset_add_auto_field_int (rset, auto_field_name, record))
872                           {
873                             /* Out of memory.  */
874                             return NULL;
875                           }
876 
877                         break;
878                       }
879                     case REC_TYPE_DATE:
880                       {
881                         if (!rec_rset_add_auto_field_date (rset, auto_field_name, record))
882                           {
883                             /* Out of memory.  */
884                             return NULL;
885                           }
886 
887                         break;
888                       }
889 #if defined UUID_TYPE
890                     case REC_TYPE_UUID:
891                       {
892                         if (!rec_rset_add_auto_field_uuid (rset, auto_field_name, record))
893                           {
894                             /* Out of memory.  */
895                             return NULL;
896                           }
897 
898                         break;
899                       }
900 #endif /* UUID_TYPE */
901                     default:
902                       {
903                         /* Do nothing for other types.  */
904                         break;
905                       }
906                     }
907                 }
908             }
909         }
910     }
911 
912   return rset;
913 }
914 
915 size_t
rec_rset_num_sex_constraints(rec_rset_t rset)916 rec_rset_num_sex_constraints (rec_rset_t rset)
917 {
918   return rset->num_constraints;
919 }
920 
921 rec_sex_t
rec_rset_sex_constraint(rec_rset_t rset,size_t index)922 rec_rset_sex_constraint (rec_rset_t rset,
923                          size_t index)
924 {
925   return rset->constraints[index];
926 }
927 
928 /*
929  * Private functions
930  */
931 
932 static void
rec_rset_init(rec_rset_t rset)933 rec_rset_init (rec_rset_t rset)
934 {
935   /* Initialize the rset structure so it can be safely passed to
936      rec_rset_destroy even if its contents are not completely
937      initialized with real values.  */
938 
939   memset (rset, 0 /* NULL */, sizeof (struct rec_rset_s));
940 }
941 
942 static void
rec_rset_record_disp_fn(void * data)943 rec_rset_record_disp_fn (void *data)
944 {
945   rec_record_t record = (rec_record_t) data;
946   rec_record_destroy (record);
947 }
948 
949 static bool
rec_rset_record_equal_fn(void * data1,void * data2)950 rec_rset_record_equal_fn (void *data1,
951                           void *data2)
952 {
953   return (data1 == data2);
954   /*  return rec_record_equal_p ((rec_record_t) data1,
955       (rec_record_t) data2); */
956 }
957 
958 static void *
rec_rset_record_dup_fn(void * data)959 rec_rset_record_dup_fn (void *data)
960 {
961   rec_record_t record = (rec_record_t) data;
962   rec_record_t new = rec_record_dup (record);
963 
964   return (void *) new;
965 }
966 
967 static int
rec_rset_record_compare_fn(void * data1,void * data2,int type2)968 rec_rset_record_compare_fn (void *data1,
969                             void *data2,
970                             int type2)
971 {
972   /* data1 is a record.  data2 can be either a record or a comment.
973 
974      order_by_field can't be NULL, because this callback is invoked
975      only if rec_mset_add_sorted is used to add an element to the
976      list.
977 
978      The following rules apply here:
979 
980      1. If the fields in order_by_fields are not in both record1 and
981         record2, then data1 < data2.
982 
983      2. Else, perform a lexicographic comparison, i.e.
984 
985         (a1, a2, ...) < (b1, b2, ...) IFF
986                       a1 < b1 OR (a1 = b2 AND a2 < b2) OR ...
987 
988     Note that record1 will always be a regular record.  Never a
989     descriptor.
990   */
991 
992   rec_rset_t rset                  = NULL;
993   rec_record_t record1             = NULL;
994   rec_record_t record2             = NULL;
995   int type_comparison              = 0;
996 
997   /* If elem2 is a comment then elem1 > elem2.  */
998   if (type2 == MSET_COMMENT)
999     {
1000       return 1;
1001     }
1002 
1003   /* Get the records and the containing rset.  */
1004   record1 = (rec_record_t) data1;
1005   record2 = (rec_record_t) data2;
1006   rset = (rec_rset_t) rec_record_container (record1);
1007 
1008   /* Perform a lexicographic comparison of the order_by_fields in both
1009      registers.  */
1010 
1011   type_comparison = rec_rset_compare_typed_records (rset,
1012                                                     record1,
1013                                                     record2,
1014                                                     rset->order_by_fields);
1015 
1016   /* If both records are equal, return -1 instead of 0 in order to
1017      maintain the relative ordering between equal records.  */
1018 
1019   if (type_comparison == 0)
1020     {
1021       type_comparison = -1;
1022     }
1023 
1024   return type_comparison;
1025 }
1026 
1027 static void
rec_rset_comment_disp_fn(void * data)1028 rec_rset_comment_disp_fn (void *data)
1029 {
1030   rec_comment_t comment = (rec_comment_t) data;
1031   rec_comment_destroy (comment);
1032 }
1033 
1034 static bool
rec_rset_comment_equal_fn(void * data1,void * data2)1035 rec_rset_comment_equal_fn (void *data1,
1036                            void *data2)
1037 {
1038   return (data1 == data2);
1039   /*  return rec_comment_equal_p ((rec_comment_t) data1,
1040       (rec_comment_t) data2);*/
1041 }
1042 
1043 static void *
rec_rset_comment_dup_fn(void * data)1044 rec_rset_comment_dup_fn (void *data)
1045 {
1046   rec_comment_t comment = (rec_comment_t) data;
1047   rec_comment_t new = rec_comment_dup (comment);
1048   return (void *) new;
1049 }
1050 
1051 static int
rec_rset_comment_compare_fn(void * data1,void * data2,int type2)1052 rec_rset_comment_compare_fn (void *data1,
1053                              void *data2,
1054                              int   type2)
1055 {
1056   /* data1 is a comment, and data2 can be either a comment or a
1057      record.  In any case, data1 < data2.  */
1058 
1059   return -1;
1060 }
1061 
1062 static void
rec_rset_update_sex_constraints(rec_rset_t rset)1063 rec_rset_update_sex_constraints (rec_rset_t rset)
1064 {
1065   /* Reset the existing constraints.  */
1066 
1067   {
1068     size_t i = 0;
1069 
1070     for (i = 0; i < rset->num_constraints; i++)
1071       {
1072         rec_sex_destroy (rset->constraints[i]);
1073       }
1074     rset->num_constraints = 0;
1075   }
1076 
1077   /* If there is not a record descriptor in the record set then simply
1078      return.  */
1079 
1080   if (!rset->descriptor)
1081     {
1082       return;
1083     }
1084 
1085   /* Allocate memory for the constraints memory.  In case of
1086      not-enough-memory simply return.  */
1087 
1088   {
1089     size_t num_constraints =
1090       rec_record_get_num_fields_by_name (rset->descriptor, FNAME(REC_FIELD_CONSTRAINT));
1091     rset->constraints = malloc (num_constraints * sizeof(rec_sex_t));
1092 
1093     if (!rset->constraints)
1094       {
1095         return;
1096       }
1097   }
1098 
1099   /* Scan the record descriptor for %constraint: directives, and build
1100      the constraints.  Not well formed constraint entries,
1101      i.e. entries not containing valid sexes, are simply ignored.  */
1102 
1103   {
1104     rec_field_t field = NULL;
1105     rec_mset_iterator_t iter;
1106 
1107     iter = rec_mset_iterator (rec_record_mset (rset->descriptor));
1108     while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **)&field, NULL))
1109       {
1110         const char *field_name = rec_field_name (field);
1111         const char *field_value = rec_field_value (field);
1112 
1113         if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_CONSTRAINT)))
1114           {
1115             rec_sex_t sex = rec_sex_new (false);
1116             if (!sex)
1117               {
1118                 return;
1119               }
1120 
1121             if (rec_sex_compile (sex, field_value))
1122               {
1123                 rset->constraints[rset->num_constraints++] = sex;
1124               }
1125             else
1126               {
1127                 rec_sex_destroy (sex);
1128               }
1129           }
1130       }
1131     rec_mset_iterator_free (&iter);
1132   }
1133 }
1134 
1135 static void
rec_rset_update_size_constraints(rec_rset_t rset)1136 rec_rset_update_size_constraints (rec_rset_t rset)
1137 {
1138   rec_field_t field;
1139   enum rec_size_condition_e condition;
1140   size_t size = 0;
1141 
1142   /* Reset the constraints. */
1143   rset->min_size = 0;
1144   rset->max_size = SIZE_MAX;
1145 
1146   /* Scan the record descriptor for %size: directives, and build the
1147      new list.  */
1148   if (rset->descriptor)
1149     {
1150       field = rec_record_get_field_by_name (rset->descriptor,
1151                                             FNAME(REC_FIELD_SIZE),
1152                                             0);
1153 
1154       if (field && rec_match (rec_field_value (field), REC_INT_SIZE_RE))
1155         {
1156           /* Extract 'min' and 'max' and update the constraints in the
1157              rset.  */
1158           condition = rec_extract_size_condition (rec_field_value (field));
1159           size = rec_extract_size (rec_field_value (field));
1160 
1161           /* Set min_size and max_size depending on the
1162              condition.  */
1163           switch (condition)
1164             {
1165             case SIZE_COND_E:
1166               {
1167                 rset->min_size = size;
1168                 rset->max_size = size;
1169                 break;
1170               }
1171             case SIZE_COND_L:
1172               {
1173                 rset->max_size = size - 1;
1174                 break;
1175               }
1176             case SIZE_COND_LE:
1177               {
1178                 rset->max_size = size;
1179                 break;
1180               }
1181             case SIZE_COND_G:
1182               {
1183                 rset->min_size = size + 1;
1184                 break;
1185               }
1186             case SIZE_COND_GE:
1187               {
1188                 rset->min_size = size;
1189                 break;
1190               }
1191             }
1192         }
1193     }
1194 }
1195 
1196 static void
rec_rset_update_field_props(rec_rset_t rset)1197 rec_rset_update_field_props (rec_rset_t rset)
1198 {
1199   rec_rset_fprops_t props = NULL;
1200 #if defined REC_CRYPT_SUPPORT
1201   const char *confidential_field_name;
1202 #endif
1203   char *type_name = NULL;
1204 
1205   /* Reset the field properties.  */
1206   props = rset->field_props;
1207   while (props)
1208     {
1209       props->key_p = false;
1210       props->auto_p = false;
1211       if (props->type)
1212         {
1213           rec_type_destroy (props->type);
1214           props->type = NULL;
1215         }
1216 
1217       props = props->next;
1218     }
1219 
1220   if (rset->descriptor)
1221     {
1222       /* Pass 1: scan the record descriptor for % directives, and update
1223          the fields properties accordingly.  */
1224 
1225       rec_field_t field;
1226       rec_mset_iterator_t iter;
1227 
1228       iter = rec_mset_iterator (rec_record_mset (rset->descriptor));
1229       while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &field, NULL))
1230         {
1231           const char *field_name = rec_field_name (field);
1232           const char *field_value = rec_field_value (field);
1233 
1234           /* Update field types.  Only valid %type: descriptors are
1235              considered.  Invalid descriptors are ignored.  */
1236 
1237           if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_TYPE))
1238               && rec_rset_type_field_p (field_value))
1239             {
1240               size_t i;
1241               rec_fex_t fex = rec_rset_type_field_fex (field_value);
1242 
1243               for (i = 0; i < rec_fex_size (fex); i++)
1244                 {
1245                   char *field_type = rec_rset_type_field_type (field_value);
1246                   rec_type_t type = rec_type_new (field_type);
1247 
1248                   if (!type)
1249                     {
1250                       /* Set field_type as a field property.  Note
1251                          that if the field is already associated with
1252                          an anonymous type, or a type name, they are
1253                          replaced.  */
1254 
1255                       const char *p = field_type;
1256                       rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, &type_name);
1257                       props = rec_rset_get_props (rset,
1258                                                   rec_fex_elem_field_name (rec_fex_get (fex, i)),
1259                                                   true);
1260                       if (props->type)
1261                         {
1262                           rec_type_destroy (props->type);
1263                           props->type = NULL;
1264                         }
1265                       free (props->type_name);
1266                       props->type_name = type_name;
1267                     }
1268                   else
1269                     {
1270                       /* Set the type as a field property.  Note that
1271                          if the field is already associated with an
1272                          anonymous type, or a type name, they are
1273                          replaced.  */
1274 
1275                       props = rec_rset_get_props (rset,
1276                                                   rec_fex_elem_field_name (rec_fex_get (fex, i)),
1277                                                   true);
1278                       if (props->type)
1279                         {
1280                           rec_type_destroy (props->type);
1281                         }
1282                       free (props->type_name);
1283                       props->type_name = NULL;
1284                       props->type = type;
1285                     }
1286 
1287                   free (field_type);
1288                 }
1289 
1290               rec_fex_destroy (fex);
1291             }
1292 
1293           /* Update the key field.  */
1294           if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_KEY)))
1295             {
1296               /* %key: fields containing incorrect data are
1297                   ignored.  */
1298 
1299               const char *field_value = rec_field_value (field);
1300               char *type_name = NULL;
1301 
1302               rec_skip_blanks (&field_value);
1303               rec_parse_regexp (&field_value, "^" REC_RECORD_TYPE_RE, &type_name);
1304               props = rec_rset_get_props (rset, type_name, true);
1305               props->key_p = true;
1306               free (type_name);
1307             }
1308 
1309           /* Update auto fields.  */
1310           if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_AUTO)))
1311             {
1312               /* %auto: fields containing incorrect data are
1313                   ignored.  */
1314 
1315               rec_fex_t fex = rec_fex_new (rec_field_value (field), REC_FEX_SIMPLE);
1316               if (fex)
1317                 {
1318                   size_t i;
1319 
1320                   for (i = 0; i < rec_fex_size (fex); i++)
1321                     {
1322                       const char *auto_field_name
1323                         = rec_fex_elem_field_name (rec_fex_get (fex, i));
1324                       props = rec_rset_get_props (rset, auto_field_name, true);
1325                       props->auto_p = true;
1326                     }
1327                 }
1328             }
1329 
1330           /* Update sort fields.  The last field takes precedence.  */
1331           if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_SORT)))
1332             {
1333               /* Parse the simple fex in the field value.  Invalid
1334                  entries are just ignored.  */
1335 
1336               const char *field_value = rec_field_value (field);
1337 
1338               rec_fex_t fex = rec_fex_new (field_value, REC_FEX_SIMPLE);
1339               if (fex)
1340                 {
1341                   rec_fex_destroy (rset->order_by_fields);
1342                   rset->order_by_fields = fex;
1343                 }
1344             }
1345 
1346 #if defined REC_CRYPT_SUPPORT
1347           /* Update confidential fields.  */
1348           if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_CONFIDENTIAL)))
1349             {
1350               /* Parse the field names in the field value.  Ignore
1351                  invalid entries.  */
1352 
1353               rec_fex_t fex = rec_fex_new (rec_field_value (field), REC_FEX_SIMPLE);
1354               if (fex)
1355                 {
1356                   size_t i;
1357 
1358                   for (i = 0; i < rec_fex_size (fex); i++)
1359                     {
1360                       confidential_field_name =
1361                         rec_fex_elem_field_name (rec_fex_get (fex, i));
1362                       props = rec_rset_get_props (rset, confidential_field_name, true);
1363                       props->confidential_p = true;
1364                     }
1365                 }
1366             }
1367 #endif /* REC_CRYPT_SUPPORT */
1368 
1369         }
1370 
1371       rec_mset_iterator_free (&iter);
1372     }
1373 
1374   /* Pass 2: scan the fields having properties on the record set.  */
1375 
1376   props = rset->field_props;
1377   while (props)
1378     {
1379       /* Auto fields not having an explicit type are implicitly
1380          typed as integers.  */
1381 
1382       if (props->auto_p && !props->type && !props->type_name)
1383         {
1384           props->type = rec_type_new ("int");
1385         }
1386 
1387       props = props->next;
1388     }
1389 }
1390 
1391 static void
rec_rset_update_types(rec_rset_t rset)1392 rec_rset_update_types (rec_rset_t rset)
1393 {
1394   rec_field_t field;
1395   rec_mset_iterator_t iter;
1396   const char *p, *q = NULL;
1397   rec_type_t type;
1398   char *type_name, *to_type = NULL;
1399 
1400 
1401   /* Scan the record descriptor for %typedef directives and update the
1402      types registry accordingly.  */
1403   if (rset->descriptor)
1404     {
1405       /* Purge the registry.  */
1406 
1407       rec_type_reg_destroy (rset->type_reg);
1408       rset->type_reg = rec_type_reg_new ();
1409 
1410       /* Iterate on the fields of the descriptor.  */
1411 
1412       iter = rec_mset_iterator (rec_record_mset (rset->descriptor));
1413       while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **) &field, NULL))
1414         {
1415           const char *field_name = rec_field_name (field);
1416           const char *field_value = rec_field_value (field);
1417 
1418           if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_TYPEDEF)))
1419             {
1420               p = field_value;
1421               rec_skip_blanks (&p);
1422 
1423               /* Get the name of the type.  */
1424               if (rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, &type_name))
1425                 {
1426                   /* Get the type.  */
1427                   type = rec_type_new (p);
1428                   if (type)
1429                     {
1430                       /* Set the name of the type.  */
1431                       rec_type_set_name (type, type_name);
1432 
1433                       /* Create and insert the type in the type
1434                          registry.  */
1435                       rec_type_reg_add (rset->type_reg, type);
1436                     }
1437                   else
1438                     {
1439                       /* This could be a synonym.  Try to parse a type
1440                          name and, if the operation succeeds, insert
1441                          the synonym in the registry.  */
1442                       rec_skip_blanks (&p);
1443                       q = p;
1444                       if (rec_parse_regexp (&q,
1445                                             "^" REC_TYPE_NAME_RE "[ \t\n]*",
1446                                             NULL))
1447                         {
1448                           rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, &to_type);
1449                           rec_type_reg_add_synonym (rset->type_reg,
1450                                                     type_name,
1451                                                     to_type);
1452                         }
1453                     }
1454 
1455                   free (type_name);
1456                 }
1457             }
1458         }
1459 
1460       rec_mset_iterator_free (&iter);
1461     }
1462 }
1463 
1464 static bool
rec_rset_type_field_p(const char * str)1465 rec_rset_type_field_p (const char *str)
1466 {
1467   const char *p = str;
1468 
1469   /* Check the fex */
1470 
1471   rec_skip_blanks (&p);
1472   if (!rec_parse_regexp (&p,
1473                          "^" REC_FNAME_LIST_CS_RE,
1474                          NULL))
1475     {
1476       return false;
1477     }
1478   rec_skip_blanks (&p);
1479 
1480   /* Check the type description, or the name of a type.  */
1481 
1482   return (rec_type_descr_p (p)
1483           || rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE "[ \t\n]*$", NULL));
1484 }
1485 
1486 static rec_fex_t
rec_rset_type_field_fex(const char * str)1487 rec_rset_type_field_fex (const char *str)
1488 {
1489   rec_fex_t fex = NULL;
1490   const char *p;
1491   char *name;
1492 
1493   p = str;
1494 
1495   if (rec_parse_regexp (&p,
1496                         "^" REC_FNAME_LIST_CS_RE,
1497                         &name))
1498     {
1499       fex = rec_fex_new (name, REC_FEX_CSV);
1500       free (name);
1501     }
1502 
1503   return fex;
1504 }
1505 
1506 static char*
rec_rset_type_field_type(const char * str)1507 rec_rset_type_field_type (const char *str)
1508 {
1509   char *result = NULL;
1510   const char *p;
1511 
1512   if (rec_rset_type_field_p (str))
1513     {
1514       p = str;
1515 
1516       rec_skip_blanks (&p);
1517       rec_parse_regexp (&p, "^" REC_FNAME_LIST_CS_RE, NULL);
1518       rec_skip_blanks (&p);
1519 
1520       /* Return the rest of the string.  */
1521       result = strdup (p);
1522     }
1523 
1524   return result;
1525 }
1526 
1527 static rec_rset_fprops_t
rec_rset_get_props(rec_rset_t rset,const char * fname,bool create_p)1528 rec_rset_get_props (rec_rset_t rset,
1529                     const char *fname,
1530                     bool create_p)
1531 {
1532   rec_rset_fprops_t props = NULL;
1533 
1534   props = rset->field_props;
1535   while (props)
1536     {
1537       if (rec_field_name_equal_p (fname, props->fname))
1538         {
1539           break;
1540         }
1541 
1542       props = props->next;
1543     }
1544 
1545   if (!props && create_p)
1546     {
1547       /* Create a new properties structure for this field name and
1548          initialize it.  */
1549       props = malloc (sizeof (struct rec_rset_fprops_s));
1550       if (props)
1551         {
1552           props->fname = strdup (fname);
1553           props->auto_p = false;
1554           props->key_p = false;
1555 
1556 #if defined REC_CRYPT_SUPPORT
1557           props->confidential_p = false;
1558 #endif
1559 
1560           props->type = NULL;
1561           props->type_name = NULL;
1562 
1563           /* Prepend it to the field properties list.  */
1564           props->next = rset->field_props;
1565           rset->field_props = props;
1566         }
1567     }
1568 
1569   return props;
1570 }
1571 
1572 static bool
rec_rset_add_auto_field_int(rec_rset_t rset,const char * field_name,rec_record_t record)1573 rec_rset_add_auto_field_int (rec_rset_t rset,
1574                              const char *field_name,
1575                              rec_record_t record)
1576 {
1577   rec_mset_iterator_t iter;
1578   rec_record_t rec;
1579   rec_field_t field;
1580   size_t num_fields, i;
1581   int auto_value, field_value;
1582   char *end;
1583   char *auto_value_str;
1584 
1585   /* Find the auto value.  */
1586 
1587   auto_value = 0;
1588 
1589   iter = rec_mset_iterator (rec_rset_mset (rset));
1590   while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &rec, NULL))
1591     {
1592       num_fields = rec_record_get_num_fields_by_name (rec, field_name);
1593       for (i = 0; i < num_fields; i++)
1594         {
1595           field = rec_record_get_field_by_name (rec, field_name, i);
1596 
1597           /* Ignore fields that can't be converted to integer
1598              values.  */
1599           errno = 0;
1600           field_value = strtol (rec_field_value (field), &end, 10);
1601           if ((errno == 0) && (*end == '\0'))
1602             {
1603               if (auto_value <= field_value)
1604                 {
1605                   auto_value = field_value + 1;
1606                 }
1607             }
1608         }
1609     }
1610 
1611   rec_mset_iterator_free (&iter);
1612 
1613   /* Create and insert the auto field.  */
1614 
1615   if (asprintf (&auto_value_str, "%d", auto_value) != -1)
1616     {
1617       field = rec_field_new (field_name, auto_value_str);
1618       if (!field)
1619         {
1620           /* Out of memory.  */
1621           free (auto_value_str);
1622           return false;
1623         }
1624 
1625       if (!rec_mset_insert_at (rec_record_mset (record), MSET_FIELD, (void *) field, 0))
1626         {
1627           /* Out of memory.  */
1628           free (auto_value_str);
1629           return false;
1630         }
1631 
1632       free (auto_value_str);
1633     }
1634 
1635   return true;
1636 }
1637 
1638 static bool
rec_rset_add_auto_field_date(rec_rset_t rset,const char * field_name,rec_record_t record)1639 rec_rset_add_auto_field_date (rec_rset_t rset,
1640                               const char *field_name,
1641                               rec_record_t record)
1642 {
1643   rec_field_t auto_field;
1644   time_t t;
1645   char outstr[200];
1646   struct tm *tmp;
1647 
1648   t = time (NULL);
1649   tmp = localtime (&t);
1650 
1651   setlocale (LC_TIME, "C"); /* We want english dates that can be
1652                                  parsed with parse_datetime */
1653   strftime (outstr, sizeof(outstr), "%a, %d %b %Y %T %z", tmp);
1654   setlocale (LC_TIME, ""); /* And restore the locale from the
1655                               environment. */
1656 
1657   auto_field = rec_field_new (field_name, outstr);
1658   if (!auto_field)
1659     {
1660       /* Out of memory.  */
1661       return false;
1662     }
1663 
1664   if (!rec_mset_insert_at (rec_record_mset (record), MSET_FIELD, (void *) auto_field, 0))
1665     {
1666       /* Out of memory.  */
1667       return false;
1668     }
1669 
1670   return true;
1671 }
1672 
1673 #if defined UUID_TYPE
1674 
1675 static bool
rec_rset_add_auto_field_uuid(rec_rset_t rset,const char * field_name,rec_record_t record)1676 rec_rset_add_auto_field_uuid (rec_rset_t rset,
1677                               const char *field_name,
1678                               rec_record_t record)
1679 {
1680   rec_field_t auto_field;
1681   uuid_t uu;
1682   char uu_str[40]; /* Enough to hold any standard UUID.  */
1683 
1684   /* Generate a new time-based UUID using the libuuid library and use
1685      it for the value of the new auto field.  */
1686 
1687   uuid_generate_time (uu);
1688   uuid_unparse (uu, uu_str);
1689 
1690   auto_field = rec_field_new (field_name, uu_str);
1691   if (!auto_field)
1692     {
1693       /* Out of memory.  */
1694       return false;
1695     }
1696 
1697   if (!rec_mset_insert_at (rec_record_mset (record), MSET_FIELD, (void *) auto_field, 0))
1698     {
1699       /* Out of memory.  */
1700       return false;
1701     }
1702 
1703   return true;
1704 }
1705 
1706 #endif /* UUID_TYPE */
1707 
1708 static rec_record_t
rec_rset_merge_records(rec_record_t to_record,rec_record_t from_record,rec_fex_t group_by_fields)1709 rec_rset_merge_records (rec_record_t to_record,
1710                         rec_record_t from_record,
1711                         rec_fex_t    group_by_fields)
1712 {
1713   rec_mset_elem_t elem;
1714   void *data;
1715   rec_mset_iterator_t iter;
1716 
1717   iter = rec_mset_iterator (rec_record_mset (from_record));
1718   while (rec_mset_iterator_next (&iter, MSET_ANY, (const void**) &data, &elem))
1719     {
1720       if (rec_mset_elem_type (elem) == MSET_FIELD)
1721         {
1722           rec_field_t field = (rec_field_t) data;
1723 
1724           /* Don't add the field if it is in the list of group-by
1725              fields.  */
1726 
1727           if (rec_fex_member_p (group_by_fields, rec_field_name (field), -1, -1))
1728             {
1729               continue;
1730             }
1731 
1732           /* Don't allow duplicated fields in the resulting record
1733              generated as a result of this operation.  This is
1734              commented out because it fucks up the usage of aggregated
1735              functions in grouped-by record sets.  */
1736 
1737           /*         if (rec_record_contains_field (to_record,
1738                                          rec_field_name (field),
1739                                          rec_field_value (field)))
1740             {
1741               continue;
1742               } */
1743 
1744           /* Ok, add this field.  */
1745 
1746           if (!rec_mset_append (rec_record_mset (to_record),
1747                                 MSET_FIELD,
1748                                 (void *) rec_field_dup (field),
1749                                 MSET_ANY))
1750             {
1751               /* Out of memory.  */
1752               return NULL;
1753             }
1754         }
1755       else
1756         {
1757           rec_comment_t comment = (rec_comment_t) data;
1758           rec_mset_append (rec_record_mset (to_record),
1759                            MSET_COMMENT,
1760                            (void *) rec_comment_dup (comment),
1761                            MSET_ANY);
1762         }
1763     }
1764   rec_mset_iterator_free (&iter);
1765 
1766   return to_record;
1767 }
1768 
1769 static int
rec_rset_compare_typed_records(rec_rset_t rset,rec_record_t record1,rec_record_t record2,rec_fex_t fields)1770 rec_rset_compare_typed_records (rec_rset_t rset,
1771                                 rec_record_t record1,
1772                                 rec_record_t record2,
1773                                 rec_fex_t fields)
1774 {
1775   int result = 0;
1776   size_t i = 0;
1777   size_t num_fields = rec_fex_size (fields);
1778 
1779   for (i = 0; i < num_fields; i++)
1780     {
1781       rec_fex_elem_t elem       = rec_fex_get (fields, i);
1782       const char    *field_name = rec_fex_elem_field_name (elem);
1783       rec_field_t    field1     = rec_record_get_field_by_name (record1, field_name, 0);
1784       rec_field_t    field2     = rec_record_get_field_by_name (record2, field_name, 0);
1785 
1786       /* If any of the fields is not present in some of the records
1787          then that record is considered to be smaller than the record
1788          featuring the other one.  */
1789 
1790       if (field1 && !field2)
1791         {
1792           result = 1; /* field1 > field2 */
1793           break;
1794         }
1795       else if (!field1 && field2)
1796         {
1797           result = -1;  /* field1 < field2 */
1798           break;
1799         }
1800       else if (!field1 && !field2)
1801         {
1802           result = -1;  /* field1 < field2 */
1803           break;
1804         }
1805 
1806       /* A field with such a name exists in both records.  Compare the
1807          field typed values.  */
1808 
1809       result =  rec_type_values_cmp (rec_rset_get_field_type (rset, field_name),
1810                                      rec_field_value (field1),
1811                                      rec_field_value (field2));
1812 
1813       if (result != 0)
1814         {
1815           /* Either (a1, a2, ...) < (b1, b2, ...) or (a1, a2, ...) >
1816              (b1, b2, ...) */
1817 
1818           break;
1819         }
1820     }
1821 
1822   return result;
1823 }
1824 
1825 /* End of rec-rset.c */
1826