4 * Date: Thu Jan 14 15:35:27 2010
6 * GNU recutils - Databases
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/>.
31 #include <gl_array_list.h>
34 #include <rec-utils.h>
43 size_t size
; /* Number of record sets contained
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
,
53 static void rec_db_rset_dispose_fn (const void *elt
);
55 static rec_record_t
rec_db_process_fex (rec_db_t db
,
60 static bool rec_db_record_selected_p (size_t num_rec
,
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
);
86 new = malloc (sizeof (struct rec_db_s
));
90 new->rset_list
= gl_list_nx_create_empty (GL_ARRAY_LIST
,
91 rec_db_rset_equals_fn
,
93 rec_db_rset_dispose_fn
,
96 if (new->rset_list
== NULL
)
103 /* Add the standard field functions to the registry in the
106 new->aggregates
= rec_aggregate_reg_new ();
107 if (!new->aggregates
)
113 rec_aggregate_reg_add_standard (new->aggregates
);
120 rec_db_destroy (rec_db_t db
)
124 rec_aggregate_reg_destroy (db
->aggregates
);
125 gl_list_free (db
->rset_list
);
131 rec_db_size (rec_db_t db
)
137 rec_db_get_rset (rec_db_t db
,
146 if (position
>= db
->size
)
148 position
= db
->size
- 1;
151 rset
= (rec_rset_t
) gl_list_get_at (db
->rset_list
, position
);
158 rec_db_insert_rset (rec_db_t db
,
168 node
= gl_list_nx_add_first (db
->rset_list
,
171 else if (position
>= db
->size
)
173 node
= gl_list_nx_add_last (db
->rset_list
,
178 node
= gl_list_nx_add_at (db
->rset_list
,
193 rec_db_remove_rset (rec_db_t db
, size_t position
)
201 if (position
>= db
->size
)
203 position
= db
->size
- 1;
206 if (gl_list_remove_at (db
->rset_list
,
218 rec_db_type_p (rec_db_t db
,
221 return (rec_db_get_rset_by_type (db
, type
) != NULL
);
225 rec_db_get_rset_by_type (rec_db_t db
,
234 for (i
= 0; i
< rec_db_size (db
); i
++)
236 rset
= rec_db_get_rset (db
, i
);
237 rtype
= rec_rset_type (rset
);
242 /* Return the default rset. */
250 && (strcmp (rtype
, type
) == 0))
267 rec_db_query (rec_db_t db
,
272 const char *fast_string
,
275 const char *password
,
280 rec_rset_t res
= NULL
;
281 rec_rset_t rset
= NULL
;
283 /* Create a new, empty, record set, that will contain the contents
286 res
= rec_rset_new ();
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
298 rset
= rec_db_get_rset_by_type (db
, type
);
301 /* If the default record set was selected, it was not found, and
302 the database contains only one record set, then it is
305 if (!type
&& (rec_db_size (db
) == 1))
307 rset
= rec_db_get_rset (db
, 0);
311 /* Type not found, so return an empty record set. */
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
);
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
349 if (flags
& REC_F_DESCRIPTOR
)
351 rec_record_t descriptor
= rec_rset_descriptor (rset
);
354 descriptor
= rec_record_dup (descriptor
);
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). */
372 rec_db_add_random_indexes (&index
, random
, rec_rset_num_records (rset
));
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
);
391 rec_record_set_container (record
, res
);
392 if (!rec_mset_append (rec_rset_mset (res
),
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
;
414 if (!rec_rset_sort (rset
, group_by
))
420 if (!rec_rset_group (rset
, group_by
))
427 if (!rec_rset_sort (rset
, sort_by
))
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
;
439 /* Determine whether we must skip this record. */
441 if (!rec_db_record_selected_p (num_rec
,
446 flags
& REC_F_ICASE
))
451 /* Process this record. */
453 /* Transform the record through the field expression and add
454 it to the result record set. */
457 = rec_db_process_fex (db
, rset
, record
, fex
);
465 /* Do not add empty records to the result record set. */
467 if (rec_record_num_elems (res_record
) == 0)
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. */
482 if (!rec_decrypt_record (rset
, res_record
, password
))
490 /* Remove duplicated fields if requested by the user. */
492 if (flags
& REC_F_UNIQ
)
494 rec_record_uniq (res_record
);
499 rec_record_set_container (res_record
, res
);
500 if (!rec_mset_append (rec_rset_mset (res
),
510 rec_mset_iterator_free (&iter
);
517 rec_db_insert (rec_db_t db
,
521 const char *fast_string
,
523 const char *password
,
527 /* Discard NULL or empty records. */
529 if (!record
|| (rec_record_num_fields (record
) == 0))
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
);
545 /* If the user requested to replace random records,
546 calculate them now for this record set. */
550 rec_db_add_random_indexes (&index
, random
, rec_rset_num_records (rset
));
558 /* Add auto generated fields unless the user disabled
561 if (!(flags
& REC_F_NOAUTO
))
563 if (!rec_rset_add_auto_fields (rset
, record
))
570 #if defined REC_CRYPT_SUPPORT
572 /* Encrypt confidential fields if a password was provided by
577 if (!rec_encrypt_record (rset
, record
, password
))
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
))
597 /* Shall we skip this record? */
599 if (!rec_db_record_selected_p (num_rec
,
604 flags
& REC_F_ICASE
))
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
);
621 /* Append the record in the proper record set. */
623 rec_rset_t rset
= rec_db_get_rset_by_type (db
, type
);
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
))
641 #if defined REC_CRYPT_SUPPORT
642 /* Encrypt confidential fields if a password was
647 if (!rec_encrypt_record (rset
, record
, password
))
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
),
663 rec_rset_descriptor_pos (rset
));
667 /* Insert the new record after the last record in the
670 rec_mset_t mset
= rec_rset_mset (rset
);
671 rec_record_t last_record
=
672 (rec_record_t
) rec_mset_get_at (mset
,
674 rec_rset_num_records (rset
) - 1);
676 if (!rec_mset_insert_after (mset
,
679 rec_mset_search (mset
, (void *) last_record
)))
688 /* Create a new type and insert the record there. */
690 rset
= rec_rset_new ();
697 rec_rset_set_type (rset
, type
);
698 rec_record_set_container (record
, rset
);
699 if (!rec_mset_append (rec_rset_mset (rset
),
710 rec_db_insert_rset (db
, rset
, rec_db_size (db
));
714 /* The default rset should always be placed in the
715 beginning of the db. */
717 rec_db_insert_rset (db
, rset
, 0);
726 rec_db_delete (rec_db_t db
,
730 const char *fast_string
,
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)
751 /* If the user requested to delete random records then calculate
752 them now for this record set. */
756 rec_db_add_random_indexes (&index
, random
, rec_rset_num_records (rset
));
764 /* Iterate on the records, deleting or commenting out the selected
768 rec_record_t record
= NULL
;
769 rec_mset_elem_t elem
;
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
))
777 if (!rec_db_record_selected_p (num_rec
,
782 flags
& REC_F_ICASE
))
787 if (flags
& REC_F_COMMENT_OUT
)
789 /* Replace the record with a comment in the current
792 rec_comment_t comment
= rec_record_to_comment (record
);
799 rec_record_destroy (record
);
800 rec_mset_elem_set_data (elem
, (void *) comment
);
801 rec_mset_elem_set_type (elem
, MSET_COMMENT
);
805 /* Remove the physical record from the record set and
808 rec_mset_remove_elem (rec_rset_mset (rset
), elem
);
811 rec_mset_iterator_free (&iter
);
817 bool rec_db_set (rec_db_t db
,
821 const char *fast_string
,
825 const char *action_arg
,
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)
845 /* If the user requested to manipulate random records then calculate
846 them now for this record set. */
850 rec_db_add_random_indexes (&index
, random
, rec_rset_num_records (rset
));
858 /* Iterate on the records, operating on the selected ones. */
861 rec_record_t record
= NULL
;
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
))
870 if (!rec_db_record_selected_p (num_rec
,
875 flags
& REC_F_ICASE
))
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
))
904 case REC_SET_ACT_SET
:
906 if (!rec_db_set_act_set (rset
, record
, fex
, false, action_arg
))
913 case REC_SET_ACT_ADD
:
915 if (!rec_db_set_act_add (rset
, record
, fex
, action_arg
))
922 case REC_SET_ACT_SETADD
:
924 if (!rec_db_set_act_set (rset
, record
, fex
, true, action_arg
))
931 case REC_SET_ACT_DELETE
:
933 if (!rec_db_set_act_delete (rset
, record
, fex
, false))
940 case REC_SET_ACT_COMMENT
:
942 if (!rec_db_set_act_delete (rset
, record
, fex
, true))
951 /* Ignore an invalid action. */
956 rec_mset_iterator_free (&iter
);
963 rec_db_aggregates (rec_db_t db
)
965 return db
->aggregates
;
973 rec_db_merge_records (rec_record_t record1
,
974 rec_record_t record2
,
977 rec_mset_iterator_t iter
;
979 rec_record_t merge
= NULL
;
981 merge
= rec_record_dup (record1
);
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
);
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);
1007 /* Out of memory. */
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. */
1024 if (!rec_mset_append (rec_record_mset (merge
),
1029 /* Out of memory. */
1033 rec_mset_iterator_free (&iter
);
1039 rec_db_join (rec_db_t db
,
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
)
1062 /* Determine the key field of the second record set. */
1063 key
= rec_rset_key (rset2
);
1071 join
= rec_rset_new ();
1074 /* Out of memory. */
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
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. */
1104 rec_field_t key_field
= rec_record_get_field_by_name (record2
, key
, num_foreign_key
);
1107 /* A record without a key is an integrity error, but
1108 none of our business, so just skip it. */
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)
1125 /* Skip this combination record. */
1129 /* Merge record1 and record2 into a new record. */
1131 rec_record_t record
= rec_db_merge_records (record1
, record2
, field
);
1134 /* Out of memory. */
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. */
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
1167 rec_record_t new_descriptor
= rec_record_new ();
1168 if (!new_descriptor
)
1170 /* Out of memory. */
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
);
1181 /* Out of memory. */
1185 new_field
= rec_field_new (rec_std_field_name (REC_FIELD_REC
),
1187 if (!rec_mset_append (rec_record_mset (new_descriptor
),
1192 /* Out of memory. */
1197 rec_rset_set_descriptor (join
, new_descriptor
);
1204 rec_db_set_act_rename (rec_rset_t rset
,
1205 rec_record_t record
,
1207 bool rename_descriptor
,
1210 size_t j
, min
, max
, renamed
;
1212 rec_fex_elem_t fex_elem
;
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
);
1225 rec_record_get_num_fields_by_name (record
, field_name
);
1228 /* Process all the fields with the given name. */
1230 max
= num_fields
- 1;
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
,
1249 rec_field_set_name (field
, arg
);
1253 if (rename_descriptor
)
1256 rec_rset_rename_field (rset
,
1268 rec_db_set_act_set (rec_rset_t rset
,
1269 rec_record_t record
,
1274 size_t i
, j
, min
, max
;
1276 rec_fex_elem_t fex_elem
;
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
);
1288 rec_record_get_num_fields_by_name (record
, field_name
);
1291 /* Process all the fields with the given name. */
1293 max
= num_fields
- 1;
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
,
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. */
1332 rec_db_set_act_add (rec_rset_t rset
,
1333 rec_record_t record
,
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
);
1347 /* Out of memory. */
1351 if (!rec_mset_append (rec_record_mset (record
), MSET_FIELD
, (void *) field
, MSET_ANY
))
1353 /* Out of memory. */
1362 rec_db_set_act_delete (rec_rset_t rset
,
1363 rec_record_t record
,
1369 bool *deletion_mask
;
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
));
1378 /* Out of memory. */
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
);
1396 rec_record_get_num_fields_by_name (record
, field_name
);
1399 /* Delete all the fields with the given name. */
1401 max
= num_fields
- 1;
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. */
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
])
1431 /* Turn the field into a comment. */
1433 rec_comment_t comment
= rec_field_to_comment (field
);
1436 /* Out of memory. */
1440 rec_field_destroy (field
);
1441 rec_mset_elem_set_data (elem
, (void *) comment
);
1442 rec_mset_elem_set_type (elem
, MSET_COMMENT
);
1446 /* Remove the field from the list and dispose it. */
1448 rec_mset_remove_elem (rec_record_mset (record
), elem
);
1454 rec_mset_iterator_free (&iter
);
1460 rec_db_index_p (size_t *index
,
1463 while ((index
[0] != REC_Q_NOINDEX
) || (index
[1] != REC_Q_NOINDEX
))
1466 size_t min
= index
[0];
1467 size_t max
= index
[1];
1469 if (max
== REC_Q_NOINDEX
)
1471 found
= (num
== min
);
1475 found
= ((num
>= min
) && (num
<= max
));
1490 rec_db_add_random_indexes (size_t **index
,
1494 /* Create NUM different random numbers in the [0..limit-1] range,
1495 without repetition, and store them in a buffer pointed by
1499 char random_state
[128];
1500 struct random_data random_data
;
1502 *index
= malloc (sizeof(size_t) * ((num
+ 1) * 2));
1505 /* Out of memory. */
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. */
1532 for (i
= 0; i
< limit
; i
++)
1534 if (!rec_db_index_p (*index
, i
))
1542 (*index
)[i
] = random_value
; /* Min. */
1543 (*index
)[i
+1] = REC_Q_NOINDEX
; /* Max. */
1548 rec_db_record_selected_p (size_t num_record
,
1549 rec_record_t record
,
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. */
1564 return rec_record_contains_value (record
,
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. */
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
1586 return rec_db_index_p (index
, num_record
);
1593 rec_db_process_fex (rec_db_t db
,
1595 rec_record_t record
,
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. */
1606 return rec_record_dup (record
);
1609 res
= rec_record_new ();
1612 /* Out of memory. */
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
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
);
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
1642 rec_aggregate_t func
= rec_aggregate_reg_get (rec_db_aggregates (db
), function_name
);
1645 char *func_res
= (func
) (rset
, record
, field_name
);
1648 /* Add a new field with the result of the aggregate
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. */
1662 agg_field_name
= strdup (alias
);
1663 if (!agg_field_name
)
1665 /* Out of memory. */
1671 agg_field_name
= malloc (strlen(function_name
) + 1 /* _ */ + strlen (field_name
) + 1);
1672 if (!agg_field_name
)
1674 /* Out of memory. */
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
);
1686 /* Out of memory. */
1690 if (!rec_mset_append (rec_record_mset (res
),
1695 /* Out of memory. */
1699 free (agg_field_name
);
1706 if ((min
== -1) && (max
== -1))
1708 /* Add all the fields with that name. */
1710 max
= rec_record_get_num_fields_by_name (record
, field_name
);
1714 /* Add just one field: Field[min]. */
1719 /* Add the interval min..max, max inclusive. */
1723 /* Add the selected fields to the result record. */
1725 for (j
= min
; j
< max
; j
++)
1727 rec_field_t res_field
= NULL
;
1729 rec_record_get_field_by_name (record
, field_name
, j
);
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
);
1743 if (!rec_field_set_name (res_field
, alias
))
1745 /* Out of memory. */
1750 if (!rec_mset_append (rec_record_mset (res
),
1755 /* Out of memory. */
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
1768 rec_record_set_location (res
, rec_record_location (record
));
1769 rec_record_set_char_location (res
, rec_record_char_location (record
));
1776 rec_db_rset_equals_fn (const void *elt1
,
1783 rec_db_rset_dispose_fn (const void *elt
)
1787 rset
= (rec_rset_t
) elt
;
1788 rec_rset_destroy (rset
);
1791 /* End of rec-db.c */