📄 ug_ch5c.htm
字号:
are used as sort fields in an ascending or descending set, andfunction <b>d_recwrite</b> is used to modify the contents of bothfields, better performance will result if you first disconnect therecord from the set before calling <b>d_recwrite</b> and thenreconnect the record after returning from <b>d_recwrite</b>.Otherwise, <b><i>db.*</i></b> will still adjust the position of theset for each field.</blockquote><p><font size="2">Optional keys are automatically modified if a keyexisted for the old value when its field was modified. If a keyentry did not exist for the old value, none will be created for thenew value. However, the field's value in the record isupdated.</font></p><h2><a name="Deletion" id="Deletion"></a>5.7 Data Deletion</h2><p><font size="2">The functions involved in data deletion appear inTable 5-7.</font></p><p align="center"><b>Table 5-7. Data Deletion Functions</b></p><table cellspacing="0" border="0" cellpadding="7" width="542"><tr><td width="39%" valign="top"><p><font size="2"><b>d_delete</b>(<i>task, dbn</i>)</font></p></td><td width="61%" valign="top"><p><font size="2">Delete current record.</font></p></td></tr><tr><td width="39%" valign="top"><p><font size="2"><b>d_keydel</b>(<i>KEY</i>, <i>task,dbn</i>)</font></p></td><td width="61%" valign="top"><p><font size="2">Delete optional key value.</font></p></td></tr><tr><td width="39%" valign="top"><p><font size="2"><b>d_discon</b>(<i>SET</i>, <i>task,dbn</i>)</font></p></td><td width="61%" valign="top"><p><font size="2">Disconnect current member from set.</font></p></td></tr><tr><td width="39%" valign="top"><p><font size="2"><b>d_disdel</b>(<i>task, dbn</i>)</font></p></td><td width="61%" valign="top"><p><font size="2">Disconnect current record from all sets anddelete it.</font></p></td></tr></table><p><font size="2">A record can only be deleted if it is notconnected as an owner or member of any sets. The general deletionprocedure is, therefore, to disconnect a record from all sets forwhich it is a member and disconnect all members from sets owned bythat record, and then delete the record. All disconnections and thedelete can be performed with one call by using function<b>d_disdel</b>.</font></p><p>Function <b>d_keydel</b> is used to delete the key entry of anoptional key field in the current record. The field value in therecord itself, however, does not change. All key entries, includingoptional keys, are deleted from their respective key files when arecord is deleted using either function <b>d_delete</b> or<b>d_disdel</b>.</p><p>Below is the code for function <b>del_info</b>, which deletes an<b>info</b> record from the <b>tims</b> database.</p><pre><font color="#0000FF">#include <stdio.h>#include "db.star.h"#include "tims.h"/* Delete technical information records from tims database */del_info(){ struct info irec; long count; char id[SIZEOF_ID_CODE], name[SIZEOF_NAME]; /* find info to be deleted */ printf("id_code: " ); gets(id); if (d_keyfind(ID_CODE, id, task, CURR_DB) == S_NOTFOUND) { printf("id_code %s not on file\n", id); return; } d_recread(&irec, task, CURR_DB); /* get author name */ d_findco(HAS_PUBLISHED, task, CURR_DB); d_crread(NAME, name, task, CURR_DB); ... /* confirm delete request */ ... /* disconnect and delete any listed articles */ ... /* disconnect and delete borrowers */ /* disconnect and delete abstract */ d_setom(ABSTRACT, HAS_PUBLISHED, task, CURR_DB); while (d_findfm(ABSTRACT, task, CURR_DB) == S_OKAY) { d_discon(ABSTRACT, task, CURR_DB); d_delete(task, CURR_DB); } /* disconnect and delete intersect and (possibly) key word */ d_setom(INFO_TO_KEY, HAS_PUBLISHED, task, CURR_DB); while (d_findfm(INFO_TO_KEY, task, CURR_DB) == S_OKAY) { d_discon(INFO_TO_KEY, task, CURR_DB); d_setmr(KEY_TO_INFO, task, CURR_DB); d_discon(KEY_TO_INFO, task, CURR_DB); d_delete(task, CURR_DB); d_members(KEY_TO_INFO, &count, task, CURR_DB); if (count == 0L) { /* delete key word */ d_setro(KEY_TO_INFO, task, CURR_DB); d_delete(task, CURR_DB); } } /* disconnect info record from author and delete */ d_discon(HAS_PUBLISHED, task, CURR_DB); d_delete(task, CURR_DB); /* delete author too, if he has no other pubs */ d_members(HAS_PUBLISHED, &count, task, CURR_DB); if (count == 0L) { d_setmo(AUTHOR_LIST, HAS_PUBLISHED, task, CURR_DB); d_discon(AUTHOR_LIST, task, CURR_DB); d_delete(task, CURR_DB); }}</font></pre><p><font size="2">Function <b>del_info</b> first prompts the userfor the id code of the <b>info</b> record to be deleted. If the idcode is on file, the <b>info</b> record contents are read intovariable <b>irec</b>, the author name is found from the owner of<b>info</b> through set <b>has_published</b>, and a confirmation ofthe delete is requested by displaying the data (notshown).</font></p><p>If the info item to be deleted is a journal or magazine, anyarticles contained in it must also be deleted. This is done first(not shown).</p><p>Next, any <b>borrower</b> records that are members of that infoitem are disconnected and deleted (also not shown).</p><p>The abstract is deleted by repeatedly disconnecting and deletingthe first member of the <b>abstract</b> set until there are no moremembers. Note that the current owner of <b>abstract</b> had to beinitially set to the <b>info</b> record that is the current memberof <b>has_published</b> (as established by the earlier<b>d_findco</b>(HAS_PUBLISHED) call).</p><p>Deletion of the key words associated with the <b>info</b> recordis similar, but more complicated. Intersect records are deletedjust like the abstract was, except that they need to bedisconnected from set <b>key_to_info</b> as well as from set<b>info_to_key</b>. If the <b>key_to_info</b> set is empty afterdeleting the intersect record, the <b>key_word</b> must also bedeleted. Note the call to <b>d_setro</b> to set the current recordfrom the current owner of set <b>key_to_info</b> (that is, the<b>key_word</b> record). This is necessary because function<b>d_delete</b> deletes the current record, and the <b>key_word</b>record was not the current record.</p><p>The <b>info</b> record is disconnected from its final set,<b>has_published</b>, and can now be deleted. Function<b>d_discon</b> disconnects the current member from the specifiedset and makes the deleted record the current record.</p><p>One last task is a check to see if the author has other<b>info</b> items in the database. If not, then the <b>author</b>record is disconnected from set <b>author_list</b> and is deletedas well.</p><h2><a name="Error" id="Error"></a>5.8 Database ErrorReporting</h2><p><font size="2">All <b><i>db.*</i></b> runtime functions returnan integer database status code as the value of the function. Thesestatus codes are classified into the following threecategories:</font></p><table cellspacing="0" border="0" cellpadding="7" width="529"><tr><td width="27%" valign="top"><p><font size="2"><b>Function Statuses</b></font></p></td><td width="73%" valign="top"><p><font size="2">These indicate normal statuses, such as recordnot found or end of set. Function status codes range from 0 to99.</font></p></td></tr><tr><td width="27%" valign="top"><p><font size="2"><b>User</b> <b>Errors</b></font></p></td><td width="73%" valign="top"><p><font size="2">These correspond to programming errors, such aspassing a record type to a function with a set type as itsargument. User error codes range from -1 to -99.</font></p></td></tr><tr><td width="27%" valign="top"><p><font size="2"><b>System</b> <b>Errors</b></font></p></td><td width="73%" valign="top"><p><font size="2">These errors occur when <b><i>db.*</i></b>detects an abnormal database condition, such as no more file space.System error codes range from -900 to -999.</font></p></td></tr></table><p><font size="2">When user errors are reported, either thearguments to a <b><i>db.*</i></b> function are not correct or thedatabase environment has not been properly set up for the calledfunction. For example, function <b>d_csoread</b> will return usererror S_NOCO if the current owner of the specified set is NULL_DBA.All user errors in a <b><i>db.*</i></b> program should becorrected.</font></p><p>Only one system error is recoverable. The system error S_NOSPACEis returned when there is no more space available on the disk, butit is recoverable. A recovery technique is described with function<b>d_trend</b> in the <i><b>db.*</b> Reference Manual</i>. Allother system errors (and sometimes even error S_NOSPACE) indicatethat a serious error has occurred and processing should beterminated immediately. Usually, these errors result from anapplication programming error that corrupts the <b><i>db.*</i></b>runtime environment. These errors are caused by improper use ofpointers, by memory mismanagement, and by operations on stringsthat are not terminated by a null byte. The most common pointererror is passing a function argument by value rather than byreference (that is, rather than by using a pointer).</p><p>The standard <b><i>db.*</i></b> C header file, <b>db.star.h</b>,contains constant definitions for all status and error codes thatcan be returned from a <b><i>db.*</i></b> function. This fileshould be <b>#include</b>d in each C source file that uses<b><i>db.*</i></b>. Detailed explanations for each status code canbe found in the <b><i>db.*</i> Reference Manual</b>.</p><p>The internal function <b>dberr</b> is automatically called bythe <b><i>db.*</i></b> runtime functions whenever a user or systemerror occurs. Whenever a user or system error occurs, this versionof <b>dberr</b> will display the error code and description, andthen prompt for a <Return> to continue. You may need tocustomize the error reporting to make it more suitable for the userinterface style of your application.</p><p>The recommended method is to use <b>d_set_dberr</b>, whichallows you to supply the <b><i>db.*</i></b> runtime with a callbackfunction to call when reporting an error. After calling<b>d_set_dberr</b>, the <b>dberr</b> function will call thefunction you supply, instead of printing the message itself. Yourerror reporting function should be declared as follows:</p><pre><font color="#0000FF">void EXTERNAL_FIXED my_dberr(int, char *);</font></pre><p><font size="2">The first parameter is the error number, and thesecond parameter is the textual message that <b>dberr</b> wouldhave printed regarding the error. The void EXTERNAL_FIXED precedingthe function name ensures that its declaration will match thatexpected by <b><i>db.*</i></b>. The macros are defined in<b>db.star.h</b>. Use the function as follows:</font></p><pre><font color="#0000FF">#define "db.star.h"void EXTERNAL_FIXED my_dberr(int, char *);...main(){ ... d_set_dberr(my_dberr, task); ...}void EXTERNAL_FIXED my_dberr(int err_no, char *err_msg){ /* Special handling of some error codes here */ if (err_no <= -900) { /* take care in calling d_close, because it may call dberr again */ exit(err_no); } ... /* You may choose to ignore some codes */ if (err_no == S_NOCM) return; ... /* Report errors */ ... return;}</font></pre><h2><a name="Multiple" id="Multiple"></a>5.9 Multiple DatabaseAccess</h2><p><font size="2">Using <b><i>db.*</i></b>, more than one databasecan be open and accessed within a single application program. Thiscapability has been implemented with very little performance impactfor those <b><i>db.*</i></b> applications that only need to accessa single database. Section 4.4.1, "Logical Design Considerations,"described some of the uses of multiple database access from adatabase design standpoint. This section explains how to open andaccess multiple databases.</font></p><h3><a name="Opening" id="Opening"></a>5.9.1 Opening MultipleDatabases</h3><p><font size="2">To open more than one database, the desireddatabase names are passed, separated by a semicolon (;), as thefirst argument to function <b>d_open</b> or <b>d_iopen</b>. Nowhite space (that is, spaces, tabs, etc.) should be embeddedbetween the database names. An improperly constructed list willresult in error S_INVDB being returned. Any number of databases maybe opened, limited only by the amount of available memory. Allopened databases are opened in the same mode. It is not possible toopen some in exclusive access and others in shared or one-useraccess. You can, however, open all databases in shared mode andthen place exclusive locks on all of the files in one or moredatabases.</font></p><p>A currency value is defined called current database. The currentdatabase will be zero (that is, the first one listed) afterexecution of <b>d_open</b>. See the example below:</p><pre><font color="#0000FF">if ((status=d_open("genledg;acctsrec;acctspay", "s", task)) != S_OKAY) { if (status == S_UNAVAIL) printf("database(s) not currently available\n"); exit(1);}</font></pre><p><font size="2">Here, the databases named <b>genledg</b>,<b>acctsrec</b> and <b>acctspay</b> are all opened for sharedaccess. Each is assigned a number by the system in order from leftto right, beginning with zero. Thus database 0 is <b>genledg</b>,database 1 is <b>acctsrec</b>, and database 2 is <b>acctspay</b>.These numbers are used to specify to the runtime functions whichdatabase to access. After the <b>d_open</b> call, database<b>genledg</b> will be the current database.</font></p><p>It is not necessary to open all databases at one time. Thefunction <b>d_iopen</b> will incrementally open a new (set of)database(s) in the same open mode as the already opened databases.The following statements would be equivalent to the example above,except that the current database will be two instead of zero:</p><pre><font color="#0000FF">if ((status = d_open("genledg", "s", task)) != S_OKAY || (status = d_iopen("acctsrec", task)) != S_OKAY || (status = d_iopen("acctspay", task)) != S_OKAY)) { if (status == S_UNAVAIL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -