Notes on NSonawane's asgnt3.c RJLRef: $PH/06f522/asgnt3/asgnt3_ns.rjlfdbk061106.txt Contents: 1. Nitin's asgnt3.c: ------------------------ Nitin's test driver has a commented-out call to the keyExists check function. This looks OK below in Nitin's agnt3.c, inside table_loop(VIEW_NAME, CQ) But note his name is keyValueListExists, not keyExists. One of you needs to change the name, UNLESS his function makes sub-calls to keyExists for each CA's field name. That is NOT acceptable if it searches the table over again for each key-component! Someone needs to break out the field values FIRST, and apply them in a logical AND condition inside ONE table loop. [And check signature for argtype agreement.] /* if (keyValueListExists (pr_get_str(CQcurr,CKname), pr_get_str(CQcurr,values)) {...} */ Note: At the end is an explanation of how and why I asked you earlier to use CandidateQueryGetCKname(CQid) and CandidateQueryGetvalues(CQid) instead of pr_get_str(CQcurr, CKname) and pr_get_str(CQcurr,values). 2. Consistency of CK and CQ format and content: ------------------------------------------- In asgnt3.msdat: TT010019 SV010001 CQ CandidateQueries /* Stored queries table */ TA010095 TT010019 CQid CQid c8 1 /* Query ID Primary Key */ TA010096 TT010019 cqname cqname t30 0 /* meaningful name */ TA010097 TT010019 CKname ?? c32 0 /* name of the candidate key for this query */ TA010098 TT010019 values values t80 0 /* A list of values to be checked for existance */ Table CQ in .msdat above was derived by chgen from $CASE/06f522/nsonawan/asgnt3/asgnt3.sch below: /* Added CQ table to store queries for regression testing */ ... CandidateQueries CQ /* Stored queries table */ { CQid CQid c8 1 /* Query ID Primary Key */ cqname cqname t30 0 /* A meaningful name */ CKname ?? c32 0 /* name of the candidate key for this query */ values values t80 0 /* A list of values to be checked for existance */ } In $CASE/06f522/nsonawan/asgnt3/asgnt3.out.dat: ... CK010003 TT010002 TermByName 1 ... CQ010002 CheckTermByName TermByName 06f (These are consistent, because TermByName in CQ#2 is the value in the CKname field of CK#3.) Hindsight wish-list for CQ schema definition: --------------------------------------------- Note 1: If CQ had contained instead the fkey CKid = CK010002, then pr_load would have assigned the right value to CKid_pp, to provide direct access to the parent CK-row of CQ and indirect access to the grand-parent TT-row. The cost of finding the right CK would be incurred once (at load time) instead of each time a query is executed. Note 2: If CQ's schema table was defined with field1, field2, ...fieldk, then loading (which pr_parse) a CQ-row instance would split the values string into separately named field values. (Chgen can NOT convert them from ASCII to internal form without enhancements or sub-classing of table CQ for each cqname. 3. Recommended field Get and Set methods: ---------------------- Get and set routine ought to use pr_accessors.c rather than pr_get/set_type, to improve encapsulation. (This incurs a pkey search whenever the pkey value changes). $CASE/067f522/nsonawan/asgnt3/pr_accessors.c explains that: ... ** SETROUTINE(int,EventInstance,EI,Int1,int) produces ** ** FUNCTION2( ** void EventInstanceSetInt1, ** hcg_key, EIid, ** int, value ** ) ** { ** pr_find(EI, EIid, EIid); ** EIcurr->Int1 = (int)value; ** } ** (I.e., void EventInstanceSetInt1(hcg_key EIid, int value) {...} ) ... ** ** GETROUTINE(const char *,ActiveInstance,AI,State) produces ** ** FUNCTION1( ** const char * ActiveInstanceGetState, ** hcg_key, AIid ** ) ** { ** pr_find(AI, AIid, AIid); ** if (AIcurr == 0) { ** return (const char *)0; ** } else { ** return (const char *)(AIcurr->State); ** } ** } ** (i.e., const char * ActiveInstanceGetState(hcg_key AIid) {...} ) ----------------------- Note: the ** comment giving examples in pr_accessors.c is an artifact from olcarch in GEN_LCP: it says the method name is based on ttname: e.g., CandidateQueriesGetvalue; however, the pr-accessors.c code generation project now uses ttabb = CQ instead of ttname for the method name, which is shorter (e.g., to CQGetvalue). So SETROUTINE(hcg_key,CandidateQueries,CQ,CQid,hcg_key,value) defines method hcg_key CQSetCQid(hcg_key CQid, hcg_key value) and GETROUTINE(hcg_key,CandidateQueries,CQ,CQid) defines method hcg_key CQGetCQid(hcg_key CQid) (You need to know CQid in order to find and return CQid, which doesn't make much sense. It is NOT legal to update an existing table row by setting a pkey. It is a BUG to update it by setting an fkey without relinking. EXCEPTION: You CAN set fkeys (but not pkeys) when constructing new rows. These are inserted by pr-add which installs ptrs via pr_link. SETROUTINE2(char*,CandidateQueries,CQ,cqname,char*,value) GETROUTINE(char*,CandidateQueries,CQ,cqname) SETROUTINE2(char*,CandidateQueries,CQ,CKname,char*,value) GETROUTINE(char*,CandidateQueries,CQ,CKname) SETROUTINE2(char*,CandidateQueries,CQ,values,char*,value) defines method hcg_key CQSetvalues(hcg_key CQid, char* value) {...} and GETROUTINE(char*,CandidateQueries,CQ,values) defines method char* CQGetvalues(hcg_key CQid) {...} ------------------ These are pkey-based methods. hcg_key is the pkey type. pr_find() is used to search for the pkey argument. The XXcurr value from pr-find is cached to avoid repeated searches for the SAME pkey value.