Re: Comparing RECORD's
Posted in 1994
>From: root@candle.pha.pa.us (Bruce Momjian) >Subject: Comparing RECORD's >Date: Tue, 14 Jun 1994 04:05:20 GMT >X-Informix-List-Id: <news.7206> > >If I have two structures with idenical fields, is there an easy way to >see if the values in each of the fields is the same, without comparing >each and every field (with NULL checks too)? > >I need this because I am using a INPUT ARRAY statement, but want to >record the date each row changes. I am going to store the record in a >BEFORE ROW statement, and compare in an AFTER ROW statement. > >Is there a better way to do this? Succinctly, No. Here's what I wrote about 18 months ago when the question was asked: Date: Tue, 10 Nov 92 22:56:25 GMT From: uunet!obelix.informix.com!johnl (Jonathan Leffler) Subject: Re: Comparing/passing records in 4GL/C X-Informix-List-Id: <list.1584> >From: uunet!magnus.acs.ohio-state.edu!kbrummel (Karl P Brummel) >Subject: Comparing/passing records in 4GL/C >Date: 5 Nov 92 15:24:59 GMT >X-Informix-List-Id: <news.2067> >I'm interested in comparing two entire records at runtime, so I can tell if >one (which started out a copy of the first) is still the same as the first: >i.e., I want to detect if the record has been updated. I can't do something >like >if ( rec1 = rec2 ) then... >or >if (rec1.* = rec2.*) then... >in 4GL, and I don't seem to be able to find a way to pass a pointer to a >record to a C function. That's not very surprising -- there are no pointers anywhere in I4GL. >I can pass all the fields with "call myfunc(rec1.*,rec2.*)," but then I >have to pop all the fields off the stack, which means I have to know all >the fields in the record. What I want to do is get a pointer to the >first, a pointer to the second, find the size somehow (at run time) and do >a "memcmp(rec1,rec2,sizeof(rec));" or something similar. No chance. >The library function field_touched() almost does what I want, so there >must be a way to know this information at runtime. Any ideas how I write >field_changed()? I doubt if it does. What it does is tell you if the user typed anything in any of the fields in the input record. It may be that the user typed an 'A' over an existing 'A' -- that makes field_touched think something happened. And it only tells you if the record was modified during input. >Poking through the headers for 4GL didn't give me any great ideas. Bad luck -- it wouldn't have helped me either. Roughly speaking, what you have to do is, for each field in the record, is: LET is_changed = FALSE IF is_changed = FALSE THEN CASE WHEN rec1.columnA IS NULL AND rec2.columnA IS NULL LET is_changed = FALSE WHEN rec1.columnA IS NULL OR rec2.columnA IS NULL LET is_changed = TRUE WHEN rec1.columnA != rec2.columnA LET is_changed = TRUE --OTHERWISE --LET is_changed = FALSE END CASE END IF IF is_changed = FALSE THEN CASE WHEN rec1.columnB IS NULL AND rec2.columnB IS NULL ... END CASE END IF Obviously, for each field which cannot contain nulls, you only need the last test -- a darned sight easier. This algorithm can end up testing is_changed a few times, but it avoids poblems with the tests being indented off the RHS of the screen. This is non-trivial, especially on tables with 50-odd columns -- I normally use a shell script to generate the code, and I leave the shell script in the program as a set of comments, so if (when?) the table is changed, I can recreate the test automatically. Jonathan Leffler (johnl@informix.com) #include <disclaimer.h>