20221212
[devspec.git] / devspec.en_US / project / recutils / src / rec-db.c
blobc2afc37c8f0168be5c68182a56be52102358dbfe
1 /* -*- mode: C -*-
3 * File: rec-db.c
4 * Date: Thu Jan 14 15:35:27 2010
6 * GNU recutils - Databases
8 */
10 /* Copyright (C) 2010-2019 Jose E. Marchesi */
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.
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.
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/>.
26 #include <config.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <time.h>
31 #include <gl_array_list.h>
32 #include <gl_list.h>
34 #include <rec-utils.h>
35 #include <rec.h>
38 * Data structures.
41 struct rec_db_s
43 size_t size; /* Number of record sets contained
44 in this database. */
45 gl_list_t rset_list; /* List of record sets. */
46 rec_aggregate_reg_t aggregates; /* Registry with the aggregates. */
49 /* Static functions defined in this file. */
51 static bool rec_db_rset_equals_fn (const void *elt1,
52 const void *elt2);
53 static void rec_db_rset_dispose_fn (const void *elt);
55 static rec_record_t rec_db_process_fex (rec_db_t db,
56 rec_rset_t rset,
57 rec_record_t record,
58 rec_fex_t fex);
60 static bool rec_db_record_selected_p (size_t num_rec,
61 rec_record_t record,
62 size_t *index,
63 rec_sex_t sex,
64 const char *fast_string,
65 bool case_insensitive_p);
66 static void rec_db_add_random_indexes (size_t **index, size_t num, size_t limit);
67 static bool rec_db_index_p (size_t *index, size_t num);
69 static bool rec_db_set_act_rename (rec_rset_t rset, rec_record_t record, rec_fex_t fex, bool rename_descriptor, const char *arg);
70 static bool rec_db_set_act_set (rec_rset_t rset, rec_record_t record, rec_fex_t fex, bool xxx, const char *arg);
71 static bool rec_db_set_act_add (rec_rset_t rset, rec_record_t record, rec_fex_t fex, const char *arg);
72 static bool rec_db_set_act_delete (rec_rset_t rset, rec_record_t record, rec_fex_t fex, bool comment_out);
74 static rec_rset_t rec_db_join (rec_db_t db, const char *type1, const char *field, const char *type2);
75 static rec_record_t rec_db_merge_records (rec_record_t record1, rec_record_t record2, const char *prefix);
78 * Public functions.
81 rec_db_t
82 rec_db_new (void)
84 rec_db_t new;
86 new = malloc (sizeof (struct rec_db_s));
87 if (new)
89 new->size = 0;
90 new->rset_list = gl_list_nx_create_empty (GL_ARRAY_LIST,
91 rec_db_rset_equals_fn,
92 NULL,
93 rec_db_rset_dispose_fn,
94 true);
96 if (new->rset_list == NULL)
98 /* Out of memory. */
99 free (new);
100 new = NULL;
103 /* Add the standard field functions to the registry in the
104 database. */
106 new->aggregates = rec_aggregate_reg_new ();
107 if (!new->aggregates)
109 /* Out of memory. */
110 free (new);
111 return NULL;
113 rec_aggregate_reg_add_standard (new->aggregates);
116 return new;
119 void
120 rec_db_destroy (rec_db_t db)
122 if (db)
124 rec_aggregate_reg_destroy (db->aggregates);
125 gl_list_free (db->rset_list);
126 free (db);
130 size_t
131 rec_db_size (rec_db_t db)
133 return db->size;
136 rec_rset_t
137 rec_db_get_rset (rec_db_t db,
138 size_t position)
140 rec_rset_t rset;
142 rset = NULL;
144 if (db->size > 0)
146 if (position >= db->size)
148 position = db->size - 1;
151 rset = (rec_rset_t) gl_list_get_at (db->rset_list, position);
154 return rset;
157 bool
158 rec_db_insert_rset (rec_db_t db,
159 rec_rset_t rset,
160 size_t position)
162 gl_list_node_t node;
164 node = NULL;
166 if (position == 0)
168 node = gl_list_nx_add_first (db->rset_list,
169 (void *) rset);
171 else if (position >= db->size)
173 node = gl_list_nx_add_last (db->rset_list,
174 (void *) rset);
176 else
178 node = gl_list_nx_add_at (db->rset_list,
179 position,
180 (void *) rset);
183 if (node != NULL)
185 db->size++;
186 return true;
189 return false;
192 bool
193 rec_db_remove_rset (rec_db_t db, size_t position)
195 bool removed;
197 removed = false;
199 if (db->size > 0)
201 if (position >= db->size)
203 position = db->size - 1;
206 if (gl_list_remove_at (db->rset_list,
207 position))
209 db->size--;
210 removed = true;
214 return removed;
217 bool
218 rec_db_type_p (rec_db_t db,
219 const char *type)
221 return (rec_db_get_rset_by_type (db, type) != NULL);
224 rec_rset_t
225 rec_db_get_rset_by_type (rec_db_t db,
226 const char *type)
228 int i;
229 rec_rset_t rset;
230 bool found;
231 char *rtype;
233 found = false;
234 for (i = 0; i < rec_db_size (db); i++)
236 rset = rec_db_get_rset (db, i);
237 rtype = rec_rset_type (rset);
238 if (rtype == NULL)
240 if (type == NULL)
242 /* Return the default rset. */
243 found = true;
244 break;
247 else
249 if ((type != NULL)
250 && (strcmp (rtype, type) == 0))
252 found = true;
253 break;
258 if (!found)
260 rset = NULL;
263 return rset;
266 rec_rset_t
267 rec_db_query (rec_db_t db,
268 const char *type,
269 const char *join,
270 size_t *index,
271 rec_sex_t sex,
272 const char *fast_string,
273 size_t random,
274 rec_fex_t fex,
275 const char *password,
276 rec_fex_t group_by,
277 rec_fex_t sort_by,
278 int flags)
280 rec_rset_t res = NULL;
281 rec_rset_t rset = NULL;
283 /* Create a new, empty, record set, that will contain the contents
284 of the selection. */
286 res = rec_rset_new ();
287 if (!res)
289 /* Out of memory. */
290 return NULL;
293 /* Search for the rset containing records of the requested type. If
294 type equals to NULL then the default record set is used. If JOIN
295 is not NULL then the record set must be the join of the involved
296 record sets. */
298 rset = rec_db_get_rset_by_type (db, type);
299 if (!rset)
301 /* If the default record set was selected, it was not found, and
302 the database contains only one record set, then it is
303 selected. */
305 if (!type && (rec_db_size (db) == 1))
307 rset = rec_db_get_rset (db, 0);
309 else
311 /* Type not found, so return an empty record set. */
312 return res;
315 else
317 if (join)
319 /* A join was requested. The steps to proceed are:
321 - Make sure that the requested field join is declared of
322 type 'rec' in the record set.
323 - Retrieve the referred record set from the database.
324 - Calculate the join and store it in 'rset'.
327 rec_type_t ref_type = rec_rset_get_field_type (rset, join);
328 if (ref_type && (rec_type_kind (ref_type) == REC_TYPE_REC))
330 const char *referred_type = rec_type_rec (ref_type);
332 if (rec_db_get_rset_by_type (db, referred_type))
334 rset = rec_db_join (db, type, join, referred_type);
335 if (!rset)
337 /* Out of memory. */
338 return NULL;
345 /* If a descriptor is requested then get a copy of the descriptor of
346 the referred record set, which exists only if it is not the
347 default. */
349 if (flags & REC_F_DESCRIPTOR)
351 rec_record_t descriptor = rec_rset_descriptor (rset);
352 if (descriptor)
354 descriptor = rec_record_dup (descriptor);
355 if (!descriptor)
357 /* Out of memory. */
358 free (res);
359 return NULL;
363 rec_rset_set_descriptor (res, descriptor);
366 /* Generate a list of random indexes here if requested. The
367 generated random indexes are added to the indexes list, which
368 must be NULL if random > 0 (mutually exclusive arguments). */
370 if (random > 0)
372 rec_db_add_random_indexes (&index, random, rec_rset_num_records (rset));
373 if (!index)
375 /* Out of memory. */
376 return NULL;
380 if (fex && !group_by && rec_fex_all_calls_p (fex))
382 /* This query is a request for the value of several aggregates,
383 with no grouping. This means that the resulting rset will
384 contain one record containing the evaluation of the
385 aggregates. This is peformed by invoking rec_db_process_fex
386 with a NULL record. */
388 rec_record_t record = rec_db_process_fex (db, rset, NULL, fex);
389 if (record)
391 rec_record_set_container (record, res);
392 if (!rec_mset_append (rec_rset_mset (res),
393 MSET_RECORD,
394 (void *) record,
395 MSET_RECORD))
397 /* Out of memory. */
398 return NULL;
402 else
404 /* Process this record set. This means that every record of this
405 record set which is selected by some of the selection arguments
406 (a sex, an index, a random selection or a "fast string") will
407 be duplicated and added to the 'res' record set. */
409 rec_record_t record = NULL;
410 size_t num_rec = -1;
412 if (group_by)
414 if (!rec_rset_sort (rset, group_by))
416 /* Out of memory. */
417 return NULL;
420 if (!rec_rset_group (rset, group_by))
422 /* Out of memory. */
423 return NULL;
427 if (!rec_rset_sort (rset, sort_by))
429 /* Out of memory. */
430 return NULL;
433 rec_mset_iterator_t iter = rec_mset_iterator (rec_rset_mset (rset));
434 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &record, NULL))
436 rec_record_t res_record;
437 num_rec++;
439 /* Determine whether we must skip this record. */
441 if (!rec_db_record_selected_p (num_rec,
442 record,
443 index,
444 sex,
445 fast_string,
446 flags & REC_F_ICASE))
448 continue;
451 /* Process this record. */
453 /* Transform the record through the field expression and add
454 it to the result record set. */
456 res_record
457 = rec_db_process_fex (db, rset, record, fex);
459 if (!res_record)
461 /* Out of memory. */
462 return NULL;
465 /* Do not add empty records to the result record set. */
467 if (rec_record_num_elems (res_record) == 0)
469 continue;
472 #if defined REC_CRYPT_SUPPORT
474 /* Decrypt the confidential fields in the record if some
475 of the fields are declared as "confidential", but only
476 do that if the user provided a password. Note that we
477 use 'rset' instead of 'res' to cover cases where (flags
478 & REC_F_DESCRIPTOR) == 0. */
480 if (password)
482 if (!rec_decrypt_record (rset, res_record, password))
484 /* Out of memory. */
485 return NULL;
488 #endif
490 /* Remove duplicated fields if requested by the user. */
492 if (flags & REC_F_UNIQ)
494 rec_record_uniq (res_record);
497 /* Append. */
499 rec_record_set_container (res_record, res);
500 if (!rec_mset_append (rec_rset_mset (res),
501 MSET_RECORD,
502 (void *) res_record,
503 MSET_RECORD))
505 /* Out of memory. */
506 return NULL;
510 rec_mset_iterator_free (&iter);
513 return res;
516 bool
517 rec_db_insert (rec_db_t db,
518 const char *type,
519 size_t *index,
520 rec_sex_t sex,
521 const char *fast_string,
522 size_t random,
523 const char *password,
524 rec_record_t record,
525 int flags)
527 /* Discard NULL or empty records. */
529 if (!record || (rec_record_num_fields (record) == 0))
531 return true;
534 /* Insert the record in the database. */
536 if (index || sex || fast_string || (random > 0))
538 /* Replace matching records with copies of RECORD. */
540 rec_rset_t rset = rec_db_get_rset_by_type (db, type);
541 if (rset)
543 size_t num_rec = -1;
545 /* If the user requested to replace random records,
546 calculate them now for this record set. */
548 if (random > 0)
550 rec_db_add_random_indexes (&index, random, rec_rset_num_records (rset));
551 if (!index)
553 /* Out of memory. */
554 return false;
558 /* Add auto generated fields unless the user disabled
559 it. */
561 if (!(flags & REC_F_NOAUTO))
563 if (!rec_rset_add_auto_fields (rset, record))
565 /* Out of memory. */
566 return false;
570 #if defined REC_CRYPT_SUPPORT
572 /* Encrypt confidential fields if a password was provided by
573 the user. */
575 if (password)
577 if (!rec_encrypt_record (rset, record, password))
579 /* Out of memory. */
580 return false;
583 #endif
585 /* Iterate on the record set, replacing matching records
586 with copies of the provided record. */
589 rec_record_t rset_record = NULL;
590 rec_mset_elem_t elem;
591 rec_mset_iterator_t iter = rec_mset_iterator (rec_rset_mset (rset));
593 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &rset_record, &elem))
595 num_rec++;
597 /* Shall we skip this record? */
599 if (!rec_db_record_selected_p (num_rec,
600 rset_record,
601 index,
602 sex,
603 fast_string,
604 flags & REC_F_ICASE))
606 continue;
609 /* Replace the record. */
611 rec_record_set_container (record, rset);
612 rec_mset_elem_set_data (elem, (void *) rec_record_dup (record));
615 rec_mset_iterator_free (&iter);
619 else
621 /* Append the record in the proper record set. */
623 rec_rset_t rset = rec_db_get_rset_by_type (db, type);
625 if (rset)
627 rec_record_set_container (record, rset);
629 /* Add auto-set fields required by this record set, unless
630 the addition of auto-fields is disabled by the user. */
632 if (!(flags & REC_F_NOAUTO))
634 if (!rec_rset_add_auto_fields (rset, record))
636 /* Out of memory. */
637 return false;
641 #if defined REC_CRYPT_SUPPORT
642 /* Encrypt confidential fields if a password was
643 provided. */
645 if (password)
647 if (!rec_encrypt_record (rset, record, password))
649 /* Out of memory. */
650 return false;
653 #endif
655 if (rec_rset_num_records (rset) == 0)
657 /* The rset is empty => Insert the new record just after
658 the relative position of the record descriptor. */
660 rec_mset_insert_at (rec_rset_mset (rset),
661 MSET_RECORD,
662 (void *) record,
663 rec_rset_descriptor_pos (rset));
665 else
667 /* Insert the new record after the last record in the
668 set. */
670 rec_mset_t mset = rec_rset_mset (rset);
671 rec_record_t last_record =
672 (rec_record_t) rec_mset_get_at (mset,
673 MSET_RECORD,
674 rec_rset_num_records (rset) - 1);
676 if (!rec_mset_insert_after (mset,
677 MSET_RECORD,
678 (void *) record,
679 rec_mset_search (mset, (void *) last_record)))
681 /* Out of memory. */
682 return NULL;
686 else
688 /* Create a new type and insert the record there. */
690 rset = rec_rset_new ();
691 if (!rset)
693 /* Out of memory. */
694 return false;
697 rec_rset_set_type (rset, type);
698 rec_record_set_container (record, rset);
699 if (!rec_mset_append (rec_rset_mset (rset),
700 MSET_RECORD,
701 (void *) record,
702 MSET_ANY))
704 /* Out of memory. */
705 return false;
708 if (type)
710 rec_db_insert_rset (db, rset, rec_db_size (db));
712 else
714 /* The default rset should always be placed in the
715 beginning of the db. */
717 rec_db_insert_rset (db, rset, 0);
722 return true;
725 bool
726 rec_db_delete (rec_db_t db,
727 const char *type,
728 size_t *index,
729 rec_sex_t sex,
730 const char *fast_string,
731 size_t random,
732 int flags)
734 /* Get the selected record set. If the user did not specify a type,
735 the default record set does not exist, and the database contains
736 only one record set, then select it. */
738 rec_rset_t rset = rec_db_get_rset_by_type (db, type);
739 if (!type && !rset && (rec_db_size (db) == 1))
741 rset = rec_db_get_rset (db, 0);
744 /* Don't process empty record sets. */
746 if (rec_rset_num_records (rset) == 0)
748 return true;
751 /* If the user requested to delete random records then calculate
752 them now for this record set. */
754 if (random > 0)
756 rec_db_add_random_indexes (&index, random, rec_rset_num_records (rset));
757 if (!index)
759 /* Out of memory. */
760 return false;
764 /* Iterate on the records, deleting or commenting out the selected
765 ones. */
768 rec_record_t record = NULL;
769 rec_mset_elem_t elem;
770 size_t num_rec = -1;
771 rec_mset_iterator_t iter = rec_mset_iterator (rec_rset_mset (rset));
773 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &record, &elem))
775 num_rec++;
777 if (!rec_db_record_selected_p (num_rec,
778 record,
779 index,
780 sex,
781 fast_string,
782 flags & REC_F_ICASE))
784 continue;
787 if (flags & REC_F_COMMENT_OUT)
789 /* Replace the record with a comment in the current
790 element. */
792 rec_comment_t comment = rec_record_to_comment (record);
793 if (!comment)
795 /* Out of memory. */
796 return false;
799 rec_record_destroy (record);
800 rec_mset_elem_set_data (elem, (void *) comment);
801 rec_mset_elem_set_type (elem, MSET_COMMENT);
803 else
805 /* Remove the physical record from the record set and
806 dispose it. */
808 rec_mset_remove_elem (rec_rset_mset (rset), elem);
811 rec_mset_iterator_free (&iter);
814 return true;
817 bool rec_db_set (rec_db_t db,
818 const char *type,
819 size_t *index,
820 rec_sex_t sex,
821 const char *fast_string,
822 size_t random,
823 rec_fex_t fex,
824 int action,
825 const char *action_arg,
826 int flags)
828 /* Get the selected record set. If the user did not specify a type,
829 the default record set does not exist, and the database contains
830 only one record set, then select it. */
832 rec_rset_t rset = rec_db_get_rset_by_type (db, type);
833 if (!type && !rset && (rec_db_size (db) == 1))
835 rset = rec_db_get_rset (db, 0);
838 /* Don't process empty record sets. */
840 if (rec_rset_num_records (rset) == 0)
842 return true;
845 /* If the user requested to manipulate random records then calculate
846 them now for this record set. */
848 if (random > 0)
850 rec_db_add_random_indexes (&index, random, rec_rset_num_records (rset));
851 if (!index)
853 /* Out of memory. */
854 return false;
858 /* Iterate on the records, operating on the selected ones. */
861 rec_record_t record = NULL;
862 size_t num_rec = -1;
863 rec_mset_iterator_t iter = rec_mset_iterator (rec_rset_mset (rset));
864 bool descriptor_renamed = false;
866 while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &record, NULL))
868 num_rec++;
870 if (!rec_db_record_selected_p (num_rec,
871 record,
872 index,
873 sex,
874 fast_string,
875 flags & REC_F_ICASE))
877 continue;
880 switch (action)
882 case REC_SET_ACT_RENAME:
884 /* If the operation is applied to all records of a given
885 type (or default) then change the record descriptor
886 as well. But make sure to do it just once! */
888 bool rename_descriptor = false;
889 if (!descriptor_renamed
890 && (sex == NULL) && (index == NULL) && (random == 0) && (fast_string == NULL))
892 rename_descriptor = true;
893 descriptor_renamed = true;
896 if (!rec_db_set_act_rename (rset, record, fex, rename_descriptor, action_arg))
898 /* Out of memory. */
899 return false;
902 break;
904 case REC_SET_ACT_SET:
906 if (!rec_db_set_act_set (rset, record, fex, false, action_arg))
908 /* Out of memory. */
909 return false;
911 break;
913 case REC_SET_ACT_ADD:
915 if (!rec_db_set_act_add (rset, record, fex, action_arg))
917 /* Out of memory. */
918 return false;
920 break;
922 case REC_SET_ACT_SETADD:
924 if (!rec_db_set_act_set (rset, record, fex, true, action_arg))
926 /* Out of memory. */
927 return false;
929 break;
931 case REC_SET_ACT_DELETE:
933 if (!rec_db_set_act_delete (rset, record, fex, false))
935 /* Out of memory. */
936 return false;
938 break;
940 case REC_SET_ACT_COMMENT:
942 if (!rec_db_set_act_delete (rset, record, fex, true))
944 /* Out of memory. */
945 return false;
947 break;
949 default:
951 /* Ignore an invalid action. */
952 return true;
956 rec_mset_iterator_free (&iter);
959 return true;
962 rec_aggregate_reg_t
963 rec_db_aggregates (rec_db_t db)
965 return db->aggregates;
969 * Private functions.
972 static rec_record_t
973 rec_db_merge_records (rec_record_t record1,
974 rec_record_t record2,
975 const char *prefix)
977 rec_mset_iterator_t iter;
978 rec_field_t field;
979 rec_record_t merge = NULL;
981 merge = rec_record_dup (record1);
982 if (!merge)
984 return NULL;
987 /* Add all the fields from record2 to record1, prepending PREFIX_ to
988 the field name. It is the responsability of the user to provide
989 a PREFIX whose application results in a unique field. */
991 iter = rec_mset_iterator (rec_record_mset (record2));
992 while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **) &field, NULL))
994 rec_field_t new_field = rec_field_dup (field);
995 if (!new_field)
997 /* Out of memory. */
998 return NULL;
1001 /* Apply the prefix. */
1003 const char *field_name = rec_field_name (new_field);
1004 char *new_name = malloc (strlen (field_name) + strlen(prefix) + 2);
1005 if (!new_name)
1007 /* Out of memory. */
1008 return NULL;
1011 memcpy (new_name, prefix, strlen (prefix));
1012 new_name[strlen (prefix)] = '_';
1013 memcpy (new_name + strlen (prefix) + 1, field_name, strlen (field_name) + 1);
1015 if (!rec_field_set_name (new_field, new_name))
1017 /* Out of memory. */
1018 return NULL;
1021 free (new_name);
1024 if (!rec_mset_append (rec_record_mset (merge),
1025 MSET_FIELD,
1026 (void *) new_field,
1027 MSET_ANY))
1029 /* Out of memory. */
1030 return NULL;
1033 rec_mset_iterator_free (&iter);
1035 return merge;
1038 static rec_rset_t
1039 rec_db_join (rec_db_t db,
1040 const char *type1,
1041 const char *field,
1042 const char *type2)
1044 /* Note that this function is inefficient like hell. */
1046 /* Perform the join of the specified record sets, using TYPE1.Field
1047 = TYPE2.Key as the join criteria. If some of the specified
1048 record sets don't exist as named rset in the specified database
1049 then return NULL. */
1051 const char *key = NULL;
1052 rec_rset_t join = NULL;
1053 rec_rset_t rset1 = rec_db_get_rset_by_type (db, type1);
1054 rec_rset_t rset2 = rec_db_get_rset_by_type (db, type2);
1057 if (!rset1 || !rset2)
1059 return NULL;
1062 /* Determine the key field of the second record set. */
1063 key = rec_rset_key (rset2);
1064 if (!key)
1066 return NULL;
1069 /* Do the join. */
1071 join = rec_rset_new ();
1072 if (!join)
1074 /* Out of memory. */
1075 return NULL;
1077 else
1079 rec_record_t record1 = NULL;
1080 rec_mset_iterator_t iter1 = rec_mset_iterator (rec_rset_mset (rset1));
1081 while (rec_mset_iterator_next (&iter1, MSET_RECORD, (const void **) &record1, NULL))
1083 /* For each field record1.key in this record we scan the
1084 second record set for record1.field == record2.key
1085 instances. */
1087 size_t num_foreign_keys = rec_record_get_num_fields_by_name (record1, field);
1088 size_t num_foreign_key = 0;
1090 for (num_foreign_key = 0; num_foreign_key < num_foreign_keys; num_foreign_key++)
1092 rec_record_t record2 = NULL;
1093 rec_mset_iterator_t iter2 = rec_mset_iterator (rec_rset_mset (rset2));
1095 while (rec_mset_iterator_next (&iter2, MSET_RECORD, (const void **) &record2, NULL))
1098 /* Continue only if there is a field in record1 such as:
1099 record1.field == record2.key. */
1101 bool found = false;
1102 size_t i = 0;
1104 rec_field_t key_field = rec_record_get_field_by_name (record2, key, num_foreign_key);
1105 if (!key_field)
1107 /* A record without a key is an integrity error, but
1108 none of our business, so just skip it. */
1109 break;
1112 found = false;
1113 for (i = 0; i < rec_record_get_num_fields_by_name (record1, field); i++)
1115 if (strcmp (rec_field_value (key_field),
1116 rec_field_value (rec_record_get_field_by_name (record1, field, i))) == 0)
1118 found = true;
1119 break;
1123 if (!found)
1125 /* Skip this combination record. */
1126 continue;
1129 /* Merge record1 and record2 into a new record. */
1131 rec_record_t record = rec_db_merge_records (record1, record2, field);
1132 if (!record)
1134 /* Out of memory. */
1135 return NULL;
1138 /* Remove all the occurrences of the 'field' from
1139 record1, which were substituted in the merge. */
1141 while (rec_record_get_num_fields_by_name (record, field) > 0)
1143 rec_record_remove_field_by_name (record, field, 0);
1146 /* Add it into the join result. */
1148 rec_record_set_container (record, join);
1149 if (!rec_mset_append (rec_rset_mset (join), MSET_RECORD, (void *) record, MSET_ANY))
1151 /* Out of memory. */
1152 return NULL;
1155 rec_mset_iterator_free (&iter2);
1158 rec_mset_iterator_free (&iter1);
1161 /* The descriptor of the new record set will define records of type
1162 TYPE_FIELD, where FIELD is the name specified to trigger the
1163 operation. The contents of the descriptor will be just the
1164 %rec entry. */
1167 rec_record_t new_descriptor = rec_record_new ();
1168 if (!new_descriptor)
1170 /* Out of memory. */
1171 return NULL;
1174 /* Set the type of the joined record set. */
1177 rec_field_t new_field = NULL;
1178 char *new_rset_type = rec_concat_strings (type1, "_", field);
1179 if (!new_rset_type)
1181 /* Out of memory. */
1182 return NULL;
1185 new_field = rec_field_new (rec_std_field_name (REC_FIELD_REC),
1186 new_rset_type);
1187 if (!rec_mset_append (rec_record_mset (new_descriptor),
1188 MSET_FIELD,
1189 (void *) new_field,
1190 MSET_ANY))
1192 /* Out of memory. */
1193 return NULL;
1197 rec_rset_set_descriptor (join, new_descriptor);
1200 return join;
1203 static bool
1204 rec_db_set_act_rename (rec_rset_t rset,
1205 rec_record_t record,
1206 rec_fex_t fex,
1207 bool rename_descriptor,
1208 const char *arg)
1210 size_t j, min, max, renamed;
1211 size_t num_fields;
1212 rec_fex_elem_t fex_elem;
1213 rec_field_t field;
1214 const char *field_name;
1216 /* Rename the selected fields. The size of the FEX is guaranteed to
1217 be 1 at this point. */
1219 fex_elem = rec_fex_get (fex, 0);
1220 field_name = rec_fex_elem_field_name (fex_elem);
1221 min = rec_fex_elem_min (fex_elem);
1222 max = rec_fex_elem_max (fex_elem);
1224 num_fields =
1225 rec_record_get_num_fields_by_name (record, field_name);
1226 if (min == -1)
1228 /* Process all the fields with the given name. */
1229 min = 0;
1230 max = num_fields - 1;
1232 if (max == -1)
1234 max = min;
1237 renamed = 0;
1238 for (j = 0; j < num_fields; j++)
1240 if ((j >= min) && (j <= max))
1242 /* Set the name of the Jth field
1243 named FIELD_NAME, if it exists.*/
1244 field = rec_record_get_field_by_name (record,
1245 field_name,
1246 j - renamed);
1247 if (field)
1249 rec_field_set_name (field, arg);
1250 renamed++;
1253 if (rename_descriptor)
1256 rec_rset_rename_field (rset,
1257 field_name,
1258 arg);
1263 return true;
1267 static bool
1268 rec_db_set_act_set (rec_rset_t rset,
1269 rec_record_t record,
1270 rec_fex_t fex,
1271 bool add_p,
1272 const char *arg)
1274 size_t i, j, min, max;
1275 size_t num_fields;
1276 rec_fex_elem_t fex_elem;
1277 rec_field_t field;
1278 const char *field_name;
1280 for (i = 0; i < rec_fex_size (fex); i++)
1282 fex_elem = rec_fex_get (fex, i);
1283 field_name = rec_fex_elem_field_name (fex_elem);
1284 min = rec_fex_elem_min (fex_elem);
1285 max = rec_fex_elem_max (fex_elem);
1287 num_fields =
1288 rec_record_get_num_fields_by_name (record, field_name);
1289 if (min == -1)
1291 /* Process all the fields with the given name. */
1292 min = 0;
1293 max = num_fields - 1;
1295 if (max == -1)
1297 max = min;
1300 for (j = 0; j < num_fields; j++)
1302 if ((j >= min) && (j <= max))
1304 /* Set the value of the Jth field
1305 named FIELD_NAME, if it exists.*/
1306 field = rec_record_get_field_by_name (record,
1307 field_name,
1309 if (field)
1311 rec_field_set_value (field, arg);
1316 if (add_p && (num_fields == 0))
1318 /* Add a field with this name and value. */
1319 field = rec_field_new (field_name, arg);
1320 if (!rec_mset_append (rec_record_mset (record), MSET_FIELD, (void *) field, MSET_ANY))
1322 /* Out of memory. */
1323 return false;
1328 return true;
1331 static bool
1332 rec_db_set_act_add (rec_rset_t rset,
1333 rec_record_t record,
1334 rec_fex_t fex,
1335 const char *arg)
1337 size_t i;
1339 /* Create new fields from the FEX and add them to the record. */
1340 for (i = 0; i < rec_fex_size (fex); i++)
1342 rec_fex_elem_t fex_elem = rec_fex_get (fex, i);
1343 const char *field_name = rec_fex_elem_field_name (fex_elem);
1344 rec_field_t field = rec_field_new (field_name, arg);
1345 if (!field)
1347 /* Out of memory. */
1348 return false;
1351 if (!rec_mset_append (rec_record_mset (record), MSET_FIELD, (void *) field, MSET_ANY))
1353 /* Out of memory. */
1354 return false;
1358 return true;
1361 static bool
1362 rec_db_set_act_delete (rec_rset_t rset,
1363 rec_record_t record,
1364 rec_fex_t fex,
1365 bool comment_out)
1367 size_t i, j;
1368 size_t num_fields;
1369 bool *deletion_mask;
1370 rec_field_t field;
1371 rec_mset_iterator_t iter;
1372 rec_mset_elem_t elem;
1374 /* Initialize the deletion mask. */
1375 deletion_mask = malloc (sizeof (bool) * rec_record_num_fields (record));
1376 if (!deletion_mask)
1378 /* Out of memory. */
1379 return false;
1382 for (i = 0; i < rec_record_num_fields (record); i++)
1384 deletion_mask[i] = false;
1387 /* Mark fields that will be deleted from the record. */
1388 for (i = 0; i < rec_fex_size (fex); i++)
1390 rec_fex_elem_t fex_elem = rec_fex_get (fex, i);
1391 const char *field_name = rec_fex_elem_field_name (fex_elem);
1392 size_t min = rec_fex_elem_min (fex_elem);
1393 size_t max = rec_fex_elem_max (fex_elem);
1395 num_fields =
1396 rec_record_get_num_fields_by_name (record, field_name);
1397 if (min == -1)
1399 /* Delete all the fields with the given name. */
1400 min = 0;
1401 max = num_fields - 1;
1403 if (max == -1)
1405 max = min;
1408 for (j = 0; j < num_fields; j++)
1410 if ((j >= min) && (j <= max))
1412 /* Mark this field for deletion. */
1413 field = rec_record_get_field_by_name (record,
1414 rec_fex_elem_field_name (fex_elem),
1416 deletion_mask[rec_record_get_field_index (record, field)] = true;
1421 /* Delete the marked fields. */
1422 i = 0;
1424 iter = rec_mset_iterator (rec_record_mset (record));
1425 while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &field, &elem))
1427 if (deletion_mask[i])
1429 if (comment_out)
1431 /* Turn the field into a comment. */
1433 rec_comment_t comment = rec_field_to_comment (field);
1434 if (!comment)
1436 /* Out of memory. */
1437 return false;
1440 rec_field_destroy (field);
1441 rec_mset_elem_set_data (elem, (void *) comment);
1442 rec_mset_elem_set_type (elem, MSET_COMMENT);
1444 else
1446 /* Remove the field from the list and dispose it. */
1448 rec_mset_remove_elem (rec_record_mset (record), elem);
1452 i++;
1454 rec_mset_iterator_free (&iter);
1456 return true;
1459 static bool
1460 rec_db_index_p (size_t *index,
1461 size_t num)
1463 while ((index[0] != REC_Q_NOINDEX) || (index[1] != REC_Q_NOINDEX))
1465 bool found = false;
1466 size_t min = index[0];
1467 size_t max = index[1];
1469 if (max == REC_Q_NOINDEX)
1471 found = (num == min);
1473 else
1475 found = ((num >= min) && (num <= max));
1478 if (found)
1480 return true;
1483 index = index + 2;
1486 return false;
1489 static void
1490 rec_db_add_random_indexes (size_t **index,
1491 size_t num,
1492 size_t limit)
1494 /* Create NUM different random numbers in the [0..limit-1] range,
1495 without repetition, and store them in a buffer pointed by
1496 INDEX. */
1498 size_t i;
1499 char random_state[128];
1500 struct random_data random_data;
1502 *index = malloc (sizeof(size_t) * ((num + 1) * 2));
1503 if (*index == NULL)
1505 /* Out of memory. */
1506 return;
1509 for (i = 0; i < ((num + 1) * 2); i++)
1511 (*index)[i] = REC_Q_NOINDEX;
1514 /* Insert the random indexes. */
1516 memset (&random_data, 0, sizeof (random_data));
1517 initstate_r (time(NULL), (char *) &random_state, 128, &random_data);
1518 for (i = 0; i < (num * 2); i = i + 2)
1520 size_t random_value = 0;
1522 random_r (&random_data, (int32_t *) &random_value); /* Can't fail. */
1523 random_value = random_value % limit;
1525 /* Avoid having repeated random indexes. */
1527 if (rec_db_index_p (*index, random_value))
1529 /* Pick the first available number. */
1531 size_t i;
1532 for (i = 0; i < limit; i++)
1534 if (!rec_db_index_p (*index, i))
1536 random_value = i;
1537 break;
1542 (*index)[i] = random_value; /* Min. */
1543 (*index)[i+1] = REC_Q_NOINDEX; /* Max. */
1547 static bool
1548 rec_db_record_selected_p (size_t num_record,
1549 rec_record_t record,
1550 size_t *index,
1551 rec_sex_t sex,
1552 const char *fast_string,
1553 bool case_insensitive_p)
1555 /* Note that the logic in this function assumes that SEX and
1556 FAST_STRING are mutually exclusive. If they are not then
1557 FAST_STRING takes precedence. */
1559 /* The record is searched for instances of the "fast string", which
1560 can appear as a substring. */
1562 if (fast_string)
1564 return rec_record_contains_value (record,
1565 fast_string,
1566 case_insensitive_p);
1569 /* The selected expression is evaluated in the record. If there is
1570 an error evaluating the expression, or if the expression does not
1571 evaluate to 'true', then 'false' is returned. */
1573 if (sex)
1575 bool eval_status;
1576 return rec_sex_eval (sex, record, &eval_status);
1579 /* The memory pointed by INDEX contains pairs of indexes Min,Max.
1580 The final pair is always REC_Q_NOINDEX,REC_Q_NOINDEX. Select the
1581 current record only if its position is into some of the defined
1582 intervals. */
1584 if (index)
1586 return rec_db_index_p (index, num_record);
1589 return true;
1592 static rec_record_t
1593 rec_db_process_fex (rec_db_t db,
1594 rec_rset_t rset,
1595 rec_record_t record,
1596 rec_fex_t fex)
1598 rec_record_t res = NULL;
1599 size_t fex_size, i, j = 0;
1601 /* If fex is NULL then just return a copy of RECORD. Otherwise
1602 create an empty result record. */
1604 if (!fex)
1606 return rec_record_dup (record);
1609 res = rec_record_new ();
1610 if (!res)
1612 /* Out of memory. */
1613 return NULL;
1616 /* Iterate on the elements of the FEX, picking and transforming the
1617 fields of RECORD that must be copied and inserted into RES. If a
1618 function call is found in the fex then invoke the corresponding
1619 function and add the fields returned by that function into the
1620 record. */
1622 fex_size = rec_fex_size (fex);
1623 for (i = 0; i < fex_size; i++)
1625 rec_fex_elem_t elem = rec_fex_get (fex, i);
1626 const char *field_name = rec_fex_elem_field_name (elem);
1627 const char *alias = rec_fex_elem_rewrite_to (elem);
1628 const char *function_name = rec_fex_elem_function_name (elem);
1629 size_t min = rec_fex_elem_min (elem);
1630 size_t max = rec_fex_elem_max (elem);
1632 if (function_name)
1634 /* Get a handler for the aggregate function and invoke it on
1635 the rset or record, passing the field_name argument and
1636 the indexes. The value returned by the funciton is then
1637 appended into the current record in a new field, named
1638 after the name of the aggregate and the name of the
1639 argument field. Non-existing aggregates are simply
1640 ignored. */
1642 rec_aggregate_t func = rec_aggregate_reg_get (rec_db_aggregates (db), function_name);
1643 if (func)
1645 char *func_res = (func) (rset, record, field_name);
1646 if (func_res)
1648 /* Add a new field with the result of the aggregate
1649 as its value. */
1651 rec_field_t agg_field = NULL;
1652 char *agg_field_name = NULL;
1653 char *agg_field_value = func_res;
1655 /* The name of the new field is a composition of the
1656 name of the invoked function and the name of the
1657 field to which the function is applied. Unless
1658 an alias is used, of course. */
1660 if (alias)
1662 agg_field_name = strdup (alias);
1663 if (!agg_field_name)
1665 /* Out of memory. */
1666 return NULL;
1669 else
1671 agg_field_name = malloc (strlen(function_name) + 1 /* _ */ + strlen (field_name) + 1);
1672 if (!agg_field_name)
1674 /* Out of memory. */
1675 return NULL;
1678 memcpy (agg_field_name, function_name, strlen (function_name) + 1);
1679 strcat (agg_field_name, "_");
1680 strcat (agg_field_name, field_name);
1683 agg_field = rec_field_new (agg_field_name, agg_field_value);
1684 if (!agg_field)
1686 /* Out of memory. */
1687 return NULL;
1690 if (!rec_mset_append (rec_record_mset (res),
1691 MSET_FIELD,
1692 (void *) agg_field,
1693 MSET_FIELD))
1695 /* Out of memory. */
1696 return NULL;
1699 free (agg_field_name);
1700 free (func_res);
1704 else
1706 if ((min == -1) && (max == -1))
1708 /* Add all the fields with that name. */
1709 min = 0;
1710 max = rec_record_get_num_fields_by_name (record, field_name);
1712 else if (max == -1)
1714 /* Add just one field: Field[min]. */
1715 max = min + 1;
1717 else
1719 /* Add the interval min..max, max inclusive. */
1720 max++;
1723 /* Add the selected fields to the result record. */
1725 for (j = min; j < max; j++)
1727 rec_field_t res_field = NULL;
1728 rec_field_t field =
1729 rec_record_get_field_by_name (record, field_name, j);
1731 if (!field)
1733 continue;
1736 /* Duplicate the field and append it into 'res'. If there
1737 is a rewrite rule defined in this fex entry then use it
1738 instead of the original name of the field. */
1740 res_field = rec_field_dup (field);
1741 if (alias)
1743 if (!rec_field_set_name (res_field, alias))
1745 /* Out of memory. */
1746 return NULL;
1750 if (!rec_mset_append (rec_record_mset (res),
1751 MSET_FIELD,
1752 (void *) res_field,
1753 MSET_FIELD))
1755 /* Out of memory. */
1756 return NULL;
1762 /* At this point RES is a record containing all the selected fields
1763 of the original record, but we must also copy the location
1764 information. */
1766 if (record)
1768 rec_record_set_location (res, rec_record_location (record));
1769 rec_record_set_char_location (res, rec_record_char_location (record));
1772 return res;
1775 static bool
1776 rec_db_rset_equals_fn (const void *elt1,
1777 const void *elt2)
1779 return false;
1782 static void
1783 rec_db_rset_dispose_fn (const void *elt)
1785 rec_rset_t rset;
1787 rset = (rec_rset_t) elt;
1788 rec_rset_destroy (rset);
1791 /* End of rec-db.c */