1 dnl Copyright (C) 2014 The Meme Factory, Inc. http://www.meme.com/
3 dnl This file is part of Gombe-MI.
5 dnl Gombe-MI is free software; you can redistribute it and/or modify
6 dnl it under the terms of the GNU General Public License as published by
7 dnl the Free Software Foundation; either version 3 of the License, or
8 dnl (at your option) any later version.
10 dnl This program is distributed in the hope that it will be useful,
11 dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
12 dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 dnl GNU General Public License for more details.
15 dnl You should have received a copy of the GNU General Public License
16 dnl along with Gombe-MI. If not, see <http://www.gnu.org/licenses/>.
18 dnl Functions to convert food and fishing from comments.
21 dnl It's grody to have so many macros but we're only running this once.
23 dnl Karl O. Pinc <kop@meme.com>
26 include(`copyright.m4')
27 include(`constants.m4')
29 include(`macros.m4')dnl
31 dnl The behavior code for eating.
32 define(`_ca_eating', `UE')
34 dnl plpgsql fragment for processing a focal's food comment
36 dnl Syntax: _process_eating_focal(focal, prefix)
38 dnl focal Either "mom", "infant", or "sib".
39 dnl prefix Either "MA", "INF", or "SIB".
42 define({_process_eating_focal},{
44 SELECT events.eid, events.uncertain
45 INTO this_eid, this_uncertain
47 JOIN parts ON (parts.eid = events.eid)
48 JOIN chimpids ON (chimpids.chimpid = parts.participant)
49 WHERE events.intid = this_intid
50 AND events.behavior = '_ca_eating'
51 AND chimpids.animid = $1
55 -- There is an eating behavior.
58 -- See if we have a food comment applicable to the $1.
61 SELECT regexp_matches(this_comment
62 -- don't try to split foodpart
63 , '(ALL|$2)FOOD!\[([^+]*)\+([^]]*)\]'
74 -- We do not have a food comment.
75 IF NOT($1_eating_or_fishing)
76 -- or the page has changed and the food behavior is
78 OR ($1_page != this_page
79 AND allfood_page != this_page
80 AND ($1_last_btime IS NULL
81 OR $1_last_btime + '1 minute'::INTERVAL
84 IF $1_page = this_page
85 AND allfood_page != this_page THEN
86 -- The $1 already has a food for the page.
89 ELSIF allfood_page = this_page
90 AND $1_page != this_page THEN
91 -- The $1 is eating the allfood that everybody else is eating.
92 $1_foodparts := allfood_foodparts;
93 $1_foodkind := allfood_foodkind;
94 $1_food_changed := FALSE; -- May have changed, we don't care.
96 ELSIF this_uncertain THEN
97 -- When the eating is uncertain we can have no food comment.
101 -- We must have a food comment to know what the $1 is eating.
102 RAISE EXCEPTION data_exception USING
103 MESSAGE = 'Error found in comment'
104 , DETAIL = 'Key (intervals.intid) = (' || this_intid
105 || '): Value (intervals.followid) = ('
107 || '): Value (follows.date) = ('
108 || (SELECT follows.date
110 WHERE follows.followid = this_followid
112 || '): Value mother (followparts.chimpid) = ('
114 || '): Value (intervals.time) = (' || this_time
115 || '): Value (intervals.comment) = ('
116 || textualize(`this_comment')
117 || '): No eating food comment for $1';
122 -- We have a food comment.
123 $1_food_comment := TRUE;
125 -- (We don't care if we had a food comment already or not.)
126 new_foodparts := TRIM(BOTH FROM foodcomment[2]);
127 new_foodkind := TRIM(BOTH FROM foodcomment[3]);
129 IF ($1_foodparts != new_foodparts OR $1_foodparts IS NULL
130 OR $1_foodkind != new_foodkind OR $1_foodkind IS NULL) THEN
131 $1_food_changed := TRUE;
132 $1_foodparts := new_foodparts;
133 $1_foodkind := new_foodkind;
136 -- Remember what kind of food comment we have.
137 IF foodcomment[1] = 'ALL' THEN
138 allfood_found := TRUE;
139 allfood_page := this_page;
140 allfood_foodparts := new_foodparts;
141 allfood_foodkind := new_foodkind;
142 mom_page := 0; -- hack
143 infant_page := 0; -- hack
144 sib_page := 0; -- hack
146 focalfood_found := TRUE;
147 $1_page := this_page;
148 allfood_page := 0; -- hack
151 -- We have too many food comments.
152 RAISE EXCEPTION data_exception USING
153 MESSAGE = 'Error found in comment'
154 , DETAIL = 'Key (intervals.intid) = (' || this_intid
155 || '): Value (intervals.followid) = ('
157 || '): Value (follows.date) = ('
158 || (SELECT follows.date
160 WHERE follows.followid = this_followid
162 || '): Value mother (followparts.chimpid) = ('
164 || '): Value (intervals.time) = (' || this_time
165 || '): Value (intervals.comment) = ('
167 || '): Too many food comments for $1';
170 -- Process the $1's foodcomment.
171 $1_processed := TRUE;
172 converted := converted + 1;
174 -- Update the old event with the new food code.
177 WHERE events.eid = this_eid;
180 -- Insert a made up EATS row.
181 INSERT INTO eats (eid, foodkind, foodpart)
182 VALUES (this_eid, 'UNRECORDED', 'NR');
184 -- Go through the $1's foodparts.
185 these_foodparts := regexp_split_to_array($1_foodparts, ';');
186 FOREACH this_foodpart IN ARRAY these_foodparts LOOP
187 this_foodpart := TRIM(BOTH FROM this_foodpart);
189 -- Create the EATS row.
190 INSERT INTO eats (eid, foodkind, foodpart)
191 SELECT this_eid, $1_foodkind, foodpart_map.newfp
193 WHERE foodpart_map.oldfp = this_foodpart;
196 RAISE EXCEPTION data_exception USING
197 MESSAGE = 'Error found in comment'
198 , DETAIL = 'Key (intervals.intid) = (' || this_intid
199 || '): Value (intervals.followid) = ('
201 || '): Value (follows.date) = ('
202 || (SELECT follows.date
204 WHERE follows.followid = this_followid
206 || '): Value mother (followparts.chimpid) = ('
208 || '): Value (intervals.time) = (' || this_time
209 || '): Value (intervals.comment) = ('
211 || '): Foodpart for $1 in comment ('
213 || ') is not a known old foodpart code';
216 END LOOP; -- Over $1 foodparts
220 $1_last_btime := this_time;
221 ELSE -- No $1 eating behavior.
223 -- Somebody's got a behavior
229 dnl plpgsql fragment for processing a focal's food comment
231 dnl Syntax: _process_fishing_focal(focal, prefix)
233 dnl focal Either "mom", "infant", or "sib".
234 dnl prefix Either "MA", "INF", or "SIB".
236 dnl This is almost identical to _process_eating_focal,
237 dnl the changes are in the behavior codes, error messages
238 dnl and inserting into FISHED,
239 dnl but it's too much trouble to abstract out the
243 define({_process_fishing_focal},{
244 -- Is the $1 fishing?
245 fishing_result := 'N'; -- not recorded
248 -- Infant fishing is recorded in the comments.
249 fishing_found := FALSE;
250 -- Ensure we capture the beginning and end of the comment
251 -- by putting a space on both ends.
252 devbeh_parts := REGEXP_SPLIT_TO_ARRAY(' ' || new_comment || ' '
253 , 'DEVBEH!\[[^]]*]');
254 IF ARRAY_LENGTH(devbeh_parts, 1) > 2 THEN
255 RAISE EXCEPTION data_exception USING
256 MESSAGE = 'Error found in comment'
257 , DETAIL = 'Key (intervals.intid) = (' || this_intid
258 || '): Value (intervals.followid) = ('
260 || '): Value (follows.date) = ('
261 || (SELECT follows.date
263 WHERE follows.followid = this_followid
265 || '): Value mother (followparts.chimpid) = ('
267 || '): Value (intervals.time) = (' || this_time
268 || '): Value (intervals.comment) = ('
269 || textualize(`this_comment')
270 || '): More than one DEVBEH![...] in fishing food comment for $1';
272 IF devbeh_parts[1] != (' ' || new_comment || ' ') THEN
273 -- There is a devbeh comment.
274 -- Get the content of the devbeh.
275 -- The existing Vua devbeh content does not contain
276 -- multiple entries, separated by semi-colon, so don't
280 IN SELECT REGEXP_MATCHES(new_comment , 'DEVBEH!\[([^]]*)]', 'g')
282 devbeh_whole_content := tmp_array[1];
283 FOREACH devbeh_content
284 IN ARRAY REGEXP_SPLIT_TO_ARRAY(TRIM(BOTH FROM devbeh_whole_content)
287 devbeh_content := TRIM(BOTH FROM devbeh_content);
288 IF devbeh_content ~* ('^' || infant || ' vua') THEN
289 -- This is a fishing devbeh comment.
290 fishing_found := TRUE;
292 IF devbeh_content ~* ('^' || infant || ' vua$') THEN
296 ~* ('^' || infant || ' vua' || ', negative results?$') THEN
297 fishing_result := 'U';
299 RAISE EXCEPTION data_exception USING
300 MESSAGE = 'Error found in comment'
301 , DETAIL = 'Key (intervals.intid) = (' || this_intid
302 || '): Value (intervals.followid) = ('
304 || '): Value (follows.date) = ('
305 || (SELECT follows.date
307 WHERE follows.followid = this_followid
309 || '): Value mother (followparts.chimpid) = ('
311 || '): Value (intervals.time) = ('
313 || '): Value (intervals.comment) = ('
314 || textualize(`this_comment')
315 || '): Unrecognized Vua DEVBEH![...]';
318 -- Get rid of the VUA devbeh.
319 new_comment := TRIM(BOTH FROM
320 ARRAY_TO_STRING(devbeh_parts, ''));
322 -- See if a Other events row exists for the infant's vua
323 SELECT events.eid, events.uncertain
324 INTO this_eid, this_uncertain
326 JOIN parts ON (parts.eid = events.eid)
328 ON (chimpids.chimpid = parts.participant)
329 WHERE events.intid = this_intid
330 AND events.behavior = 'O'
331 AND chimpids.animid = infant
333 = 'DEVBEH![' || devbeh_whole_content || ']'
338 -- -- We don't need the comment any more.
340 -- SET comment = NULL
341 -- WHERE events.eid = this_eid;
343 -- We don't have an events row. Make one.
345 := (SELECT NOT EXISTS
349 ON (parts.eid = events.eid)
353 WHERE events.intid = this_intid
354 AND NOT(events.uncertain)
355 AND chimpids.animid = infant
359 (intid, behavior, baboon
362 VALUES (this_intid, 'F', FALSE
364 , 'DEVBEH![' || devbeh_whole_content || ']');
366 this_eid := currval('events_eid_seq'::REGCLASS);
368 -- And we need a corresponding parts row.
369 INSERT INTO parts (eid, part, participant)
370 VALUES (this_eid, 'S', infant);
373 EXIT devbehs; -- Loop over DEVBEHs
375 END LOOP; -- over ; parsed devbeh content
376 END LOOP devbehs; -- Over DEVEBHs
381 -- Mom and sib have events rows for vua.
385 JOIN parts ON (parts.eid = events.eid)
386 JOIN chimpids ON (chimpids.chimpid = parts.participant)
387 WHERE events.intid = this_intid
388 AND events.behavior = 'VUA'
389 AND chimpids.animid = $1
392 fishing_found := FOUND;
395 IF fishing_found THEN
396 -- There is a fishing behavior.
397 makeup_food := FALSE;
399 -- See if we have a food comment applicable to the $1.
402 SELECT regexp_matches(this_comment
403 -- don't try to split foodpart
404 , '(ALL|$2)FOOD!\[([^+]*)\+([^]]*)\]'
415 -- We do not have a food comment.
416 IF NOT($1_eating_or_fishing)
417 -- or the page has changed and the food behavior is
419 OR ($1_page != this_page
420 AND allfood_page != this_page
421 AND ($1_last_btime IS NULL
422 OR $1_last_btime + '1 minute'::INTERVAL
425 IF $1_page = this_page
426 AND allfood_page != this_page THEN
427 -- The $1 already has a food for the page.
430 ELSIF allfood_page = this_page
431 AND $1_page != this_page THEN
432 -- The $1 is fishing the allfood that everybody else is fishing.
433 $1_foodparts := allfood_foodparts;
434 $1_foodkind := allfood_foodkind;
435 $1_food_changed := FALSE; -- May have changed, we don't care.
437 ELSIF this_uncertain THEN
438 -- When the eating is uncertain we can have no food comment.
442 -- We must have a food comment to know what the $1 is fishing for.
443 RAISE EXCEPTION data_exception USING
444 MESSAGE = 'Error found in comment'
445 , DETAIL = 'Key (intervals.intid) = (' || this_intid
446 || '): Value (intervals.followid) = ('
448 || '): Value (follows.date) = ('
449 || (SELECT follows.date
451 WHERE follows.followid = this_followid
453 || '): Value mother (followparts.chimpid) = ('
455 || '): Value (intervals.time) = (' || this_time
456 || '): Value (intervals.comment) = ('
457 || textualize(`this_comment')
458 || '): No fishing food comment for $1';
463 -- We have a food comment.
464 $1_food_comment := TRUE;
466 -- (We don't care if we had a food comment already or not.)
467 new_foodparts := TRIM(BOTH FROM foodcomment[2]);
468 new_foodkind := TRIM(BOTH FROM foodcomment[3]);
470 IF ($1_foodparts != new_foodparts OR $1_foodparts IS NULL
471 OR $1_foodkind != new_foodkind OR $1_foodkind IS NULL) THEN
472 $1_food_changed := TRUE;
473 $1_foodparts := new_foodparts;
474 $1_foodkind := new_foodkind;
477 -- Remember what kind of food comment we have.
478 IF foodcomment[1] = 'ALL' THEN
479 allfood_found := TRUE;
480 allfood_page := this_page;
481 allfood_foodparts := new_foodparts;
482 allfood_foodkind := new_foodkind;
483 mom_page := 0; -- hack
484 infant_page := 0; -- hack
485 sib_page := 0; -- hack
487 focalfood_found := TRUE;
488 $1_page := this_page;
489 allfood_page := 0; -- hack
492 -- We have too many food comments.
493 RAISE EXCEPTION data_exception USING
494 MESSAGE = 'Error found in comment'
495 , DETAIL = 'Key (intervals.intid) = (' || this_intid
496 || '): Value (intervals.followid) = ('
498 || '): Value (follows.date) = ('
499 || (SELECT follows.date
501 WHERE follows.followid = this_followid
503 || '): Value mother (followparts.chimpid) = ('
505 || '): Value (intervals.time) = (' || this_time
506 || '): Value (intervals.comment) = ('
508 || '): Too many food comments for $1';
511 -- Process the $1's foodcomment.
512 $1_processed := TRUE;
513 converted := converted + 1;
515 -- Update the old event with the new food code.
518 WHERE events.eid = this_eid;
521 -- Insert a made up FISHED row.
522 INSERT INTO fished (eid, foodkind, foodpart, result)
523 VALUES (this_eid, 'UNRECORDED', 'NR', 'N');
526 -- Go through the $1's foodparts.
527 these_foodparts := regexp_split_to_array($1_foodparts, ';');
528 FOREACH this_foodpart IN ARRAY these_foodparts LOOP
529 this_foodpart := TRIM(BOTH FROM this_foodpart);
531 -- Create the FISHED row.
532 INSERT INTO fished (eid, foodkind, foodpart
534 SELECT this_eid, $1_foodkind, foodpart_map.newfp
537 WHERE foodpart_map.oldfp = this_foodpart;
540 RAISE EXCEPTION data_exception USING
541 MESSAGE = 'Error found in comment'
542 , DETAIL = 'Key (intervals.intid) = (' || this_intid
543 || '): Value (intervals.followid) = ('
545 || '): Value (follows.date) = ('
546 || (SELECT follows.date
548 WHERE follows.followid = this_followid
550 || '): Value mother (followparts.chimpid) = ('
552 || '): Value (intervals.time) = (' || this_time
553 || '): Value (intervals.comment) = ('
555 || '): Foodpart for $1 in comment ('
557 || ') is not a known old foodpart code';
560 END LOOP; -- Over $1 foodparts
564 $1_last_btime := this_time;
565 ELSE -- No $1 fishing behavior.
567 -- Somebody's got a behavior
573 CREATE OR REPLACE FUNCTION prepared_data.convert_food(fromdate DATE,
578 gmi_function_set_search_path
580 -- Convert food from comments and unconverted eating behavior.
582 -- GPL_notice(` --', `2014', `The Meme Factory, Inc. http://www.meme.com/')
584 -- Syntax: select convert_food(fromdate, todate);
587 -- fromdate Date of earliest follows to convert (inclusive).
588 -- todate Date of latest follows to convert (inclusive).
591 -- Converts food for all follows on the date.
592 -- One-off program. Once it works we won't run it again.
597 this_followid follows.followid%TYPE;
603 SELECT follows.followid
605 WHERE follows.date >= fromdate
606 AND follows.date <= todate
607 ORDER BY follows.date, follows.followid
610 r := r + convert_food(this_followid);
616 grant_func_priv(`prepared_data.convert_food(DATE, DATE)')
620 CREATE OR REPLACE FUNCTION prepared_data.convert_food(followdate DATE
621 , mom VARCHAR(gmi_animid_len))
625 gmi_function_set_search_path
627 -- Convert food from comments and unconverted eating behavior.
629 -- GPL_notice(` --', `2014', `The Meme Factory, Inc. http://www.meme.com/')
631 -- Syntax: select convert_food(followdate, mom);
634 -- followdate Date of follow
635 -- mom chimpid of mom.
638 -- One-off program. Once it works we won't run it again.
642 this_followid follows.followid%TYPE;
647 SELECT follows.followid
650 JOIN followparts ON (followparts.followid = follows.followid)
651 JOIN followroles ON (followroles.role = followparts.role)
652 JOIN chimpids AS fcid ON (fcid.chimpid = followparts.chimpid)
653 JOIN chimpids AS this_cid ON (this_cid.animid = fcid.animid)
654 WHERE follows.date = followdate
655 AND followroles.function = 'gmi_mom'
656 AND this_cid.chimpid = mom;
662 RETURN convert_food(this_followid);
665 grant_func_priv(`prepared_data.convert_food(DATE, VARCHAR(gmi_animid_len))')
668 CREATE OR REPLACE FUNCTION prepared_data.convert_food(this_followid INT)
672 gmi_function_set_search_path
674 -- Convert food from comments and unconverted eating behavior.
676 -- GPL_notice(` --', `2014', `The Meme Factory, Inc. http://www.meme.com/')
678 -- Syntax: select convert_food(followid);
681 -- followid Followid of follow to convert.
684 -- One-off program. Once it works we won't run it again.
689 this_intid intervals.intid%TYPE;
690 this_time intervals.time%TYPE;
691 this_comment intervals.comment%TYPE;
692 this_page sheets.page%TYPE;
696 mom biography_data.animid%TYPE;
697 sib biography_data.animid%TYPE;
698 infant biography_data.animid%TYPE;
700 mom_last_btime intervals.time%TYPE;
701 sib_last_btime intervals.time%TYPE;
702 infant_last_btime intervals.time%TYPE;
706 infant_eating BOOLEAN;
710 infant_fishing BOOLEAN;
712 mom_eating_or_fishing BOOLEAN;
713 sib_eating_or_fishing BOOLEAN;
714 infant_eating_or_fishing BOOLEAN;
716 mom_foodkind eats.foodkind%TYPE;
717 infant_foodkind eats.foodkind%TYPE;
718 sib_foodkind eats.foodkind%TYPE;
721 infant_foodparts TEXT;
727 mom_page sheets.page%TYPE;
728 infant_page sheets.page%TYPE;
729 sib_page sheets.page%TYPE;
731 mom_processed BOOLEAN;
732 infant_processed BOOLEAN;
733 sib_processed BOOLEAN;
735 mom_food_comment BOOLEAN;
736 infant_food_comment BOOLEAN;
737 sib_food_comment BOOLEAN;
739 mom_food_changed BOOLEAN;
740 infant_food_changed BOOLEAN;
741 sib_food_changed BOOLEAN;
743 allfood_found BOOLEAN;
744 focalfood_found BOOLEAN;
746 fishing_found BOOLEAN;
747 fishing_result fished.result%TYPE;
750 allfood_foodkind TEXT;
751 allfood_foodparts TEXT;
756 devbeh_whole_content TEXT;
758 this_eid events.eid%TYPE;
759 this_uncertain events.uncertain%TYPE;
763 these_foodparts TEXT[];
765 comment_parts TEXT[];
768 food_fragment TEXT[];
774 -- Create a temporary table to map old foodpart codes to new.
775 CREATE TEMP TABLE IF NOT EXISTS
776 foodpart_map (oldfp TEXT PRIMARY KEY, newfp TEXT)
783 INSERT INTO foodpart_map (oldfp, newfp)
802 , ('UNRECORDED', 'NR')
803 , ('UNKNOWN', 'UNK');
806 -- Find mom, infant, and sib.
807 SELECT chimpids.animid
810 JOIN followroles ON (followroles.role = followparts.role)
811 JOIN chimpids ON (chimpids.chimpid = followparts.chimpid)
812 WHERE followparts.followid = this_followid
813 AND followroles.function = 'gmi_mom'
816 SELECT chimpids.animid
819 JOIN followroles ON (followroles.role = followparts.role)
820 JOIN chimpids ON (chimpids.chimpid = followparts.chimpid)
821 WHERE followparts.followid = this_followid
822 AND followroles.function = 'gmi_infant'
825 SELECT chimpids.animid
828 JOIN followroles ON (followroles.role = followparts.role)
829 JOIN chimpids ON (chimpids.chimpid = followparts.chimpid)
830 WHERE followparts.followid = this_followid
831 AND followroles.function = 'gmi_sib'
836 infant_eating := FALSE;
839 mom_fishing := FALSE;
840 infant_fishing := FALSE;
841 sib_fishing := FALSE;
843 mom_eating_or_fishing := FALSE;
844 infant_eating_or_fishing := FALSE;
845 sib_eating_or_fishing := FALSE;
853 mom_last_btime := NULL; -- time of last eating or fishing behavior
854 sib_last_btime := NULL;
855 infant_last_btime := NULL;
857 -- Go through all the intervals for the follow by time.
858 FOR this_intid, this_time, this_comment, this_page IN
859 SELECT intervals.intid, intervals.time, intervals.comment, sheets.page
861 JOIN sheets ON (sheets.sheetid = intervals.sheetid)
862 WHERE intervals.followid = this_followid
863 ORDER BY intervals.time
866 new_comment := this_comment;
868 mom_food_changed := FALSE;
869 infant_food_changed := FALSE;
870 sib_food_changed := FALSE;
872 mom_food_comment := FALSE;
873 infant_food_comment := FALSE;
874 sib_food_comment := FALSE;
876 -- Is the interval a badobs (no events)?
879 JOIN parts ON (parts.eid = events.eid)
880 JOIN chimpids ON (chimpids.chimpid = parts.participant)
881 WHERE events.intid = this_intid
884 badobs := NOT(FOUND);
886 mom_processed := FALSE;
887 infant_processed := FALSE;
888 sib_processed := FALSE;
889 -- badobs rows are ignored.
891 allfood_found := FALSE;
892 focalfood_found := FALSE;
895 _process_eating_focal(`mom', `MA')
896 _process_fishing_focal(`mom', `MA')
897 mom_eating_or_fishing := mom_eating OR mom_fishing;
899 _process_eating_focal(`infant', `INF')
900 _process_fishing_focal(`infant', `INF')
901 infant_eating_or_fishing := infant_eating OR infant_fishing;
903 _process_eating_focal(`sib', `SIB')
904 _process_fishing_focal(`sib', `SIB')
905 sib_eating_or_fishing := sib_eating OR sib_fishing;
907 IF allfood_found AND focalfood_found THEN
908 -- Can't have an allfood comment with a MA/INF/SIB food comment.
909 RAISE EXCEPTION data_exception USING
910 MESSAGE = 'Error found in comment'
911 , DETAIL = 'Key (intervals.intid) = (' || this_intid
912 || '): Value (intervals.followid) = ('
914 || '): Value (follows.date) = ('
915 || (SELECT follows.date
917 WHERE follows.followid = this_followid
919 || '): Value mother (followparts.chimpid) = ('
921 || '): Value (intervals.time) = (' || this_time
922 || '): Value (intervals.comment) = ('
924 || '): Cannot have both an ALLFOOD and a MA/INF/SIBFOOD in the comment';
926 END IF; -- badobs row
928 -- See that we have comments for the food of all focals
929 -- if any of the focal's foods have changed.
931 OR infant_food_changed
933 AND ((mom_eating_or_fishing AND NOT(mom_food_comment))
934 OR (infant_eating_or_fishing AND NOT(infant_food_comment))
935 OR (sib_eating_or_fishing AND NOT(sib_food_comment))) THEN
936 RAISE EXCEPTION data_exception USING
937 MESSAGE = 'Error found in comment'
938 , DETAIL = 'Key (intervals.intid) = (' || this_intid
939 || '): Value (intervals.followid) = ('
941 || '): Value (follows.date) = ('
942 || (SELECT follows.date
944 WHERE follows.followid = this_followid
946 || '): Value mother (followparts.chimpid) = ('
948 || '): Value (intervals.time) = (' || this_time
949 || '): Value (intervals.comment) = ('
951 || '): One of the focals has changed foodpart/foodkind but what is eaten by the other focals is not restated in the comments';
954 -- Clean up the comment.
955 IF mom_processed OR infant_processed OR sib_processed THEN
956 -- Get rid of any ALLFOOD comment that exists.
957 comment_parts := regexp_split_to_array(new_comment
958 , 'ALLFOOD!\[([^+]*)\+([^]]*)\]');
959 IF ARRAY_LENGTH(comment_parts, 1) > 1 THEN
960 new_comment := ARRAY_TO_STRING(comment_parts, '');
964 IF mom_processed THEN
965 -- Get rid of any MAFOOD comment that exists.
966 comment_parts := regexp_split_to_array(new_comment
967 , 'MAFOOD!\[([^+]*)\+([^]]*)\]');
968 IF ARRAY_LENGTH(comment_parts, 1) > 1 THEN
969 new_comment := ARRAY_TO_STRING(comment_parts, '');
973 IF infant_processed THEN
974 -- Get rid of any INFFOOD comment that exists.
975 comment_parts := regexp_split_to_array(new_comment
976 , 'INFFOOD!\[([^+]*)\+([^]]*)\]');
977 IF ARRAY_LENGTH(comment_parts, 1) > 1 THEN
978 new_comment := ARRAY_TO_STRING(comment_parts, '');
982 IF sib_processed THEN
983 -- Get rid of any SIBFOOD comment that exists.
984 comment_parts := regexp_split_to_array(new_comment
985 , 'SIBFOOD!\[([^+]*)\+([^]]*)\]');
986 IF ARRAY_LENGTH(comment_parts, 1) > 1 THEN
987 new_comment := ARRAY_TO_STRING(comment_parts, '');
991 -- Save the comment with the food stuff removed.
992 IF new_comment != this_comment THEN
993 IF TRIM(BOTH FROM new_comment) = '' THEN
997 -- Leave comments untouched.
999 -- SET comment = new_comment
1000 -- WHERE intervals.intid = this_intid;
1003 IF SUBSTRING(new_comment FROM 'FOOD!\[') IS NOT NULL THEN
1004 -- Change the food looking comment to a FOODRELATED comment.
1006 fixed_comment := this_comment;
1007 FOR food_fragment IN
1008 SELECT REGEXP_MATCHES(
1010 , '((?:(?:ALL)|(?:MA)|(?:INF)|(?:SIB))FOOD!\[[^]]*])'
1014 new_fragment := food_fragment[1];
1015 IF SUBSTRING(new_fragment FOR 2) = 'MA' THEN
1016 new_fragment := 'MAFOODRELATED' || SUBSTRING(new_fragment FROM 7);
1018 new_fragment := SUBSTRING(new_fragment FOR 3)
1020 || SUBSTRING(new_fragment FROM 8);
1023 p := POSITION(food_fragment[1] IN fixed_comment);
1024 l := CHAR_LENGTH(food_fragment[1]);
1025 fixed_comment := SUBSTRING(fixed_comment FOR p - 1)
1027 || SUBSTRING(fixed_comment FROM p + l);
1029 -- Change the comment in the new_comment too, just so we've
1030 -- something to test to see if there's something foodlike
1031 -- left in the comments.
1032 p := POSITION(food_fragment[1] IN new_comment);
1033 new_comment := SUBSTRING(new_comment FOR p - 1)
1035 || SUBSTRING(new_comment FROM p + l);
1039 -- Update the comment in the interval.
1041 SET comment = fixed_comment
1042 WHERE intervals.intid = this_intid;
1044 IF SUBSTRING(new_comment FROM 'FOOD!\[') IS NOT NULL THEN
1045 RAISE EXCEPTION data_exception USING
1046 MESSAGE = 'Error found in comment'
1047 , DETAIL = 'Key (intervals.intid) = (' || this_intid
1048 || '): Value (intervals.followid) = ('
1050 || '): Value (follows.date) = ('
1051 || (SELECT follows.date
1053 WHERE follows.followid = this_followid
1055 || '): Value mother (followparts.chimpid) = ('
1057 || '): Value (intervals.time) = (' || this_time
1058 || '): New Value For (intervals.comment) = ('
1060 || '): A food-looking comment remains but there is no _ca_eating, or VUA behavior (EVENTS row) or DEVBEH Vua comment for the corresponding focal for the interval';
1065 END LOOP; -- Over intervals for the follow/day.
1073 grant_func_priv(`prepared_data.convert_food(INT)')