/* SDB - relation file I/O routines */ #include #include "sdbio.h" /* global error code variable */ int dbv_errcode; /* list of currently loaded relation definitions */ static struct relation *relations = NULL; /* rfind - find the specified relation */ static struct relation *rfind(rname) char *rname; { int fd; char filename[RNSIZE+5]; struct relation *rptr; struct relation *db_nerror(); /* look for relation in list currently loaded */ for (rptr = relations; rptr != NULL; rptr = rptr->rl_next) if (db_sncmp(rname,rptr->rl_name,RNSIZE) == 0) return (rptr); /* create a file name */ make_fname(filename,rname); /* lookup the relation file */ #ifdef Lattice if ((fd = open(filename,0x8000)) == -1) /*dns*/ #else #ifdef CPM68K if ((fd = openb(filename,0)) == -1) #else if ((fd = open(filename,0)) == -1) #endif #endif return (db_nerror(RELFNF)); /* allocate a new relation structure */ if ((rptr = malloc(sizeof(struct relation))) == NULL) { close(fd); return (db_nerror(INSMEM)); } /* initialize the relation structure */ rptr->rl_scnref = 0; /* read the header block */ if ( read(fd,&rptr->rl_header,512) != 512) { free(rptr); close(fd); return (db_nerror(BADHDR)); } /* close the relation file */ close(fd); /* extract header information */ rptr->rl_tcnt = db_cvword(rptr->rl_header.hd_tcnt); rptr->rl_tmax = db_cvword(rptr->rl_header.hd_tmax); rptr->rl_data = db_cvword(rptr->rl_header.hd_data); rptr->rl_size = db_cvword(rptr->rl_header.hd_size); /* store the relation name */ strncpy(rptr->rl_name,rname,RNSIZE); /* link new relation into relation list */ rptr->rl_next = relations; relations = rptr; /* return the new relation structure pointer */ return (rptr); } /* db_ropen - open a relation file */ struct scan *db_ropen(rname) char *rname; { struct relation *rptr; struct scan *sptr; char filename[RNSIZE+5]; struct scan *db_nerror(); /* find the relation definition */ if ((rptr = rfind(rname)) == NULL) return (NULL); /* allocate a new scan structure */ if ((sptr = malloc(sizeof(struct scan))) == NULL) return (db_nerror(INSMEM)); /* allocate a tuple buffer */ if ((sptr->sc_tuple = malloc(rptr->rl_size)) == NULL) { free(sptr); return (db_nerror(INSMEM)); } /* initialize the scan structure */ sptr->sc_relation = rptr; /* store the relation struct addrs */ sptr->sc_dtnum = 0; /* desired tuple (non-existant) */ sptr->sc_atnum = 0; /* actual tuple (non-existant) */ sptr->sc_store = FALSE; /* no store done since open */ /* open relation file if necessary */ if (rptr->rl_scnref++ == 0) { /* create the relation file name */ make_fname(filename,rname); /* open the relation file */ #ifdef Lattice if ((rptr->rl_fd = open(filename,0x8002)) == -1) { /*dns*/ #else #ifdef CPM68K if ((rptr->rl_fd = openb(filename,2)) == -1) { #else if ((rptr->rl_fd = open(filename,2)) == -1) { #endif #endif rptr->rl_scnref--; free(sptr->sc_tuple); free(sptr); return (db_nerror(RELFNF)); } } /* return the new scan structure pointer */ return (sptr); } /* db_rclose - close the relation file */ int db_rclose(sptr) struct scan *sptr; { struct relation *rptr,*lastrptr; /* close relation file if this is the last reference */ if (--sptr->sc_relation->rl_scnref == 0) { /* rewrite header if any stores took place */ if (sptr->sc_store) { /* store the tuple count back in the header */ db_cvbytes(sptr->sc_relation->rl_tcnt, sptr->sc_relation->rl_header.hd_tcnt); /* write the header block */ lseek(sptr->sc_relation->rl_fd,0L,0); if (write(sptr->sc_relation->rl_fd, &sptr->sc_relation->rl_header,512) != 512) { close(sptr->sc_relation->rl_fd); free(sptr->sc_tuple); free(sptr); return (db_ferror(BADHDR)); } } /* close the relation file */ close(sptr->sc_relation->rl_fd); /* free the relation header */ lastrptr = NULL; for (rptr = relations; rptr != NULL; rptr = rptr->rl_next) { if (rptr == sptr->sc_relation) { if (lastrptr == NULL) relations = rptr->rl_next; else lastrptr->rl_next = rptr->rl_next; } lastrptr = rptr; } free(sptr->sc_relation); } /* free the scan structure */ free(sptr->sc_tuple); free(sptr); /* return successfully */ return (TRUE); } /* db_rcompress - compress a relation file */ int db_rcompress(sptr) struct scan *sptr; { unsigned int next,nextfree,tcnt; /* get the last used tuple */ tcnt = sptr->sc_relation->rl_tcnt; /* loop through all of the tuples */ for (next = nextfree = 1; next <= tcnt; next++) { /* read the tuple */ seek(sptr,next); if (read(sptr->sc_relation->rl_fd, sptr->sc_tuple,sptr->sc_relation->rl_size) != sptr->sc_relation->rl_size) return (db_ferror(TUPINP)); /* rewrite the tuple if it is active */ if (sptr->sc_tuple[0] == ACTIVE) { /* rewrite it only if it must move */ if (next != nextfree) { /* write the tuple */ seek(sptr,nextfree); if (write(sptr->sc_relation->rl_fd, sptr->sc_tuple,sptr->sc_relation->rl_size) != sptr->sc_relation->rl_size) return (db_ferror(TUPOUT)); } /* update the next free tuple number */ nextfree += 1; } } /* update the tuple count */ sptr->sc_relation->rl_tcnt = nextfree - 1; /* remember which tuple is in the buffer */ sptr->sc_atnum = sptr->sc_relation->rl_tcnt; /* reset the desired tuple */ sptr->sc_dtnum = 0; /* remember that the index needs rewriting */ sptr->sc_store = TRUE; /* return successfully */ return (TRUE); } /* db_rbegin - begin scan at first tuple in relation */ db_rbegin(sptr) struct scan *sptr; { /* begin with the first tuple in the file */ sptr->sc_dtnum = 0; } /* db_rfetch - fetch the next tuple from the relation file */ int db_rfetch(sptr) struct scan *sptr; { /* look for an active tuple */ while (TRUE) { /* check for this being the last tuple */ if (!db_rget(sptr,sptr->sc_dtnum + 1)) return (FALSE); /* increment the tuple number */ sptr->sc_dtnum += 1; /* return if the tuple found is active */ if (sptr->sc_tuple[0] == ACTIVE) return (TRUE); } } /* db_rupdate - update the current tuple */ int db_rupdate(sptr) struct scan *sptr; { /* make sure the status byte indicates an active tuple */ sptr->sc_tuple[0] = ACTIVE; /* write the tuple */ return (db_rput(sptr,sptr->sc_atnum)); } /* db_rdelete - delete the current tuple */ int db_rdelete(sptr) struct scan *sptr; { /* make sure the status byte indicates a deleted tuple */ sptr->sc_tuple[0] = DELETED; /* write the tuple */ return (db_rput(sptr,sptr->sc_atnum)); } /* db_rstore - store a new tuple */ int db_rstore(sptr) struct scan *sptr; { /* make sure there's room for this tuple */ if (sptr->sc_relation->rl_tcnt == sptr->sc_relation->rl_tmax) return (db_ferror(RELFUL)); /* make sure the status byte indicates an active tuple */ sptr->sc_tuple[0] = ACTIVE; /* write the tuple */ if (!db_rput(sptr,sptr->sc_relation->rl_tcnt + 1)) return (FALSE); /* update the tuple count */ sptr->sc_relation->rl_tcnt += 1; /* remember that a tuple was stored */ sptr->sc_store = TRUE; /* return successfully */ return (TRUE); } /* db_rget - get a tuple from the relation file */ int db_rget(sptr,tnum) struct scan *sptr; unsigned int tnum; { /* check to see if the tuple is already in the buffer */ if (tnum == sptr->sc_atnum) return (TRUE); /* check for this being beyond the last tuple */ if (tnum > sptr->sc_relation->rl_tcnt) return (db_ferror(TUPINP)); /* read the tuple */ seek(sptr,tnum); if (read(sptr->sc_relation->rl_fd, sptr->sc_tuple,sptr->sc_relation->rl_size) != sptr->sc_relation->rl_size) return (db_ferror(TUPINP)); /* remember which tuple is in the buffer */ sptr->sc_atnum = tnum; /* return successfully */ return (TRUE); } /* db_rput - put a tuple to a relation file */ int db_rput(sptr,tnum) struct scan *sptr; unsigned int tnum; { /* check for this being beyond the maximum tuple */ if (tnum > sptr->sc_relation->rl_tmax) return (db_ferror(TUPOUT)); /* write the tuple */ seek(sptr,tnum); if (write(sptr->sc_relation->rl_fd, sptr->sc_tuple,sptr->sc_relation->rl_size) != sptr->sc_relation->rl_size) return (db_ferror(TUPOUT)); /* remember which tuple is in the buffer */ sptr->sc_atnum = tnum; /* return successfully */ return (TRUE); } /* seek - seek a tuple in a relation file */ static seek(sptr,tnum) struct scan *sptr; unsigned int tnum; { long offset; offset = (long) sptr->sc_relation->rl_data + ((long) (tnum - 1) * (long) sptr->sc_relation->rl_size); lseek(sptr->sc_relation->rl_fd,offset,0); } /* make_fname - make a relation name into a file name */ static make_fname(fname,rname) char *fname,*rname; { strncpy(fname,rname,RNSIZE); fname[RNSIZE] = 0; strcat(fname,".sdb"); } /* db_nerror - store the error code and return NULL */ int *db_nerror(errcode) int errcode; { dbv_errcode = errcode; return (NULL); } /* db_ferror - store the error code and return FALSE */ int db_ferror(errcode) int errcode; { dbv_errcode = errcode; return (FALSE); } #ifdef CPM68K /* db_cvword - convert 2 bytes to a word */ int db_cvword(bytes) char bytes[2]; { return (((bytes[0] & 0377) << 8) + (bytes[1] & 0377)); } /* db_cvbytes - convert a word to 2 bytes */ db_cvbytes(word,bytes) int word; char bytes[2]; { bytes[1] = (word & 0x00FF); bytes[0] = word >> 8; } #else /* db_cvword - convert 2 bytes to a word */ int db_cvword(bytes) char bytes[2]; { return (((bytes[1] & 0377) << 8) + (bytes[0] & 0377)); } /* db_cvbytes - convert a word to 2 bytes */ db_cvbytes(word,bytes) int word; char bytes[2]; { bytes[0] = word; bytes[1] = word >> 8; } #endif