home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Guide
/
c-cplusplus-interactive-guide.iso
/
c_ref
/
csource1
/
chint
/
useful10.hnt
< prev
next >
Wrap
Text File
|
1993-09-29
|
10KB
|
305 lines
/****************************************************************************
This useful hint shows how to modify the standard, (single user), DBC.SKL
so that a whole branch of records of a database can be copied as a block.
IE. Copy a record, and all it's children, and it's childrens children, etc.
To aid in writing the procedure to accomplish this functionallity it is
first necessary to re-organise the skeleton so that certain functions and
routines can be made available to outside functions.
*****************************************************************************/
1) Copy the Standard skeleton DBC.SKL to COPYBRAN.SKL. Now make the
following modifications to COPYBRAN.SKL...
----------------------------------------------------------------------------
2) Certain procedures that we are going to write will need to have some
lines conditionally compiled depending on whether the database definition
uses "Memo" fields and/or make use of the automatic "Adjust" function.
At the top of the skeleton add the following :--
ⁿIFDEF MEMOSⁿ
#define _USESMEMOS_
ⁿENDDEFⁿ
ⁿIFDEF ADJUSTⁿ
#define _USESADJUST_
ⁿENDDEFⁿ
----------------------------------------------------------------------------
3) The function "found()" and the function "getarec()" both use the same
imbedded DataBoss Macro, "getrec". This Macro should be re-coded as a
procedure in its own right, called "getSingleRec()", and both "getarec()"
and "found()" should now call "getSingleRec()" :--
/* Place this just before the code for the "found" function */
void getSingleRec(int fno)
{
switch (fno) {
ⁿgetrecⁿ
}
}
/* So found() Changes To ... */
bool found(int fno, int kno, keystr chkkey)
...
...
ok = (bool)(ok && (strsearch(aKey, chkkey) == aKey));
if (ok) getSingleRec(fno);
tfound = ok;
...
...
}
/* And getarec() changes to ... */
void getarec(int fno)
...
...
recavail[fno] = ok;
if (ok) getSingleRec(fno);
ⁿIFDEF LINKEDⁿ
...
...
----------------------------------------------------------------------------
4) The "add_record()" function has two imbedded DataBoss macros that we need
access to. "clearmemo" and "setfield" both need to be moved into
procedures of their own.
Create a new function "clearMomoFields()" and add this function directly
after the "clearmemo" function, and INSIDE the "IFDEF MEMOS" DataBoss
conditional generation macro, :--
ⁿIFDEF MEMOSⁿ
void clearmemo(ptr fb)
...
...
}
void clearMemoFields(int fno) /* <-- New */
{ /* <-- New */
switch (fno) { /* <-- New */
ⁿCLEARMEMOⁿ /* <-- New */
} /* <-- New */
} /* <-- New */
ⁿENDDEFⁿ
Also create a new function, called "recDefaultValues()", that is based
upon the ⁿsetfieldⁿ macro. The code for this procedure will need to go
just before "add_record()", and as it may need to call the "autoinc()"
function this will also need to be moved above both the "add_record()" and
the "recDefaultValues()" functions.
The current "addarec()" function will also need to be modified so that
it can be passed a file number to indicate which record to add, (at the
moment it add a record based on the global "filno" variable).
strptr autoinc(keystr sout, int kno)
{
...
...
}
void recDefaultValues(int filno) /* New */
{ /* New */
string tts; /* New */
/* New */
ⁿSETFIELDⁿ /* New */
} /* New */
void addarec(int filno) /* <-- Modified */
{
...
...
}
/* "Add_Record" can now call "ClearMemoFields" and "RecDefaultValues" */
void add_record(char func)
{
...
...
cleartop = (bool)(func == 'A');
clear_rec(filno);
scrn_active = True;
ⁿIFDEF MEMOSⁿ
if (!cleartop) clearMemoFields(filno); /* <-- New */
ⁿENDDEFⁿ
cleartop = True;
recDefaultValues(filno); /* <-- New */
ⁿIFDEF TABLESⁿ
...
...
if (exitcode != QitKey) {
ⁿIFDEF MUSERⁿ
must_secure_rec(filno,0L,2);
addarec(filno); /* <-- Modified */
tv = lock_datf(datf[filno],recno[filno],Lock);
tv = lock_datf(datf[filno],0L,UnLock);
ⁿELSEDEFⁿ
addarec(filno); /* <-- Modified */
ⁿENDDEFⁿ
for (keyno = 1; keyno <= maxkeyno; keyno++) savkey[keyno][0] = '\0';
...
...
}
----------------------------------------------------------------------------
5) Now that these changes are in place we can write the functions that
actually copy a block of records. You could add extra code directly
to the modified skeleton, however I would suggest you put it in a
function file, (call it COPYBRAN.FUN).
/* The contents of COPYBRAN.FUN */
uchar msg_NeedHoldingFile[] = "Cannot open temporary holding file. Copy aborted!";
typedef struct {
int fileNumber;
long recordRef;
} fileAndRecRef;
FILE *hFile;
void duplicateBranch(int fno)
{
fileAndRecRef addThisRec;
bool savOK, tb;
int i;
keystr tkey, tkey2;
if (fno != filno) {
getSingleRec(fno);
#ifdef _USESMEMOS_
clearMemoFields(fno);
#endif
addarec(fno);
addThisRec.fileNumber = fno;
addThisRec.recordRef = recno[fno];
fwrite(&addThisRec,sizeof(fileAndRecRef),1,hFile);
}
for (i = 1; i <= maxfilno; i++) {
if ((linkback[i].t == _Unique) &&
(linkback[i].f == fno) && filinuse[i]) {
getlink(tkey,i); strcpy(tkey2,tkey);
searchkey(idxkey[i][1],&recno[i],tkey2);
savOK = ok && (strsearch(tkey2,tkey) == tkey2);
while (savOK) {
duplicateBranch(i);
nextkey(idxkey[i][1],&recno[i],tkey2);
savOK = ok &&(strsearch(tkey2,tkey) == tkey2);
}
ok = True; /* Restore OK to True */
}
}
}
void setLinksAndAddKeys(void)
{
int i, j, fno;
keystr tkey;
fileAndRecRef changeThisRec;
fseek(hFile,0L,SEEK_SET);
while (!(feof(hFile))) {
if (fread(&changeThisRec,sizeof(fileAndRecRef),1,hFile) == 1) {
fno = changeThisRec.fileNumber;
recno[fno] = changeThisRec.recordRef;
getSingleRec(fno); recavail[fno] = True;
recDefaultValues(fno); /* Calls SetLinkage to set link fields */
putarec(fno);
#ifdef _USESADJUST_
adjust(fno,'A');
#endif
for (i=1;i<=maxkeyno; i++) {
if (keylen[fno][i] > 0) {
getakey(tkey,fno,i);
addkey(idxkey[fno][i],&recno[fno],tkey);
}
}
}
}
}
void copyBranch(int fno, long copyRec)
{
long i;
long parentRec;
hFile = fopen("~COPYREC.HLD","rb");
if (hFile != NULL) {
parentRec = recno[fno];
recno[fno] = copyRec;
getSingleRec(fno);
duplicateBranch(fno);
recno[fno] = parentRec;
getSingleRec(fno);
setLinksAndAddKeys();
fclose(hFile);
unlink("~COPYREC.HLD");
scrn_active = False;
for (i=1; i<=maxfilno; i++) clear_rec(i);
scrn_active = True;
align_rec(recno[fno]);
}
else
dberrm(msg_NeedHoldingFile);
}
----------------------------------------------------------------------------
6) Finally we need to add a little more code to the skeleton so that we can