2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
24 /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
25 /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
26 /*%% (c) Copyright 1993, 1994 Novell, Inc. */
27 /*%% $XConsortium: isread.c /main/3 1995/10/23 11:43:35 rswiston $ */
29 * Copyright (c) 1988 by Sun Microsystems, Inc.
36 * Read a record from ISAM file.
40 #include "isam_impl.h"
46 * err = isread(isfd, record, mode)
48 * Isread() reads a new record from an ISAM file.
50 * Current record position is set.
51 * isrecnum is set to indicate the read record.
53 * If the ISAM file is for variable length records, the isreclen variable
54 * is set to indicate the actual length of the record.
56 * Returns 0 if successful, or -1 of any error.
59 * ELOCKED The record or the entire file is locked by another process.
60 * ENOTOPEN isfd does not correspond to an open ISAM file, or the
61 * ISAM file was opened with ISOUTPUT mode.
62 * EBADARG Bad mode parameter.
63 * ENOCURR Mode is ISCURR and the current record position is not set.
64 * ENOREC Specified record cannot be found (random access read)
65 * EENDFILE The end file of is reached (sequential read).
66 * EBADKEY Index was deleted by other process (can happen only
67 * when lock file is purged).
71 isread(int isfd, char *record, int mode)
77 enum readmode readmode;
80 * Get File Access Block.
82 if ((fab = _isfd_find(isfd)) == NULL) {
83 _setiserrno2(ENOTOPEN, '9', '0');
88 * Check that the open mode was ISINPUT, or ISINOUT.
90 if (fab->openmode != OM_INPUT && fab->openmode != OM_INOUT) {
91 _setiserrno2(ENOTOPEN, '9', '0');
98 if ((readmode = _getreadmode(mode)) == RM_BADMODE) {
99 _setiserrno2(EBADARG, '9', '0');
104 * All keys must be in the minimum record length.
105 * So send just the minimum length part of the record.
107 reclen = fab->minreclen;
110 * Call the Access Method
114 if ((ret = _amread(&fab->isfhandle, record, &reclen,
115 readmode, &fab->curpos, &recnum,
116 &fab->errcode)) == ISOK) {
117 isrecnum = recnum; /* Set isrecnum */
121 _seterr_errcode(&fab->errcode);
123 return (ret); /* Successful read */
127 * _amread(isfhandle, record, reclen, readmode, curpos, recnum, errcode)
129 * _amread() reads a record from ISAM file
132 * isfhandle Handle of ISAM file
133 * readmode Specifies access mode (random or sequential)
134 * curpos current record position
135 * recnum copy if isrecnum
138 * curpos new current position
139 * recnum record number
140 * errcode error status of the operation
141 * reclen actual length of the record
142 * record filled with data
147 _amread(Bytearray *isfhandle, char *record, int *reclen,
148 enum readmode readmode, Bytearray *curpos, Recno *recnum,
149 struct errcode *errcode)
157 char keybuf1[MAXKEYSIZE], keybuf2[MAXKEYSIZE];
158 char *pkey, *pkeynext;
167 * Get FCB corresponding to the isfhandle handle.
169 if ((fcb = _openfcb(isfhandle, errcode)) == NULL) {
174 rec_read = (fcb->varflag?_vlrec_read:_flrec_read);
177 * Update information in FCB from CNTL page on the disk
179 (void)_isfcb_cntlpg_r2(fcb);
182 * Save the old record position.
184 oldcurpos = _bytearr_dup(curpos);
187 * Get info from current record position structure.
189 crp = (Crp *) curpos->data;
191 if (crp->keyid == PHYS_ORDER) {
193 * Physical order in use.
198 recnum2 = *recnum; /* passed from isrecnum */
199 if ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK) {
200 _amseterrcode(errcode, ENOREC);
206 recnum2 = *recnum + 1;
207 if (recnum2 < 1) recnum2 = 1;
209 * Skip deleted records.
211 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
216 _amseterrcode(errcode, ENOREC);
223 if (recnum2 < 1) recnum2 = 1;
225 * Skip deleted records.
227 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
232 _amseterrcode(errcode, ENOREC);
238 recnum2 = *recnum - 1;
239 if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
241 * Skip deleted records.
243 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
248 _amseterrcode(errcode, ENOREC);
255 if (recnum2 > fcb->lastrecno) recnum2 = fcb->lastrecno;
257 * Skip deleted records.
259 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
264 _amseterrcode(errcode, ENOREC);
272 * Skip deleted records.
274 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
279 _amseterrcode(errcode, EENDFILE);
288 recnum2 = crp->recno;
294 _amseterrcode(errcode, ENOCURR);
298 if( rec_read(fcb, record, recnum2, reclen) != ISOK) {
299 _amseterrcode(errcode, ENOCURR);
307 recnum2 = crp->recno + 1;
313 recnum2 = crp->recno;
316 _amseterrcode(errcode, EENDFILE);
319 _amseterrcode(errcode, ENOCURR);
324 * Skip deleted records.
326 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
331 _amseterrcode(errcode, EENDFILE);
339 recnum2 = crp->recno - 1;
342 recnum2 = crp->recno;
345 _amseterrcode(errcode, EENDFILE);
348 _amseterrcode(errcode, ENOCURR);
353 * Skip deleted records.
355 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
360 _amseterrcode(errcode, EENDFILE);
365 recnum2 = fcb->lastrecno;
367 * Skip deleted records.
369 while ((err = rec_read(fcb, record, recnum2, reclen)) != ISOK &&
374 _amseterrcode(errcode, EENDFILE);
379 _isfatal_error("Invalid readmode");
385 * Set new current record position.
387 crp->recno = recnum2;
390 } /* physical order */
393 * Find key descriptor in FCB
395 if ((pkeydesc2 = _isfcb_indfindkey(fcb, crp->keyid)) == NULL) {
396 _amseterrcode(errcode, EBADKEY);
401 * skipkeybytes is set to the number of bytes in the beginning
403 * RECNOSIZE for ISNODUPS keys to skip recno part
404 * RECNOSIZE + DUPIDSIZE to skip recno and duplicate serial number
406 skipbytes = RECNOSIZE;
407 if (ALLOWS_DUPS2(pkeydesc2))
408 skipbytes += DUPIDSIZE;
411 * Create B tree object.
413 btree = _isbtree_create(fcb, pkeydesc2);
419 * Make sure that you will read the first duplicate.
421 _iskey_fillmin(pkeydesc2, keybuf1);
424 * Extract key fields from record.
426 _iskey_extract(pkeydesc2, record, keybuf2);
427 memcpy((void *)(keybuf1 + skipbytes),
428 (const void *)(keybuf2 + skipbytes), crp->matchkeylen);
431 * Position pointer in the B-tree in before the searched value.
433 _isbtree_search(btree, keybuf1);
435 if ((pkey = _isbtree_next(btree)) == NULL) {
436 _amseterrcode(errcode, ENOREC);
440 if (readmode == RM_EQUAL &&
441 memcmp(keybuf1 + skipbytes, pkey + skipbytes,
442 crp->matchkeylen) != 0) {
443 _amseterrcode(errcode, ENOREC);
447 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
448 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
450 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
451 _amseterrcode(errcode, ENOCURR);
454 recnum2 = crp->recno;
459 * Make sure that you will read past all matching records.
461 _iskey_fillmax(pkeydesc2, keybuf1);
464 * Extract key fields from record.
466 _iskey_extract(pkeydesc2, record, keybuf2);
467 memcpy((void *)(keybuf1 + skipbytes),
468 (const void *)(keybuf2 + skipbytes), crp->matchkeylen);
471 * Position pointer in the B-tree in before the searched value.
473 _isbtree_search(btree, keybuf1);
475 if ((pkey = _isbtree_next(btree)) == NULL) {
476 _amseterrcode(errcode, ENOREC);
480 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
481 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
483 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
484 _amseterrcode(errcode, ENOCURR);
487 recnum2 = crp->recno;
492 * Make sure that you will read before all matching records.
494 _iskey_fillmin(pkeydesc2, keybuf1);
497 * Extract key fields from record.
499 _iskey_extract(pkeydesc2, record, keybuf2);
500 memcpy((void *)(keybuf1 + skipbytes),
501 (const void *)(keybuf2 + skipbytes), crp->matchkeylen);
504 * Position pointer in the B-tree in before the searched value.
506 _isbtree_search(btree, keybuf1);
508 if ((pkey = _isbtree_current(btree)) == NULL) {
509 _amseterrcode(errcode, ENOREC);
513 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
514 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
516 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
517 _amseterrcode(errcode, ENOCURR);
520 recnum2 = crp->recno;
525 * Make sure that you will read the last duplicate.
527 _iskey_fillmax(pkeydesc2, keybuf1);
530 * Extract key fields from record.
532 _iskey_extract(pkeydesc2, record, keybuf2);
533 memcpy((void *)(keybuf1 + skipbytes),
534 (const void *)(keybuf2 + skipbytes), crp->matchkeylen);
537 * Position pointer in the B-tree in before the searched value.
539 _isbtree_search(btree, keybuf1);
541 if ((pkey = _isbtree_current(btree)) == NULL) {
542 _amseterrcode(errcode, ENOREC);
546 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
547 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
549 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
550 _amseterrcode(errcode, ENOCURR);
553 recnum2 = crp->recno;
562 * We have check if the record has not been deleted
563 * since the current record position was set up.
565 _isbtree_search(btree, crp->key);
566 pkey = _isbtree_current(btree);
569 ldrecno(pkey + KEY_RECNO_OFF) != crp->recno) {
570 _amseterrcode(errcode, ENOCURR);
575 _isbtree_search(btree, crp->key);
576 pkey = _isbtree_next(btree);
579 _amseterrcode(errcode, EENDFILE);
583 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
584 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
587 _amseterrcode(errcode, ENOCURR);
591 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
592 _amseterrcode(errcode, ENOCURR);
595 recnum2 = crp->recno;
601 * Validate that current position has been set.
609 _amseterrcode(errcode, EENDFILE);
612 _amseterrcode(errcode, ENOCURR);
617 * Position pointer to current position.
619 _isbtree_search(btree, crp->key);
621 if (crp->flag == CRP_BEFORE)
622 pkey = _isbtree_current(btree);
624 /* crp->flag == CRP_ON || crp->flag == CRP_BEFOREANY */
625 pkey = _isbtree_next(btree);
628 _amseterrcode(errcode, EENDFILE);
632 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
633 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
635 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
636 _amseterrcode(errcode, ENOCURR);
639 recnum2 = crp->recno;
645 * Validate that current position has been set.
651 * To get to the previous record, we must decrement
652 * the TID part for unique keys, or duplicate serial number
653 * for non-unique keys.
655 memcpy((void *)keybuf1,
656 (const void *)crp->key, pkeydesc2->k2_len);
657 if (ALLOWS_DUPS2(pkeydesc2)) {
658 stlong(ldlong(keybuf1 + KEY_DUPS_OFF) - 1,
659 keybuf1 + KEY_DUPS_OFF);
662 strecno(ldrecno(keybuf1 + KEY_RECNO_OFF) - 1,
663 keybuf1 + KEY_RECNO_OFF);
667 memcpy((void *)keybuf1, (const void *)crp->key, pkeydesc2->k2_len);
670 _amseterrcode(errcode, EENDFILE);
673 _amseterrcode(errcode, ENOCURR);
678 * Position pointer to current position.
680 _isbtree_search(btree, keybuf1);
682 pkey = _isbtree_current(btree);
685 _amseterrcode(errcode, EENDFILE);
689 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
690 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
692 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
693 _amseterrcode(errcode, ENOCURR);
696 recnum2 = crp->recno;
701 * Fill key buffer with -infinity.
703 _iskey_fillmin(pkeydesc2, keybuf1);
706 * Position pointer in the B-tree before any key entry.
708 _isbtree_search(btree, keybuf1);
710 if ((pkey = _isbtree_next(btree)) == NULL) {
711 _amseterrcode(errcode, EENDFILE);
715 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
716 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
718 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
719 _amseterrcode(errcode, EENDFILE);
722 recnum2 = crp->recno;
727 * Fill key buffer with +infinity.
729 _iskey_fillmax(pkeydesc2, keybuf1);
732 * Position pointer in the B-tree before any key entry.
734 _isbtree_search(btree, keybuf1);
736 if ((pkey = _isbtree_current(btree)) == NULL) {
737 _amseterrcode(errcode, EENDFILE);
741 crp->recno = ldrecno(pkey + KEY_RECNO_OFF);
742 memcpy((void *)crp->key, (const void *)pkey, pkeydesc2->k2_len);
744 if( rec_read(fcb, record, crp->recno, reclen) != ISOK) {
745 _amseterrcode(errcode, EENDFILE);
748 recnum2 = crp->recno;
752 _isfatal_error("Invalid readmode");
759 * Set up isdupl to handle isstat2 value for keys that allow
762 if (ALLOWS_DUPS2(pkeydesc2) && (pkeynext = _isbtree_next(btree)) &&
763 memcmp(pkey + skipbytes, pkeynext + skipbytes,
764 crp->matchkeylen) == 0) {
769 _isbtree_destroy(btree);
772 _amseterrcode(errcode, ISOK);
776 _isdisk_commit(); /* This will only check
777 * that we unfixed all fixed
780 _bytearr_free(&oldcurpos);
791 _bytearr_free(&oldcurpos);
794 * If error is ENOREC, set the current record position undefined.
796 if (errcode->iserrno == ENOREC || errcode->iserrno == EENDFILE) {
797 ((Crp *)curpos->data)->flag = CRP_UNDEF;
801 _isbtree_destroy(btree);