📄 ug_ch5b.htm
字号:
/* fetch each member of set and display text */while (d_findnm(CUST_NOTES, task, CURR_DB) == S_OKAY) { d_recread(text, task, CURR_DB); printf("%s\n", text);}</font></pre><p><font size="2">Each member of the <b>cust_notes</b> set is anoccurrence of either the <b>text30</b>, <b>text55</b>, or<b>text80</b> record types. Here it does not matter which recordtype is read, since each contains only one string field. Thecharacter array <b>text</b> is used to store the contents of all.The function <b>d_crtype</b>, however, could have been used todetermine the type of the text records.</font></p><p><b><a name="tims"></a>Database Examples from tims</b></p><p>One of the requirements for the <b>tims</b> database exampleswas to list technical publications in the library by key word orphrase. This involves traversing the many-to-many relationshipbetween the <b>key_word</b> record and the <b>info</b> record twice(once to get the <b>info</b> record from the specified key word,and again to retrieve all of the key words associated with thatlocated info record), and then scanning the <b>abstract</b> set toretrieve the text for the abstract.</p><p>Function <b>by_key</b> lists all of the <b>info</b> records thathave the user-entered key word or phrase. For each <b>info</b>record selected, all of its key words and its abstract areprinted.</p><pre><font color="#0000FF">#include <stdio.h>#include "db.star.h"#include "tims.h"extern DB_TASK *task;/* Find publications by key word or phrase */ by_key(){ struct info irec; /* info record variable */ char name[SIZEOF_NAME]; /* author's name */ char key[SIZEOF_KWORD]; /* key word */ /* find key word record */ printf("key word: "); gets(key); if (d_keyfind(KWORD, key, task, CURR_DB) == S_NOTFOUND) printf("no records found\n"); else { /* scan thru key_to_info set */ d_setor(KEY_TO_INFO, task, CURR_DB); for ( status = d_findfm(KEY_TO_INFO, task, CURR_DB); status == S_OKAY; status = d_findnm(KEY_TO_INFO, task, CURR_DB)) { /* find curr owner of curr intersect record and read it */ d_findco(INFO_TO_KEY, task, CURR_DB); d_recread(&irec, task, CURR_DB); /* find author of info record */ d_findco(HAS_PUBLISHED, task, CURR_DB); d_crread(NAME, name, task, CURR_DB); /* print results */ printf("id_code : %s\n", irec.id_code); printf("author : %s\n", name); printf("title : %s\n", irec.info_title); printf("publ. : %s, %s\n", irec.publisher, irec.pub_date); pr_keywords(); pr_abstract(); } }}</font></pre><p><font size="2">Figure 5-2 illustrates the operation of function<b>by_key</b> up to the point where function <b>pr_keywords</b> iscalled. The <b>d_keyfind</b> locates the <b>key_word</b> recordoccurrence, which is then made the current owner of set<b>key_to_info</b>. As each intersect record that is a member ofthe <b>info_to_key</b> set is found (using<b>d_findnm</b>(KEY_TO_INFO, CURR_DB)), its owner through the<b>info_to_key</b> set is found (using <b>d_</b>findco(INFO_TO_KEY,CURR_DB)), and the <b>info</b> record contents are read. The<b>author</b> is found (and made current) through the<b>has_published</b> set (using <b>d_findco</b>(HAS_PUBLISHED,CURR_DB)) and the name is read using function <b>d_crread</b> toread a field of the current record.</font></p><p align="center"> </p><p align="center"><img alt="dbstar_5-2.gif - 5385 Bytes" border="0"height="292" src="dbstar_5-2.gif" width="401"></p><p align="center">Fig. 5-2. Function by_key Operation</p><p>Function <b>pr_keywords</b> is called to print all of the keywords and phrases associated with an <b>info</b> record (note thatat least one key word will appear in each list, the one chosen inthe call to <b>by_key</b>). Function <b>d_members</b> returns, invariable <b>count</b>, the number of members in set<b>info_to_key</b>. If there are any members, then the owner ofeach intersect member record is found through the<b>key_to_info</b> set, and from this owner record the key word isread and displayed. This function (<b>pr_keywords</b>) will changethe currency associated with set <b>key_to_info</b>, which is usedby function <b>by_key</b> in its scanning of that set. Thus, it isnecessary for the current member of <b>key_to_info</b> to be saved(by <b>d_csmget</b>) before the key words are retrieved, and thenrestored (by <b>d_csmset</b>, which sets both current member andcurrent owner) after they have been retrieved.</p><pre><font color="#0000FF">/* Print key words */pr_keywords(){ long count; /* number of info_to_key members */ char key[SIZEOF_KWORD] /* key word or phrase */ DB_ADDR dba; /* db addr of key_to_info member */ /* the current member of the has_published set is the info record whose key words are to be listed */ d_setom(INFO_TO_KEY, HAS_PUBLISHED, task, CURR_DB); /* fetch number of members of info_to_key */ d_members(INFO_TO_KEY, &count, task, CURR_DB); /* list the key words, if any */ if (count > 0L) { /* save current member of key_to_info because it's going to change and we may be currently scanning though that set */ d_csmget(KEY_TO_INFO, &dba, task, CURR_DB); printf("key words:\n----------\n"); /* find each intersect member record */ while (d_findnm(INFO_TO_KEY, task, CURR_DB) == S_OKAY) { /* find, read and print corresponding key_word */ d_findco(KEY_TO_INFO, task, CURR_DB); d_crread(KWORD, key, task, CURR_DB); printf(" %s\n", key); } printf("\n"); /* reset key_to_info current member and owner */ if (dba != NULL_DBA) d_csmset(KEY_TO_INFO, &dba, task, CURR_DB); }}</font></pre><p><font size="2">The abstract is printed by function<b>pr_abstract</b>, which simply scans through the abstract setowned by the current <b>info</b> record to read and display eachline of abstract text.</font></p><pre><font color="#0000FF">/* Print abstract */pr_abstract(){ long count; /* number of abstract members */ char txt[SIZEOF_LINE]; /* line of abstract text */ /* the current member of has_published is the info record whose abstract is to be printed */ d_setom(ABSTRACT, HAS_PUBLISHED, task, CURR_DB); /* fetch number of lines in abstract */ d_members(ABSTRACT, &count, task, CURR_DB); /* print abstract, if one exists */ if ( count > 0L ) { printf("abstract:\n---------\n"); /* find, read and print each abstract text line */ while (d_findnm(ABSTRACT, task, CURR_DB) == S_OKAY) { d_csmread(ABSTRACT, LINE, txt, task, CURR_DB); printf(" %s\n", txt); } } printf("\n");}</font></pre><p><font size="2">The other retrieval requirement is to be able tolist all of the publications in the <b>tims</b> database that areby a particular author. This is accomplished with function<b>by_author</b>. The author is located by scanning through the(system-owned) <b>author_list</b> set, and comparing auser-specified name with the author name. When a match is found,each <b>info</b> record owned by the located author is read anddisplayed, along with its associated key words andabstract.</font></p><pre><font color="#0000FF">/* Find publication by author */by_author(){ int status; struct info irec; /* info rec variable */ char search[SIZEOF_NAME]; /* author to search for */ char name[SIZEOF_NAME]; /* find author record */ printf("author: "); gets(search); for (status = d_findfm(AUTHOR_LIST, task, CURR_DB); status == S_OKAY; status = d_findnm(AUTHOR_LIST, task, CURR_DB)) { d_crread(NAME, name, task, CURR_DB); if (strcmp(search, name) == 0) break; else if (strcmp(search, name) < 0) { status = S_NOTFOUND; break; /* sorted alphabetically */ } } if (status == S_OKAY ) { d_setor(HAS_PUBLISHED, task, CURR_DB); for (status = d_findfm(HAS_PUBLISHED, task, CURR_DB); status == S_OKAY; status = d_findnm(HAS_PUBLISHED, task, CURR_DB)) { /* read and print info record */ d_recread(&irec, task, CURR_DB); printf("id_code : %s\n", irec.id_code); printf("author : %s\n", name); printf("title : %s\n", irec.info_title); printf("publ. : %s, %s\n", irec.publisher, irec.pub_date); pr_keywords(); pr_abstract(); } } else printf("author record not found\n");}</font></pre><h3><a name="Direct"></a>5.4.3 Direct Access Retrieval</h3><p><font size="2">Direct access retrieval is used to locatesequentially all occurrences of a particular record type and todirectly read the contents of a record that has first been locatedby a key, set, or sequential retrieval. Sequential retrieval isperformed using these functions:</font></p><table cellspacing="0" border="0" cellpadding="7" width="542"><tr><td width="17%" valign="top"><p><b><font size="2">d_recfrst</font></b></p></td><td width="83%" valign="top"><p><font size="2">Locates the first occurrence on the data file ofthe specified record type.</font></p></td></tr><tr><td width="17%" valign="top"><p><b><font size="2">d_reclast</font></b></p></td><td width="83%" valign="top"><p><font size="2">Locates the last occurrence on the data file ofthe specified record type.</font></p></td></tr><tr><td width="17%" valign="top"><p><b><font size="2">d_recnext</font></b></p></td><td width="83%" valign="top"><p><font size="2">Finds the next occurrence of a record of the sametype.</font></p></td></tr><tr><td width="17%" valign="top"><p><b><font size="2">d_recprev</font></b></p></td><td width="83%" valign="top"><p><font size="2">Finds the next previous occurrence of a record ofthe same type.</font></p></td></tr></table><p><font size="2">When the retrieval order is not important (thephysical order of records on a file may seem random), thesequential functions are the quickest way to scan records. The<b>id_list</b> function is an example of such a scan.</font></p><pre><font color="#0000FF">/* produce a quick sequential listing of all id_code's */id_list(){ int status; char id_code[SIZEOF_ID_CODE]; for ( status = d_recfrst(INFO, task, CURR_DB); status == S_OKAY; status = d_recnext(task, CURR_DB)) { d_crread( ID_CODE, id_code, task, CURR_DB); printf("%s\n", id_code); }}</font></pre><p><font size="2">These functions maintain their own currency byrecord type. In a loop, these four functions will maintain theirown positional information, even if there are other functions inthe loop that change currency table settings. To establish orrestore a position from which to continue scanning, the function<b>d_recset</b> can be used. This function will set the currentposition of a sequential scan from the current record. Thus if a<b>d_recfrst/d_recnext</b> loop needs to contain an inner loop fora different record type, the position can be saved and restoredaround the inner loop, as follows:</font></p><pre><font color="#0000FF">DB_ADDR t1dba;int status1, status2;for ( status1 = d_recfrst(TYPE1, task, CURR_DB); status1 == S_OKAY; status1 = d_recnext(task, CURR_DB)) { d_crget(&t1dba, task, CURR_DB); ... for ( status2 = d_reclast(TYPE2, task, CURR_DB); status2 == S_OKAY; status2 = d_recprev(task, CURR_DB)) { ... } d_crset(&t1dba, task, CURR_DB); d_recset(TYPE1, task, CURR_DB);}</font></pre><p><font size="2">The function <b>page_full</b> begins with thecurrent record (which is assumed to be a <b>key_word</b> type), andcreates a list of the next twenty key word occurrences, as shownbelow:</font></p><pre><font color="#0000FF">/* create a list of key words for display */page_full( char **pglist, int dir ) { int i, status; for ( status = d_recset(KEY_WORD, task, CURR_DB), i = 0; (status == S_OKAY) && (i < 20); status = (dir ? d_recnext(task, CURR_DB) : d_recprev(task, CURR_DB)), i++ ) { d_crread(KWORD, pglist[i], task, CURR_DB); }}</font></pre><p><font size="2">Functions <b>d_recread</b>, <b>d_crread</b>,<b>d_csoread</b>, and <b>d_csmread</b> read part or all of thecontents of the current record, owner, or member, copying the datato an application program defined buffer. A pointer to this bufferis an argument to each of these functions.</font></p><p>Functions <b>d_decode_dba</b> and <b>d_encode_dba</b> are usedto decode and encode a database address with its file number andslot number. It can be used in conjunction with functions<b>d_crget</b> and <b>d_crset</b> to utilize a record's databaseaddress as a primary key, which can be displayed and referenced bya user in order to directly access individual record occurrences.For example, a database address for the record at slot number 17112on file number 11 could be displayed as a primary key field calledid number that, to the user, could look like the following:</p><pre><font color="#0000FF">id number: 11-17112</font></pre><p><font size="2">By always displaying this number (actually thedatabase address) when a record is displayed, and by requiring thisfield to be entered whenever the record is modified, the record canbe located in a single disk read. The code to display the fieldfollows.</font></p><pre><font color="#0000FF">DB_ADDR dba; /* database address of current record */short file; /* file number */unsigned long slot; /* slot number */.../* record to be displayed is current record */d_crget(&dba, task, CURR_DB);d_decode_dba(dba, &file, &slot);printf("id number: %d-%ld\n", file, slot);</font></pre><p><font size="2">When the user has entered an id number, therecord can be read as follows:</font></p><pre><font color="#0000FF">DB_ADDR dba; /* database address */int file; /* file number */unsigned long slot; /* slot number */struct record rec; /* db.* record buffer */.../* extract file number of slot number from id number string */... (you supply the tedious stuff)/* form database address */d_encode_dba(file, slot, &dba);/* set current record and read record contents */d_crset(&dba, task, CURR_DB);d_recread(&rec, task, CURR_DB);/* display record */...</font></pre><p><a href="UG_Ch5c.htm">Next Page</a></p></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -