libDtSearch: remove optional code MULTI_TASK that is not used on CDE
[oweals/cde.git] / cde / lib / DtSearch / raima / dblfcns.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /*
24  *   COMPONENT_NAME: austext
25  *
26  *   FUNCTIONS: FL_LIST_ACCESS
27  *              FL_LIST_DEACCESS
28  *              Pi
29  *              alloc_table
30  *              bld_lock_tables
31  *              d_close
32  *              d_freeall
33  *              d_keyfree
34  *              d_keylock
35  *              d_keylstat
36  *              d_lock
37  *              d_open
38  *              d_recfree
39  *              d_reclock
40  *              d_reclstat
41  *              d_retries
42  *              d_rlbclr
43  *              d_rlbset
44  *              d_rlbtst
45  *              d_setfree
46  *              d_setlock
47  *              d_setlstat
48  *              d_timeout
49  *              d_trabort
50  *              d_trbegin
51  *              d_trend
52  *              free_files
53  *              initdbt
54  *              initses
55  *              keep_locks
56  *              lock_files
57  *              neterr
58  *              pr_lock_descr
59  *              process_lock
60  *              recovery_check
61  *              reset_locks
62  *              send_free
63  *              send_lock
64  *              taskinit
65  *              termfree
66  *              termses
67  *
68  *   ORIGINS: 27,157
69  *
70  *   This module contains IBM CONFIDENTIAL code. -- (IBM
71  *   Confidential Restricted when combined with the aggregated
72  *   modules for this product)
73  *
74  *   OBJECT CODE ONLY SOURCE MATERIALS
75  *   (C) COPYRIGHT International Business Machines Corp. 1995, 1996
76  *   All Rights Reserved
77  *   US Government Users Restricted Rights - Use, duplication or
78  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
79  */
80 /*-----------------------------------------------------------------------=
81  $XConsortium: dblfcns.c /main/6 1996/11/25 18:48:05 drk $
82    dblfcns -- Database Access & Locking Functions
83
84    This file contains functions which open/close a
85    db_VISTA database and manage multiuser access
86    to the db_VISTA database files
87
88    (C) Copyright 1985, 1986, 1987 by Raima Corp.
89 -----------------------------------------------------------------------*/
90
91 /* ********************** EDIT HISTORY *******************************
92
93  SCR    DATE    INI                   DESCRIPTION
94 ----- --------- --- -----------------------------------------------------
95    76 16-Jun-88 RSC Make dblfcns consistent when SINGLE_USER defined
96   240 17-Jun-88 RSC Make dblfcns consistent when NO_TRANS defined
97   103 24-Jun-88 RSC Improve generation of single user version
98   237 29-Jun-88 RSC Do not permit recfree/setfree/keyfree inside transaction
99   272 29-Jun-88 RSC make sure log entry is added to taf after lockmgr, and
100                     deleted before lockmgr
101   305 01-Jul-88 RSC clear cache_ovfl flag after d_trend and d_trabort
102   ??? 06-Jul_88 WLW include GENERAL lockmgr changes
103   353 14-Jul-88 RSC place dio_clear outside ifndef SINGLE_USER in d_trabort
104   367 14-Jul-88 RSC initialize prev lock to 'f' in bld_lock_tables
105   115 18-Jul-88 RSC Integrate VAX/VMS changes into master source
106    76 27-Jul-88 RSC More work making dblfcns work with SINGLE_USER
107       03-AUG-88 RTK MULTI_TASKing changes
108   310 10-Aug-88 RSC Cleanup of function prototypes
109       11-Aug-88 RTK Incremental database open/multi-tasking changes
110       18-Aug-88 RSC Moved rn_type/dba to separate table
111   423 10-Sep-88 RSC Allocated wrong size for rec_locks
112   423 12-Sep-88 RSC Moved o_free above termfree
113   423 15-Sep-88 RSC Initialized no_of_dbs to 1 in d_close
114   424 21-Sep-88 RSC Integrated International Character Set (ESM)
115       04-Oct-88 WLW Removed taskinit call from d_close, replaced with init's
116   425 05-Oct-88 RSC d_trabort was not completely clearing page zero
117       05-Oct-88 RSC must also init no_of_dbs = 1 in d_close (cf 04-Oct above)
118   420 07-Oct-88 RSC Unoptimized usage of fl_list - was full of bugs.
119       11-Oct-88 RSC Fix for clean compile under Lattice 3.3
120   441 08-Dec-88 RSC Place call to netbios_chk within ifndef GENERAL
121                     Placed setting of inode/device within ifndef GENERAL
122                     Removed undef UNIX / define MSC inside GENERAL
123   440 13-Dec-88 RSC Removed LR_LOCK lock_reply from db_global to scalar
124   440 22-Dec-88 RSC More modifications for General Lockmgr
125   539 18-Jan-89 RSC General Lockmgr was broke when open mode = one user
126   420 24-Jan-89 WLW Added ifdef's for SINGLE_USER in lock sets
127   571 27-Jan-89 RSC Remove defn of taf_close - General lockmgr lattice port issue
128   420 14-Feb-89 WLW Corrected KEYMARK handling in d_lock and lock_files
129   637 08-Mar-89 RSC Should not alloc file_refs in exclusive access, wasn't
130                     Freeing fl_list of key_locks
131   713 08-May-89 WLW Make external recovery work for single-user and one-user
132   656 08-May-89 WLW Eliminate assignment to unallocated memory with gen lm.
133
134  $Log$
135  * Revision 1.2  1995/10/13  18:44:53  miker
136  * Change hardcoded dbfile[] size from 48 to DtSrFILENMLEN.
137  * Remove call to initenv()--disregard environment variables.
138  */
139
140 /* To work with the General Lock Manager, the Unix case of using inode
141    number and device to identify a file is not used.
142 */
143 #ifdef GENERAL
144 #define IS_UNIX_REALLY
145 #endif
146
147 #define DEBUG_DBLF
148 int     debugging_dopen = 0;    /* 1 = TRUE */
149
150 #include <stdio.h>
151 #include "vista.h"
152 #include "dbtype.h"
153
154 #ifdef IS_UNIX_REALLY
155 #undef DIRCHAR
156 #define DIRCHAR '/'
157 #endif
158
159 #define KEYMARK 30000
160
161 #define send_pkt (Send_pkt.ptr)
162 #define recv_pkt (Recv_pkt.ptr)
163
164 TASK db_global = { 0 };
165 int db_glob_init = 0;
166
167 /* As a quick fix to the General Lockmgr, the structure lock_reply was
168    removed from db_global.  However, this assumes that db_VISTA would
169    never be preempted in the multi-tasking version, and that all function
170    calls would complete before a new task is run.  If this assumption is
171    ever "broken" then lock_reply will need to be placed back within db_global
172    again */
173 #ifndef SINGLE_USER
174 static LR_LOCK lock_reply;              /* This used to be in db_global */
175 #endif
176
177 extern CHAR_P Dbpgbuff;  /* allocated by dio_init used by o_update */
178 extern LOOKUP_ENTRY_P Db_lookup; /* database page lookup table */
179 extern PAGE_ENTRY_P Dbpg_table; /* database page table */
180 extern LOOKUP_ENTRY_P Ix_lookup; /* index page lookup table */
181 extern PAGE_ENTRY_P Ixpg_table; /* index page table */
182 extern INT_P Used_files;
183
184
185
186 #define lsn (db_global.Lsn)
187
188 BOOLEAN trcommit = FALSE;
189 int db_txtest = 0;          /* transaction commit failure testing flag */
190
191 #define FL_LIST_ACCESS(ld_ptr)   (FILE_NO *)(ld_ptr)->fl_list.ptr
192 #define FL_LIST_DEACCESS(ld_ptr) /**/
193
194 #ifndef NO_TRANS
195 #ifndef SINGLE_USER
196 int rlb_status;
197 static char type[5];        /* open type (s or x) */
198 #endif
199 #endif
200
201 #ifndef NO_TRANS
202 #ifndef GENERAL
203 /* transaction activity file info */
204 extern INT  taf_count;
205 extern char taf_files[TAFLIMIT][FILENMLEN];
206 #endif
207 #endif
208
209 /* Internal function prototypes */
210 #ifndef SINGLE_USER
211 static void pr_lock_descr(P1(struct lock_descr *) Pi(int) 
212                                             Pi(const char *));
213 static int process_lock(P1(struct lock_descr *) Pi(char));
214 static int keep_locks(P1(struct lock_descr *));
215 static int free_files(P1(struct lock_descr *));
216 #endif
217 static int bld_lock_tables(P0);
218 static int initses(P0);
219 static int lock_files(P1(int) Pi(LOCK_REQUEST *));
220 static int send_lock(P0);
221 static int send_free(P0);
222 static void reset_locks(P0);
223 static int recovery_check(P0);
224
225
226
227
228 #ifndef NO_TRANS
229 /* Set the number of lock request retries
230 */
231 d_retries(num TASK_PARM)
232 int num;
233 TASK_DECL
234 {
235    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_NONE));
236
237 #ifndef SINGLE_USER
238    lock_tries = num;
239 #endif
240    RETURN( db_status = S_OKAY );
241 }
242 #endif
243
244
245 #ifndef NO_TRANS
246 /* Set the lock request timeout value
247 */
248 d_timeout(secs TASK_PARM)
249 int secs;
250 TASK_DECL
251 {
252 #ifdef SINGLE_USER
253    return(db_status = S_OKAY);
254 #else
255    LM_SETTIME sto;  /* send timeout packet */
256
257    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_ALL));
258    if ( !dbopen ) RETURN( dberr(S_DBOPEN) );
259
260    if ( dbopen == 1 ) {
261       sto.fcn  = L_SETTIME;
262       sto.secs = secs;
263       if ( nw_send(lsn, (MESSAGE *)&sto, sizeof(LM_SETTIME)) )
264          RETURN( neterr() );
265       db_timeout = secs;
266    }
267    RETURN( db_status = S_OKAY );
268 #endif
269 }
270 #endif
271
272
273 /* Open db_VISTA database
274 */
275 int
276 d_open(dbnames, opentype TASK_PARM)
277 const char *dbnames;
278 const char *opentype;
279 TASK_DECL
280 {
281    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_ALL));
282 #ifdef DEBUG_DBLF
283    if (debugging_dopen) {
284         puts (__FILE__"265 d_open");
285         fflush(stdout);
286    }
287 #endif
288
289    if ( dbopen ) d_close(TASK_ONLY);
290
291 #ifndef SINGLE_USER
292    if ( opentype ) {
293       switch ( *opentype ) {
294          case 's':
295          case 'x':
296 #ifndef GENERAL
297             if ( netbios_chk() == 0 )
298                 RETURN( dberr( S_NONETBIOS ) );
299 #endif
300             db_lockmgr = 1;
301             strcpy(type, opentype);
302             break;
303          case 'n':
304          case 't':
305          case 'o':
306             db_lockmgr = 0;
307             strcpy(type, "x");
308             break;
309          default:
310             RETURN( dberr(S_BADTYPE) );
311       }
312    }
313    else
314       strcpy(type, "x");
315 #endif
316
317
318 #ifdef MIKER /**@@@***/
319 #ifndef NO_COUNTRY
320    /* initialize the country table if "vista.ctb" exists */
321    if ( ctb_init() != S_OKAY )
322       RETURN( db_status );
323 #endif
324 #endif
325
326 #ifndef NO_TRANS
327 #ifndef GENERAL
328    /* open transaction activity file */
329    if ( taf_open() != S_OKAY ) 
330       RETURN( db_status );
331 #endif
332 #endif
333
334    /* initialize multi-db tables */
335    if ( initdbt(dbnames) != S_OKAY ) RETURN( db_status );
336
337    /* read in schema tables */
338    if ( inittab() != S_OKAY ) RETURN( db_status );
339
340 #ifdef DEBUG_DBLF
341    if (debugging_dopen) {
342         puts(__FILE__"324 d_open calling renfiles");
343         fflush(stdout);
344    }
345 #endif
346    if ( renfiles() != S_OKAY ) RETURN( db_status );
347
348 #ifndef SINGLE_USER
349
350    if ( db_lockmgr ) {  /* [637] Only alloc file_refs for shared open */
351       /* Macro references must be on one line for some compilers */ 
352       if (ALLOC_TABLE(&db_global.File_refs, size_ft*sizeof(FILE_NO),old_size_ft*sizeof(FILE_NO), "file_refs")
353                 !=  S_OKAY) {
354          RETURN( db_status );
355       }
356    }
357
358    if ( *type == 's' ) {
359       /* build application file lock tables */
360       if ( bld_lock_tables() != S_OKAY )
361          RETURN( db_status );
362       dbopen = 1;
363    }
364    else
365 #endif
366       dbopen = 2;
367 #ifndef SINGLE_USER
368 #ifndef GENERAL
369    if ( db_lockmgr ) {
370 #endif
371       if ( initses() != S_OKAY ) {
372          dbopen = 0;
373          RETURN( db_status );
374       }
375 #ifndef GENERAL
376    }    /* [713] perform external recovery in one-user mode */
377    else
378       if ( recovery_check() != S_OKAY ) RETURN(db_status);
379 #endif
380 #else
381 #ifndef NO_TRANS
382    /* [713] perform external recovery in single-user mode */
383    if ( recovery_check() != S_OKAY ) RETURN(db_status);
384 #endif
385 #endif
386 #ifndef NO_TRANS
387    if ( use_ovfl ) {
388       if ( o_setup() != S_OKAY ) RETURN( db_status );
389    }
390 #endif
391
392 #ifdef DEBUG_DBLF
393    if (debugging_dopen) {
394             printf(__FILE__"392 d_open before key_open. pgsz=%hd lrgst=%hd\n",
395                 page_size,largest_page);
396             fflush(stdout);
397    }
398 #endif
399    if ( key_open() == S_OKAY ) {
400       if ( dio_init() == S_OKAY ) {
401          RETURN( db_status );
402       }
403    }
404    dbopen = 0;
405 #ifdef DEBUG_DBLF
406    if (debugging_dopen) {
407             printf(__FILE__"404 d_open after dio_init. pgsz=%hd lrgst=%hd\n",
408                 page_size,largest_page);
409             fflush(stdout);
410    }
411 #endif
412    RETURN( db_status );
413 } /* d_open() */
414
415
416 /* Initialize a task structure
417 */
418 int taskinit(tsk)
419 TASK *tsk;
420 {
421    byteset(tsk, '\0', sizeof(TASK));
422 #ifndef ONE_DB
423    tsk->No_of_dbs = 1;
424 #endif
425 #ifndef SINGLE_USER
426    tsk->Lock_tries = 5;
427    tsk->Dbwait_time = 1;
428    tsk->Db_timeout = TIMEOUT_DEF;
429    tsk->Db_lockmgr = 1;
430 #endif
431 #ifndef NO_TRANS
432    tsk->Dboptions = DCHAINUSE | TRLOGGING;
433 #else
434    tsk->Dboptions = DCHAINUSE;
435 #endif
436    return( db_status );
437 }
438
439
440 /* Initialize multiple database table entries
441 */
442 int
443 initdbt(dbnames )
444 const char *dbnames;
445 {
446    int dbt_lc;                  /* loop control */
447    char dbfile [DtSrFILENMLEN];
448    char *ptr;
449 #ifndef  ONE_DB
450    const char *cp;
451    int i;
452 #endif
453
454 #ifndef  ONE_DB
455    /* compute number of databases to be opened */
456    old_no_of_dbs = (( no_of_dbs == 1 ) ? 0 : no_of_dbs);
457    for ( cp = dbnames; *cp; ++cp )
458       if ( *cp == ';' ) ++no_of_dbs;
459 #ifdef DEBUG_DBLF
460    if (debugging_dopen) {
461         printf(__FILE__"457 initdbt: new#dbs=%d\n", (int)no_of_dbs);
462         fflush(stdout);
463    }
464 #endif
465
466    /* Now make sure there are the right # of elements in dbd/dbfpath */
467    if (dbdpath[0]) {
468       if (get_element(dbdpath,no_of_dbs-1) == NULL)     /* Not enuf? */
469          return( dberr(S_BADBDPATH) );
470       if (strrchr(dbdpath,';') != NULL)         /* Is dbdpath single element */
471          if (get_element(dbdpath,no_of_dbs) != NULL)    /* Too many? */
472             return( dberr(S_BADBDPATH) );
473    }
474    if (dbfpath[0]) {
475       if (get_element(dbfpath,no_of_dbs-1) == NULL)     /* Not enuf? */
476          return( dberr(S_BADBFPATH) );
477       if (strrchr(dbfpath,';') != NULL) {       /* Is dbfpath single element */
478          if (get_element(dbfpath,no_of_dbs) != NULL)    /* Too many? */
479             return( dberr(S_BADBFPATH) );
480       }
481    }
482
483    /* allocate db_table space */
484    /* Macro references must be on one line for some compilers */ 
485    if ((ALLOC_TABLE(&db_global.Db_table, no_of_dbs*sizeof(DB_ENTRY), 
486                     old_no_of_dbs*sizeof(DB_ENTRY), "db_table") != S_OKAY) ||
487        (ALLOC_TABLE(&db_global.Rn_table, no_of_dbs*sizeof(RN_ENTRY), 
488                     old_no_of_dbs*sizeof(RN_ENTRY), "rn_table") != S_OKAY)) {
489       return( db_status );
490    }
491
492    /* initialize db_table entries */
493    for (dbt_lc = no_of_dbs, cp = dbnames, 
494            curr_db_table = &db_table[old_no_of_dbs]; 
495         --dbt_lc >= 0; 
496         ++cp, ++curr_db_table) {
497       /* extract database name */
498       for ( i = 0; *cp && *cp != ';'; ++cp, ++i )
499          dbfile[i] = *cp;
500       dbfile[i] = '\0';
501 #else
502       strcpy(dbfile, dbnames);
503 #endif
504       if ( (ptr = strrchr(dbfile, DIRCHAR)) == NULL ) 
505          ptr = strrchr(dbfile, ':');
506       if ( ptr ) {
507          if ( strlen(ptr+1) >= DBNMLEN ) RETURN( dberr(S_NAMELEN) );
508          strcpy(DB_REF(db_name), ptr+1);
509          *(ptr+1) = '\0';
510          if ( strlen(dbfile) >= PATHLEN ) RETURN( dberr(S_NAMELEN) );
511          strcpy(DB_REF(db_path), dbfile);
512       }
513       else {
514          strcpy(DB_REF(db_path), "");
515          strcpy(DB_REF(db_name), dbfile);
516       }
517 #ifndef  ONE_DB
518    }
519 #endif
520    return( db_status = S_OKAY );
521 } /* initdbt() */
522
523
524
525 #ifndef NO_TRANS
526 /* Check for possible recovery
527 */
528 static recovery_check()
529 {
530 #ifndef SINGLE_USER
531    LM_TREND trend_pkt;
532 #ifndef GENERAL
533    int tn;     /* transaction number */
534    int tc;     /* transaction count */
535 #endif
536 #endif
537
538 #ifndef GENERAL
539    /* open tr activity file */
540    if ( taf_access() == S_OKAY ) {
541       taf_release();
542 #endif
543 #ifdef SINGLE_USER
544       if (taf_count != 0) {
545          if (d_recover(taf_files[0] CURRTASK_PARM) != S_OKAY)
546             return( db_status );
547          taf_count = 0;
548       }
549 #else
550 #ifndef GENERAL
551       if ( tc = taf_count ) {
552          /* perform recovery on each file */
553          for ( tn = 0; tn < tc; ++tn ) {
554             if ( d_recover(taf_files[0] CURRTASK_PARM) != S_OKAY ) return( db_status );
555          }
556          taf_count = 0;
557       }
558 #endif
559 #endif
560 #ifndef GENERAL
561    }
562 #endif
563 #ifndef SINGLE_USER
564    if ( db_lockmgr ) {
565       /* tell lock manager that we're done */
566       trend_pkt.fcn = L_RECDONE;
567       if ( nw_send(lsn, (MESSAGE *)&trend_pkt, sizeof(LM_TREND)) )
568          neterr();
569    }
570 #endif
571
572    return( db_status );
573 }
574 #endif
575
576
577
578 #ifndef SINGLE_USER
579 /* Initial lock manager session
580 */
581 static int initses()
582 {
583    LM_DBOPEN_P Send_pkt;
584    LR_DBOPEN_P Recv_pkt;
585    int ft_lc;                   /* loop control */
586    LM_TREND trend_pkt;
587    int send_size, recv_size, recvd_sz;
588    struct stat stbuf;
589    LM_FILEID *fi_ptr;
590    FILE_ENTRY *file_ptr;
591    FILE_NO *fref_ptr;
592    INT *rcv_fref_ptr;
593
594    if ( (net_status=nw_addnm(dbuserid, (int *)NULL) ) != N_OKAY )
595       if ( net_status == N_DUPNAME ) {
596          /* It is okay to reuse this name, but first be sure that all
597             sessions are hung up.
598          */
599          nw_cleanup(dbuserid);
600       }
601       else
602          return( neterr() );
603
604    if ( nw_call("lockmgr", dbuserid, &lsn) ) {
605       return( neterr() );
606    }
607    db_timeout = TIMEOUT_DEF;  /* reset default timeout value */
608
609 #ifdef GENERAL
610
611    /* This section of code MUST be identical to else (DOS) below */
612    send_size = 0;
613    for (ft_lc = size_ft - old_size_ft, file_ptr = &file_table[old_size_ft];
614         --ft_lc >= 0; ++file_ptr) 
615       send_size += strlen(file_ptr->ft_name) + 1;
616    send_size += sizeof(LM_DBOPEN);
617    send_size += send_size % 2;
618 #else                           /* GENERAL */
619    send_size = sizeof(LM_DBOPEN) + (size_ft-1)*sizeof(LM_FILEID);
620 #endif                          /* GENERAL */
621    send_pkt = (LM_DBOPEN *)ALLOC(&Send_pkt, send_size, "send_pkt");
622    recv_size = sizeof(LR_DBOPEN) + (size_ft-1)*sizeof(INT);
623    recv_pkt = (LR_DBOPEN *)ALLOC(&Recv_pkt, recv_size, "recv_pkt");
624    if (send_pkt == NULL || recv_pkt == NULL) {
625       nw_hangup(lsn);
626       return(dberr(S_NOMEMORY));
627    }
628
629    send_pkt->fcn = L_DBOPEN;
630    send_pkt->nfiles = size_ft;
631    send_pkt->type = type[0];
632    for (ft_lc = size_ft - old_size_ft, file_ptr = &file_table[old_size_ft],
633                                                 fi_ptr = send_pkt->fnames;
634 #ifdef GENERAL
635         --ft_lc >= 0;  fi_ptr += strlen(file_ptr->ft_name)+1,++file_ptr) {
636 #else
637         --ft_lc >= 0;  ++fi_ptr,++file_ptr) {
638 #endif
639       if (stat(file_ptr->ft_name, &stbuf) == -1) {
640          nw_hangup(lsn);
641          return(dberr(S_NOFILE));
642       }
643 #ifndef GENERAL
644       fi_ptr->inode = stbuf.st_ino;
645       fi_ptr->device = stbuf.st_dev;
646 #else
647       strcpy(fi_ptr,file_ptr->ft_name);
648 #endif
649    }
650 send_open:
651    if (nw_send(lsn, (MESSAGE *)send_pkt, send_size) ||
652        nw_rcvmsg(lsn, (MESSAGE *)recv_pkt, recv_size, &recvd_sz)) {
653       nw_hangup(lsn);
654       return(neterr());
655    }
656
657    if ( recv_pkt->status == L_RECOVER )  {
658       /* perform auto-recovery */
659       d_recover( (const char *)recv_pkt->logfile CURRTASK_PARM );
660
661       /* tell lock mgr we're done */
662       trend_pkt.fcn = L_RECDONE;
663       if ( nw_send(lsn, (MESSAGE *)&trend_pkt, sizeof(LM_TREND)) ) {
664          nw_hangup(lsn);
665          return(neterr());
666       }
667       /* re-issue open request */
668       goto send_open;
669    }
670    if ( recv_pkt->fcn != L_DBOPEN ) {
671       nw_hangup(lsn);
672       return(dberr(S_NETSYNC));
673    }
674    if ( recv_pkt->status != L_OKAY ) {
675       nw_hangup(lsn);
676       nw_sestat();
677 #ifndef GENERAL
678       taf_close();
679 #endif
680       termfree();
681       MEM_UNLOCK(&Send_pkt);
682       FREE(&Send_pkt);
683       MEM_UNLOCK(&Recv_pkt);
684       FREE(&Recv_pkt);
685       dbopen = 0;
686       return(db_status = S_UNAVAIL);
687    }
688    if ( recv_pkt->nusers == 1 ) 
689       if ( recovery_check() != S_OKAY ) {
690          nw_hangup(lsn);
691          return(db_status);
692       }
693
694    /* [656] perform initialization if not general lockmgr */
695    if ( db_lockmgr ) {
696       for (ft_lc = size_ft - old_size_ft, fref_ptr = &file_refs[old_size_ft],
697                                               rcv_fref_ptr = recv_pkt->frefs;
698            --ft_lc >= 0; ++fref_ptr, ++rcv_fref_ptr) {
699          *fref_ptr = *rcv_fref_ptr;
700       }
701    }
702    MEM_UNLOCK(&Send_pkt);
703    FREE(&Send_pkt);
704    MEM_UNLOCK(&Recv_pkt);
705    FREE(&Recv_pkt);
706
707    session_active = TRUE;
708    return(db_status = S_OKAY);
709 }
710 #endif
711
712 #ifndef NO_TRANS
713 /* Build application file lock tables
714 */
715 static int bld_lock_tables()
716 {
717 #ifndef SINGLE_USER
718    int fd_lc;           /* loop control */
719    int st_lc;           /* loop control */
720    INT_P File_used;
721 #define file_used File_used.ptr
722    int rec;
723    int mem, memtot;
724    FILE_NO i;
725    FILE_NO fl_cnt;
726    struct lock_descr *ld_ptr;
727    RECORD_ENTRY *rec_ptr;
728    FIELD_ENTRY *fld_ptr;
729    SET_ENTRY *set_ptr;
730    MEMBER_ENTRY *mem_ptr;
731    int *fu_ptr;
732    FILE_NO *fl_ptr;
733    unsigned new_size;
734    unsigned old_size;
735    int old_keyl_cnt;
736
737    old_size = old_size_ft*sizeof(int);
738    new_size = size_ft*sizeof(int);
739    File_used.ptr = NULL;
740    /* Macro references must be on one line for some compilers */ 
741    if ((ALLOC_TABLE(&db_global.App_locks, new_size, old_size, "app_locks")
742                                                                 != S_OKAY) ||
743        (ALLOC_TABLE(&db_global.Excl_locks, new_size, old_size, "excl_locks")
744                                                                 != S_OKAY) ||
745        (ALLOC_TABLE(&db_global.Kept_locks, new_size, old_size, "kept_locks")
746                                                                 != S_OKAY) ||
747        (ALLOC_TABLE(&File_used, new_size, old_size, "file_used")
748                                                                 != S_OKAY)) {
749       return( db_status );
750    }
751
752    old_size = old_size_rt * sizeof(struct lock_descr);
753    new_size = size_rt * sizeof(struct lock_descr);
754    if ((ALLOC_TABLE(&db_global.Rec_locks, new_size, old_size, "rec_locks")
755                                                                 != S_OKAY)) {
756       return( db_status );
757    }
758
759    if ( size_st ) {
760       new_size = size_st * sizeof(struct lock_descr);
761       old_size = old_size_st * sizeof(struct lock_descr);
762       /* Macro references must be on one line for some compilers */ 
763       if (ALLOC_TABLE(&db_global.Set_locks, new_size, old_size, "set_locks")
764                                                                 != S_OKAY ) {
765          return( db_status );
766       }
767    }
768
769    /* build rec_locks table */
770    for (rec = old_size_rt, rec_ptr = &record_table[old_size_rt], 
771            ld_ptr = rec_locks;
772         rec < size_rt;
773         ++rec, ++rec_ptr, ++ld_ptr) {
774       ld_ptr->fl_type = 'f'; 
775       ld_ptr->fl_prev = 'f';                    /*[367] init to free */
776       ld_ptr->fl_kept = FALSE;
777
778       /* put record's data file in list */
779       file_used[rec_ptr->rt_file] = TRUE;
780
781       /* add any key files to list */
782       fl_cnt = 1;  /* count of used files */
783       for (fd_lc = size_fd - rec_ptr->rt_fields,
784               fld_ptr = &field_table[rec_ptr->rt_fields];
785            (--fd_lc >= 0) && (fld_ptr->fd_rec == rec);
786            ++fld_ptr) {
787          if ( fld_ptr->fd_key != NOKEY )  {
788             fu_ptr = &file_used[fld_ptr->fd_keyfile];
789             if (!*fu_ptr) {
790                *fu_ptr = TRUE;
791                ++fl_cnt;
792             }
793          }
794       }
795       ld_ptr->fl_cnt = fl_cnt;
796       ld_ptr->fl_list.ptr =
797                 /* Macro references must be on one line for some compilers */ 
798     (FILE_NO *)ALLOC(&ld_ptr->fl_list, fl_cnt*sizeof(FILE_NO), db_avname);
799       if ( ld_ptr->fl_list.ptr == NULL ) return( dberr(S_NOMEMORY) );
800       fl_ptr = ld_ptr->fl_list.ptr;
801       for (i = 0, fu_ptr = file_used; i < size_ft; ++i, ++fu_ptr) {
802          if (*fu_ptr) {
803             *fu_ptr = FALSE;
804             *fl_ptr++ = i;
805          }
806       }
807       FL_LIST_DEACCESS(ld_ptr);
808    }
809    /* build set_locks table */
810    if ( size_st ) {
811       for (st_lc = size_st - old_size_st, set_ptr = &set_table[old_size_st],
812                                                            ld_ptr = set_locks;
813            --st_lc >= 0; ++set_ptr, ++ld_ptr) {
814          /* add owner's data file */
815          file_used[record_table[set_ptr->st_own_rt].rt_file] = TRUE;
816          ld_ptr->fl_type = 'f'; 
817          ld_ptr->fl_prev = 'f';                 /*[367] init to free */
818          ld_ptr->fl_kept = FALSE;
819
820          /* add member record data files to list */
821          fl_cnt = 1; /* count of used files */
822          for (mem = set_ptr->st_members, memtot = mem + set_ptr->st_memtot,
823                                                    mem_ptr = &member_table[mem];
824               mem < memtot;
825               ++mem, ++mem_ptr) {
826             fu_ptr = &file_used[record_table[mem_ptr->mt_record].rt_file];
827             if (!*fu_ptr) {
828                *fu_ptr = TRUE;
829                ++fl_cnt;
830             }
831          }
832          ld_ptr->fl_cnt = fl_cnt;
833          ld_ptr->fl_list.ptr =
834                    /* Macro references must be on one line for some compilers */ 
835        (FILE_NO *)ALLOC(&ld_ptr->fl_list, fl_cnt*sizeof(FILE_NO), db_avname);
836          if ( ld_ptr->fl_list.ptr == NULL ) return( dberr(S_NOMEMORY) );
837          fl_ptr = ld_ptr->fl_list.ptr;
838          for (i = 0, fu_ptr = file_used; i < size_ft; ++i, ++fu_ptr) {
839             if (*fu_ptr) {
840                *fu_ptr = FALSE;
841                *fl_ptr++ = i;
842             }
843          }
844          FL_LIST_DEACCESS(ld_ptr);
845       }
846    }
847    /* build key_locks table */
848    keyl_cnt = 0;
849    old_keyl_cnt = keyl_cnt;
850    for (fd_lc = size_fd - old_size_fd, fld_ptr = &field_table[old_size_fd];
851         --fd_lc >= 0; ++fld_ptr) {
852       /* count number of keys */
853       if (fld_ptr->fd_key != NOKEY)
854          ++keyl_cnt;
855    }
856    if ( keyl_cnt ) {
857       old_size = old_keyl_cnt*sizeof(struct lock_descr);
858       new_size = keyl_cnt*sizeof(struct lock_descr);
859       /* Macro references must be on one line for some compilers */ 
860       if (ALLOC_TABLE(&db_global.Key_locks, new_size, old_size, "key_locks")
861                                                                    != S_OKAY) {
862          return( db_status );
863       }
864       for (fd_lc = size_fd - old_size_fd, fld_ptr = &field_table[old_size_fd],
865                                                            ld_ptr = key_locks;
866            --fd_lc >= 0; ++fld_ptr) {
867          if (fld_ptr->fd_key != NOKEY) {
868             ld_ptr->fl_type = 'f';
869             ld_ptr->fl_prev = 'f';                      /*[367] init to free */
870             ld_ptr->fl_kept = FALSE;
871             ld_ptr->fl_cnt = 1;
872             ld_ptr->fl_list.ptr = (FILE_NO *)ALLOC(&ld_ptr->fl_list, ld_ptr->fl_cnt*sizeof(FILE_NO), "fl_list");
873             if ( ld_ptr->fl_list.ptr == NULL ) return( dberr(S_NOMEMORY) );
874             *(ld_ptr->fl_list.ptr) = fld_ptr->fd_keyfile;
875             FL_LIST_DEACCESS(ld_ptr);
876             ++ld_ptr;
877          }
878       }
879    }
880    lp_size = sizeof(LM_LOCK) + (size_ft-1)*sizeof(LM_LOCKREQ);
881    fp_size = sizeof(LM_FREE) + (size_ft-1)*sizeof(INT);
882    lock_pkt = (LM_LOCK *)ALLOC(&db_global.Lock_pkt, lp_size, "lock_pkt");
883    free_pkt = (LM_FREE *)ALLOC(&db_global.Free_pkt, fp_size, "free_pkt");
884    if ( !lock_pkt || !free_pkt ) return( dberr(S_NOMEMORY) );
885    lock_pkt->fcn = L_LOCK;
886    free_pkt->fcn = L_FREE;
887    MEM_UNLOCK(&File_used);
888    FREE(&File_used);
889 #endif
890
891    return( db_status = S_OKAY );
892 }
893 #endif
894
895
896 /****************************************/
897 /*                                      */
898 /*              d_close                 */
899 /*                                      */
900 /****************************************/
901 /* Close database
902 */
903 int
904 d_close(TASK_ONLY)
905 TASK_DECL
906 {
907    int i;
908
909    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_ALL));
910
911    if ( dbopen ) {
912       db_status = S_OKAY;
913 #ifndef NO_TRANS
914       /* in case they forgot to end the transaction */
915       if ( trans_id ) 
916          d_trabort(TASK_ONLY);
917       else
918 #ifndef SINGLE_USER
919          if ( dbopen >= 2 )
920 #endif
921 #endif
922             dio_flush(); 
923
924       for (i = 0; i < size_ft; ++i) {
925          /* close all files */
926          dio_close(i); 
927       }
928
929 #ifdef MIKER /**@@@***/
930 #ifndef NO_COUNTRY
931    /* free the country table */
932    if ( db_global.ctbl_activ )
933       ctbl_free();
934 #endif
935 #endif
936
937 #ifndef NO_TRANS
938 #ifndef GENERAL
939       taf_close();
940 #endif
941 #endif
942 #ifndef SINGLE_USER
943       d_freeall(TASK_ONLY);
944 #endif
945 #ifndef NO_TRANS
946       if ( use_ovfl ) o_free();
947 #endif
948 /*    termfree();
949       key_close();
950       sk_free();
951       dio_free(); */
952 #ifndef SINGLE_USER
953       if ( db_lockmgr ) {
954          termses();
955       }
956 #endif
957    }
958    if ( dbopen ) {
959 #ifndef NO_TIMESTAMP
960       cr_time = 0;
961 #endif
962 #ifndef ONE_DB
963       setdb_on = FALSE;
964       curr_db = 0;
965       no_of_dbs = 1;
966 #endif
967 #ifndef SINGLE_USER
968       lock_tries = 5;
969       dbwait_time = 1;
970       db_lockmgr = 1;
971       session_active = FALSE;
972 #endif
973 #ifndef NO_TRANS
974       cache_ovfl = FALSE;
975       ov_initaddr = 0L;
976       ov_rootaddr = 0L;
977       ov_nextaddr = 0L;
978 #endif
979       db_status = S_OKAY;
980       curr_rec = NULL_DBA;
981       size_ft = 0;
982       size_rt = 0;
983       size_fd = 0;
984       size_st = 0;
985       size_mt = 0;
986       size_srt = 0;
987       size_kt = 0;
988       no_of_keys = 0;
989       dbopen = 0;
990    }
991    RETURN( db_status );
992 } /* d_close() */
993
994
995
996 #ifndef SINGLE_USER
997 /* Terminate lock manager session
998 */
999 termses()
1000 {
1001    LM_DBCLOSE_P Send_pkt;
1002    int ft_lc;                   /* loop control */
1003    int send_size;
1004    FILE_NO *fref_ptr;
1005    INT *snd_fref_ptr;
1006
1007    if ( session_active ) {
1008       send_size = sizeof(LM_DBCLOSE) + (size_ft-1)*sizeof(INT);
1009       send_pkt = (LM_DBCLOSE *)ALLOC(&Send_pkt, send_size, "send_pkt");
1010       if ( send_pkt == NULL ) return( dberr(S_NOMEMORY) );
1011       send_pkt->fcn = L_DBCLOSE;
1012       send_pkt->nfiles = size_ft;
1013       for (ft_lc = size_ft, fref_ptr = file_refs,
1014                                                 snd_fref_ptr = send_pkt->frefs;
1015            --ft_lc >= 0; ++fref_ptr, ++snd_fref_ptr)
1016          *snd_fref_ptr = *fref_ptr;
1017       if ( nw_send(lsn, (MESSAGE *)send_pkt, send_size) )
1018          return( neterr() );
1019
1020       nw_hangup(lsn);
1021       nw_sestat();
1022       MEM_UNLOCK(&Send_pkt);
1023       FREE(&Send_pkt);
1024       MEM_UNLOCK(&db_global.File_refs);
1025       FREE(&db_global.File_refs);
1026       session_active = FALSE;
1027    }
1028    return( db_status = S_OKAY );
1029 }
1030 #endif
1031
1032
1033
1034 /* Free all allocated memory upon termination
1035 */
1036 void termfree()
1037 {
1038 #ifndef SINGLE_USER
1039    int i;
1040    struct lock_descr *ld_ptr;
1041 #endif
1042
1043    /* free all allocated memory */
1044    if ( curr_mem ) {
1045       MEM_UNLOCK(&db_global.Curr_mem);
1046       FREE(&db_global.Curr_mem);
1047    }
1048    if ( curr_own ) {
1049       MEM_UNLOCK(&db_global.Curr_own);
1050       FREE(&db_global.Curr_own);
1051    }
1052 #ifndef  NO_TIMESTAMP
1053    if ( co_time ) {
1054       MEM_UNLOCK(&db_global.Co_time);
1055       FREE(&db_global.Co_time);
1056    }
1057    if ( cm_time ) {
1058       MEM_UNLOCK(&db_global.Cm_time);
1059       FREE(&db_global.Cm_time);
1060    }
1061    if ( cs_time ) {
1062       MEM_UNLOCK(&db_global.Cs_time);
1063       FREE(&db_global.Cs_time);
1064    }
1065 #endif
1066    if ( sort_table ) {
1067       MEM_UNLOCK(&db_global.Sort_table);
1068       FREE(&db_global.Sort_table);
1069    }
1070    if ( member_table ) {
1071       MEM_UNLOCK(&db_global.Member_table);
1072       FREE(&db_global.Member_table);
1073    }
1074    if ( set_table ) {
1075       MEM_UNLOCK(&db_global.Set_table);
1076       FREE(&db_global.Set_table);
1077    }
1078    if ( field_table ) {
1079       MEM_UNLOCK(&db_global.Field_table);
1080       FREE(&db_global.Field_table);
1081    }
1082    if ( key_table ) {
1083       MEM_UNLOCK(&db_global.Key_table);
1084       FREE(&db_global.Key_table);
1085    }
1086    if ( record_table ) {
1087       MEM_UNLOCK(&db_global.Record_table);
1088       FREE(&db_global.Record_table);
1089    }
1090    if ( file_table ) {
1091       MEM_UNLOCK(&db_global.File_table);
1092       FREE(&db_global.File_table);
1093    }
1094 #ifndef SINGLE_USER
1095    if ( app_locks ) {
1096       MEM_UNLOCK(&db_global.App_locks);
1097       FREE(&db_global.App_locks);
1098    }
1099    if ( excl_locks ) {
1100       MEM_UNLOCK(&db_global.Excl_locks);
1101       FREE(&db_global.Excl_locks);
1102    }
1103    if ( kept_locks ) {
1104       MEM_UNLOCK(&db_global.Kept_locks);
1105       FREE(&db_global.Kept_locks);
1106    }
1107    if ( rec_locks ) {
1108       for (i = 0, ld_ptr = rec_locks; i < size_rt; ++i, ++ld_ptr) {
1109          MEM_UNLOCK(&ld_ptr->fl_list);
1110          FREE(&ld_ptr->fl_list);
1111       }
1112       MEM_UNLOCK(&db_global.Rec_locks);
1113       FREE(&db_global.Rec_locks);
1114    }
1115    if ( set_locks ) {
1116       for (i = 0, ld_ptr = set_locks; i < size_st; ++i, ++ld_ptr) {
1117          MEM_UNLOCK(&ld_ptr->fl_list);
1118          FREE(&ld_ptr->fl_list);
1119       }
1120       MEM_UNLOCK(&db_global.Set_locks);
1121       FREE(&db_global.Set_locks);
1122    }
1123    if ( key_locks ) {
1124       for (i = 0, ld_ptr = key_locks; i < keyl_cnt; ++i, ++ld_ptr) { /*[637]*/
1125          MEM_UNLOCK(&ld_ptr->fl_list);
1126          FREE(&ld_ptr->fl_list);
1127       }
1128       MEM_UNLOCK(&db_global.Key_locks);
1129       FREE(&db_global.Key_locks);
1130    }
1131    if ( lock_pkt ) {
1132       MEM_UNLOCK(&db_global.Lock_pkt);
1133       FREE(&db_global.Lock_pkt);
1134    }
1135    if ( free_pkt ) {
1136       MEM_UNLOCK(&db_global.Free_pkt);
1137       FREE(&db_global.Free_pkt);
1138    }
1139 #endif
1140 #ifndef  ONE_DB
1141    if ( db_table ) {
1142       MEM_UNLOCK(&db_global.Db_table);
1143       FREE(&db_global.Db_table);
1144    }
1145    if ( rn_table ) {
1146       MEM_UNLOCK(&db_global.Rn_table);
1147       FREE(&db_global.Rn_table);
1148    }
1149 #endif
1150 }
1151
1152 #ifndef NO_TRANS
1153 /* Establish record file locks
1154 */
1155 d_reclock(rec, lock_type TASK_PARM DBN_PARM)
1156 int rec;
1157 char *lock_type;
1158 TASK_DECL
1159 DBN_DECL
1160 {
1161 #ifdef SINGLE_USER
1162    return(db_status = S_OKAY);
1163 #else
1164    LOCK_REQUEST lr;
1165
1166    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_IO));
1167
1168    lr.item = rec;
1169    lr.type = *lock_type;
1170
1171    RETURN( d_lock(1, &lr TASK_PARM DBN_PARM) );
1172 #endif
1173 }
1174 #endif
1175
1176
1177 #ifndef NO_TRANS
1178 /* Establish set file locks
1179 */
1180 d_setlock(set, lock_type TASK_PARM DBN_PARM)
1181 int  set;
1182 char *lock_type;
1183 TASK_DECL
1184 DBN_DECL
1185 {
1186 #ifdef SINGLE_USER
1187    return (db_status = S_OKAY);
1188 #else
1189    LOCK_REQUEST lr;
1190
1191    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_IO));
1192
1193    lr.item = set;
1194    lr.type = *lock_type;
1195
1196    RETURN( d_lock(1, &lr TASK_PARM DBN_PARM) );
1197 #endif
1198 }
1199 #endif
1200
1201 #ifndef NO_TRANS
1202 /* Lock key file 
1203 */
1204 d_keylock(key, lock_type TASK_PARM DBN_PARM)
1205 long key;  /* field number of key */
1206 char *lock_type;
1207 TASK_DECL
1208 DBN_DECL
1209 {
1210 #ifdef SINGLE_USER
1211    return (db_status = S_OKAY);
1212 #else
1213    int fld, rec;
1214    LOCK_REQUEST lr;
1215    RECORD_ENTRY *rec_ptr;
1216    FIELD_ENTRY *fld_ptr;
1217
1218    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_IO));
1219
1220    if (nfld_check(key, &rec, &fld, (RECORD_ENTRY * *)&rec_ptr, (FIELD_ENTRY * *)&fld_ptr) != S_OKAY)
1221       RETURN( db_status );
1222
1223    if (fld_ptr->fd_key == NOKEY)
1224       RETURN( dberr(S_NOTKEY) );
1225
1226    /* KEYMARK allows 'fld' to be recognized as a key file.  It is already
1227       adjusted (in nfld_check) to INTernal format.  Don't play with it in
1228       d_lock and lock_files.
1229    */
1230    lr.item = fld + KEYMARK;
1231    lr.type = *lock_type;
1232
1233    RETURN( d_lock(1, &lr TASK_PARM DBN_PARM) );
1234 #endif
1235 }
1236 #endif
1237
1238 #ifndef NO_TRANS
1239 /* Return lock status for record type
1240 */
1241 d_reclstat(rec, lstat TASK_PARM DBN_PARM)
1242 int rec;
1243 char *lstat;
1244 TASK_DECL
1245 DBN_DECL
1246 {
1247 #ifdef SINGLE_USER
1248    *lstat = 'f';
1249    return( db_status = S_OKAY );
1250 #else
1251    RECORD_ENTRY *rec_ptr;
1252
1253    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_NOIO));
1254
1255    if (nrec_check(rec, &rec, (RECORD_ENTRY * *)&rec_ptr) != S_OKAY)
1256       RETURN( db_status );
1257
1258    if ( dbopen >= 2 )
1259       *lstat = 'f';
1260    else {
1261       if (rec_ptr->rt_flags & STATIC)
1262          *lstat = 's';
1263       else
1264          *lstat = rec_locks[rec].fl_type;
1265    }
1266    RETURN( db_status = S_OKAY );
1267 #endif
1268 }
1269 #endif
1270
1271 #ifndef NO_TRANS
1272 /* Return lock status for set type
1273 */
1274 d_setlstat(set, lstat TASK_PARM DBN_PARM)
1275 int set;
1276 char *lstat;
1277 TASK_DECL
1278 DBN_DECL
1279 {
1280 #ifdef SINGLE_USER
1281    *lstat = 'f';
1282    return (db_status = S_OKAY);
1283 #else
1284    SET_ENTRY *set_ptr;
1285
1286    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_NOIO));
1287
1288    if (nset_check(set, &set, (SET_ENTRY * *)&set_ptr) != S_OKAY)
1289       RETURN( db_status );
1290
1291    if ( dbopen >= 2 )
1292       *lstat = 'f';
1293    else
1294       *lstat = set_locks[set].fl_type;
1295
1296    RETURN( db_status = S_OKAY );
1297 #endif
1298 }
1299 #endif
1300
1301 #ifndef NO_TRANS
1302 /* Return lock status for key type
1303 */
1304 d_keylstat(key, lstat TASK_PARM DBN_PARM)
1305 long key;
1306 char *lstat;
1307 TASK_DECL
1308 DBN_DECL
1309 {
1310 #ifdef SINGLE_USER
1311    *lstat = 'f';
1312    return (db_status = S_OKAY);
1313 #else
1314    int fld, rec;
1315    RECORD_ENTRY *rec_ptr;
1316    FIELD_ENTRY *fld_ptr;
1317
1318    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_NOIO));
1319
1320    if (nfld_check(key, &rec, &fld, (RECORD_ENTRY * *)&rec_ptr, (FIELD_ENTRY * *)&fld_ptr) != S_OKAY)
1321       RETURN( db_status );
1322
1323    if (fld_ptr->fd_key == NOKEY)
1324       RETURN( dberr(S_NOTKEY) );
1325
1326    if ( dbopen >= 2 )
1327       *lstat = 'f';
1328    else {
1329       if ( file_table[fld_ptr->fd_keyfile].ft_flags & STATIC )
1330          *lstat = 's';
1331       else
1332          *lstat = key_locks[fld_ptr->fd_keyno].fl_type;
1333    }
1334    RETURN( db_status = S_OKAY );
1335 #endif
1336 }
1337 #endif
1338
1339 #ifndef NO_TRANS
1340 /* Lock a group of records and/or sets
1341 */
1342 d_lock(count, lrpkt TASK_PARM DBN_PARM)
1343 int count;
1344 LOCK_REQUEST *lrpkt;
1345 TASK_DECL
1346 DBN_DECL
1347 {
1348 #ifdef SINGLE_USER
1349    return (db_status = S_OKAY);
1350 #else
1351    int item;
1352    int i;
1353    LOCK_REQUEST *lrpkt_ptr;
1354    struct lock_descr *ld_ptr;
1355
1356    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_IO));
1357
1358    if ( dbopen >= 2 )
1359       RETURN( db_status = S_OKAY );
1360
1361    lock_pkt->nfiles = 0;
1362    for (i = 0, lrpkt_ptr = lrpkt;
1363         (db_status == S_OKAY) && (i < count);
1364         ++i, ++lrpkt_ptr) {
1365       if ( lrpkt_ptr->item >= KEYMARK ) {
1366          /* do not adjust lrpkt->item (see comment in d_keylock) */
1367          item = field_table[lrpkt_ptr->item - KEYMARK].fd_keyno;
1368          process_lock(&key_locks[item], lrpkt_ptr->type);
1369       }
1370       else if ( lrpkt_ptr->item >= SETMARK ) {
1371          item = NUM2INT(lrpkt_ptr->item - SETMARK, st_offset);
1372          process_lock(&set_locks[item], lrpkt_ptr->type);
1373       }
1374       else if ( lrpkt_ptr->item >= RECMARK ) {
1375          item = NUM2INT(lrpkt_ptr->item - RECMARK, rt_offset);
1376          if ( record_table[item].rt_flags & STATIC )
1377             dberr(S_STATIC);
1378          else
1379             process_lock(&rec_locks[item], lrpkt_ptr->type);
1380       }
1381       else
1382          dberr( S_INVNUM );
1383    }
1384    if ( db_status == S_OKAY )
1385       lock_files(count, lrpkt);
1386
1387    if ( db_status != S_OKAY ) {
1388       /* reset lock descriptor tables to previous state */
1389       for (i = 0, lrpkt_ptr = lrpkt; i < count; ++i, ++lrpkt_ptr) {
1390          /* do not adjust lrpkt->item (see comment in d_keylock) */
1391          if ( lrpkt_ptr->item >= KEYMARK ) {
1392             item = field_table[lrpkt_ptr->item - KEYMARK].fd_keyno;
1393             ld_ptr = &key_locks[item];
1394          }
1395          else if ( lrpkt_ptr->item >= SETMARK ) {
1396             item = NUM2INT(lrpkt_ptr->item - SETMARK, st_offset);
1397             ld_ptr = &set_locks[item];
1398          }
1399          else if ( lrpkt_ptr->item >= RECMARK ) {
1400             item = NUM2INT(lrpkt_ptr->item - RECMARK, rt_offset);
1401             ld_ptr = &rec_locks[item];
1402          }
1403          else
1404             continue;
1405          ld_ptr->fl_type = ld_ptr->fl_prev;
1406       }
1407    }
1408    RETURN( db_status );
1409 #endif
1410 }
1411 #endif
1412
1413
1414 #ifndef SINGLE_USER
1415 /* Process set/record lock
1416 */
1417 static process_lock(ld_ptr, type )
1418 struct lock_descr *ld_ptr;
1419 char type;
1420 {
1421    int fl_lc;                   /* loop control */
1422    int fno;
1423    int i;
1424    LM_LOCKREQ *lockreq_ptr;
1425    FILE_NO *fl_ptr, fref;
1426
1427    db_status = S_OKAY;
1428    ld_ptr->fl_prev = ld_ptr->fl_type;
1429    switch( type ) {
1430       case 'k':
1431          if ( !trans_id )  
1432             dberr( S_TRNOTACT );
1433          else if ( ld_ptr->fl_prev == 'f' ) 
1434             dberr( S_NOTLOCKED );
1435          else if ( ld_ptr->fl_prev != 'x' ) 
1436             return( keep_locks(ld_ptr) );
1437          break;
1438       case 'r':
1439          if( ld_ptr->fl_prev != 'f' ) 
1440             dberr( S_NOTFREE );
1441          else 
1442             ld_ptr->fl_type = 'r';
1443          break;
1444       case 'w':
1445          if ( !trans_id )
1446             dberr( S_TRNOTACT );
1447          else if ( ld_ptr->fl_prev != 'f' && ld_ptr->fl_prev != 'r' ) 
1448             dberr( S_NOTFREE );
1449          else
1450             ld_ptr->fl_type = 'w';
1451          break;
1452       case 'x':
1453          if ( ld_ptr->fl_prev != 'f' && ld_ptr->fl_prev != 'r' ) 
1454             dberr(S_NOTFREE);
1455          else
1456             ld_ptr->fl_type = 'x';
1457          break;
1458       default:  
1459          dberr( S_BADTYPE );
1460    }
1461    if ( db_status == S_OKAY ) {
1462       /* build lock request packet */
1463       for (fl_lc = ld_ptr->fl_cnt, fl_ptr = FL_LIST_ACCESS(ld_ptr);
1464            --fl_lc >= 0; ++fl_ptr) {
1465          fref = file_refs[fno = *fl_ptr];
1466          for (i = 0, lockreq_ptr = lock_pkt->locks;
1467               (i < lock_pkt->nfiles) && (lockreq_ptr->fref != fref);
1468               ++i, ++lockreq_ptr)
1469             ;                           /* null statement */
1470
1471          if (i < lock_pkt->nfiles) {
1472             /* file already is in lock request packet */
1473             if ( lockreq_ptr->type == 'r' || ld_ptr->fl_type == 'x' )
1474                lockreq_ptr->type = ld_ptr->fl_type;
1475          }
1476          else if ( !excl_locks[fno] && ( !app_locks[fno] || 
1477               (ld_ptr->fl_type == 'w' && app_locks[fno] > 0) ||
1478               (ld_ptr->fl_type == 'x') ) ) {
1479             /* add to lock request packet */
1480             ++lock_pkt->nfiles;
1481             lockreq_ptr->fref = fref;
1482             lockreq_ptr->type = ld_ptr->fl_type;
1483          }
1484       }
1485       FL_LIST_DEACCESS(ld_ptr);
1486    }
1487    return( db_status );
1488 }
1489 #endif
1490
1491
1492 #ifndef NO_TRANS
1493 /* Lock database files
1494 */
1495 static lock_files(count, lrpkt )
1496 int count;
1497 LOCK_REQUEST *lrpkt;
1498 {
1499 #ifndef SINGLE_USER
1500    int fl_lc;                   /* loop control */
1501    struct lock_descr *ld_ptr;
1502    FILE_NO fno;
1503    int item;
1504    int l;
1505    LOCK_REQUEST *lrpkt_ptr;
1506    int *appl_ptr, *excl_ptr;
1507    FILE_NO *fl_ptr;
1508    
1509    lock_reply.status = L_OKAY;
1510    if ( lock_pkt->nfiles == 0 ) goto skip_send;
1511
1512    if ( send_lock() != S_OKAY )
1513       return( db_status );
1514
1515 skip_send:
1516    switch ( lock_reply.status ) {
1517       case L_OKAY:
1518          /* update app_locks and excl_lock tables */
1519          for (l = 0, lrpkt_ptr = lrpkt; l < count; ++l, ++lrpkt_ptr) {
1520             if (lrpkt_ptr->type == 'k')
1521                continue; /* skip keep lock requests */
1522             /* process each record/set lock */
1523             /* do not adjust lrpkt->item (see comment in d_keylock) */
1524             if ( lrpkt_ptr->item >= KEYMARK ) {
1525                item = field_table[lrpkt_ptr->item - KEYMARK].fd_keyno;
1526                ld_ptr = &key_locks[item];
1527             }
1528             else if ( lrpkt_ptr->item >= SETMARK ) {
1529                item = NUM2INT(lrpkt_ptr->item - SETMARK, st_offset);
1530                ld_ptr = &set_locks[item];
1531             }
1532             else {
1533                item = NUM2INT(lrpkt_ptr->item - RECMARK, rt_offset);
1534                ld_ptr = &rec_locks[item];
1535             }
1536             for (fl_lc = ld_ptr->fl_cnt, fl_ptr = FL_LIST_ACCESS(ld_ptr);
1537                  --fl_lc >= 0; ++fl_ptr) {
1538                /* process each file for each record/set lock */
1539                fno = *fl_ptr;
1540                appl_ptr = &app_locks[fno];
1541                excl_ptr = &excl_locks[fno];
1542                if ( !*appl_ptr && !*excl_ptr ) {
1543                   /* clear file's pages from cache */
1544                   dio_clrfile(fno);
1545                }
1546                if ( ld_ptr->fl_type == 'r' ) {
1547                   if ( *appl_ptr >= 0 ) 
1548                      /* increment if file free or read-locked */
1549                      ++*appl_ptr;
1550                }
1551                else {
1552                   if ( ld_ptr->fl_type == 'w' ) 
1553                      *appl_ptr = -1;
1554                   else if ( ld_ptr->fl_type == 'x' ) {
1555                      ++*excl_ptr;
1556                      if ( ld_ptr->fl_prev == 'r' ) {
1557                         /* read to excl lock upgrade */
1558                         --*appl_ptr;
1559                      }
1560                   }
1561                }
1562             }
1563             FL_LIST_DEACCESS(ld_ptr);
1564          }
1565          break;
1566       case L_UNAVAIL:
1567       case L_TIMEOUT:
1568          return( db_status = S_UNAVAIL );
1569       default:
1570          return( dberr(S_SYSERR) );
1571    }
1572 #endif
1573
1574    return( db_status = S_OKAY );
1575 }
1576 #endif
1577
1578
1579 #ifndef NO_TRANS
1580 /* Send lock request 
1581 */
1582 static int send_lock()
1583 {
1584 #ifndef SINGLE_USER
1585    LM_TREND trend_pkt;
1586    int send_size, recv_size;
1587
1588    if ( lock_pkt->nfiles ) {
1589       /* send lock request */
1590       send_size = sizeof(LM_LOCK) + (lock_pkt->nfiles-1)*sizeof(LM_LOCKREQ);
1591       if ( send_size > lp_size )
1592          return( dberr(S_SYSERR) );
1593       
1594 req_locks:
1595 #ifdef MONITOR
1596       printf("nw_send(lsn,lock_pkt->fcn=%ld,size=%d\n",lock_pkt->fcn,send_size);
1597 #endif
1598       if ( nw_send(lsn, (MESSAGE *)lock_pkt, send_size) )
1599          return( neterr() );
1600
1601       if ( nw_rcvmsg(lsn, (MESSAGE *)&lock_reply, sizeof(LR_LOCK), &recv_size) )
1602          return( neterr() );
1603 #ifdef MONITOR
1604       printf("nw_rcvmsg(lock_reply.fcn=%ld,lock_reply.status=%d\n",
1605          lock_reply.fcn,lock_reply.status);
1606 #endif
1607
1608       /* request must always be granted */
1609       if ( lock_reply.fcn != L_LOCK )
1610          return( dberr(S_NETSYNC) );
1611
1612       if (lock_reply.status == L_RECOVER) {
1613          /* perform auto-recovery */
1614          d_recover(lock_reply.logfile CURRTASK_PARM);
1615
1616          /* tell lock mgr we're done */
1617          trend_pkt.fcn = L_RECDONE;
1618          if (nw_send(lsn, (MESSAGE *)&trend_pkt, sizeof(LM_TREND)))
1619             return( neterr() );
1620
1621          /* re-issue lock request */
1622          goto req_locks;
1623       }
1624       if (lock_reply.status == L_QUEUEFULL) {
1625          sleep(dbwait_time);
1626          goto req_locks;
1627       }
1628    }
1629 #endif
1630
1631    return( db_status = S_OKAY );
1632 }
1633 #endif
1634
1635
1636 #ifndef NO_TRANS
1637 /* Free key lock
1638 */
1639 d_keyfree(key TASK_PARM DBN_PARM)
1640 long key;
1641 TASK_DECL
1642 DBN_DECL
1643 {
1644 #ifdef SINGLE_USER
1645    return (db_status = S_OKAY);
1646 #else
1647    int fld, rec;
1648    RECORD_ENTRY *rec_ptr;
1649    FIELD_ENTRY *fld_ptr;
1650    struct lock_descr *ld_ptr;
1651
1652    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_IO));
1653
1654    if (nfld_check(key, &rec, &fld, (RECORD_ENTRY * *)&rec_ptr, (FIELD_ENTRY * *)&fld_ptr) != S_OKAY)
1655       RETURN( db_status );
1656
1657    if ( fld_ptr->fd_key == NOKEY )
1658       RETURN( dberr(S_NOTKEY) );
1659
1660    if ( dbopen >= 2 )  /* exclusive access needs no locks */
1661       RETURN( db_status = S_OKAY );
1662
1663    ld_ptr = &key_locks[fld_ptr->fd_keyno];
1664    if ( trans_id )
1665       RETURN( dberr(S_TRFREE) );
1666
1667    if ( ld_ptr->fl_type == 'f' )
1668       RETURN( dberr(S_NOTLOCKED) );
1669
1670    free_files(ld_ptr);
1671    ld_ptr->fl_type = 'f';
1672
1673    RETURN( db_status );
1674 #endif
1675 }
1676 #endif
1677
1678
1679 #ifndef SINGLE_USER
1680 /* Setup table to keep locks after transaction end
1681 */
1682 static keep_locks( ld_ptr )
1683 struct lock_descr *ld_ptr;      /* Lock descriptor */
1684 {
1685    int fl_lc;                   /* loop control */
1686    FILE_NO *fl_ptr;
1687
1688    /* Mark lock as kept */
1689    ld_ptr->fl_kept = TRUE;                
1690
1691    for (fl_lc = ld_ptr->fl_cnt, fl_ptr = FL_LIST_ACCESS(ld_ptr);
1692         --fl_lc >= 0; ++fl_ptr)
1693       ++kept_locks[*fl_ptr];
1694    FL_LIST_DEACCESS(ld_ptr);
1695
1696    return( db_status = S_OKAY );
1697 }
1698 #endif
1699
1700 #ifndef NO_TRANS
1701 /* Free record lock
1702 */
1703 d_recfree(rec TASK_PARM DBN_PARM)
1704 int rec;
1705 TASK_DECL
1706 DBN_DECL
1707 {
1708 #ifdef SINGLE_USER
1709    return (db_status = S_OKAY);
1710 #else
1711    RECORD_ENTRY *rec_ptr;
1712    struct lock_descr *ld_ptr;
1713
1714    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_IO));
1715
1716    if (nrec_check(rec, &rec, (RECORD_ENTRY * *)&rec_ptr) != S_OKAY)
1717       RETURN( db_status );
1718
1719    if ( dbopen >= 2 )  /* exclusive access needs no locks */
1720       RETURN( db_status = S_OKAY );
1721
1722    ld_ptr = &rec_locks[rec];
1723
1724    if ( trans_id )
1725       RETURN( dberr(S_TRFREE) );
1726
1727    if ( ld_ptr->fl_type == 'f' )
1728       RETURN( dberr(S_NOTLOCKED) );
1729
1730    free_files(ld_ptr);
1731    ld_ptr->fl_type = 'f';
1732
1733    RETURN( db_status );
1734 #endif
1735 }
1736 #endif
1737
1738 #ifndef NO_TRANS
1739 /* Free set lock
1740 */
1741 d_setfree(set TASK_PARM DBN_PARM)
1742 int set;
1743 TASK_DECL
1744 DBN_DECL
1745 {
1746 #ifdef SINGLE_USER
1747    return (db_status = S_OKAY);
1748 #else
1749    SET_ENTRY *set_ptr;
1750    struct lock_descr *ld_ptr;
1751
1752    DB_ENTER(DB_ID TASK_ID LOCK_SET(LOCK_IO));
1753
1754    if (nset_check(set, &set, (SET_ENTRY * *)&set_ptr) != S_OKAY)
1755       RETURN( db_status );
1756
1757    if ( dbopen >= 2 )  /* exclusive access needs no locks */
1758       RETURN( db_status = S_OKAY );
1759
1760    ld_ptr = &set_locks[set];
1761
1762    if ( trans_id )
1763       RETURN( dberr(S_TRFREE) );
1764
1765    if ( ld_ptr->fl_type == 'f' )
1766       RETURN( dberr(S_NOTLOCKED) );
1767
1768    free_files(ld_ptr);
1769    ld_ptr->fl_type = 'f';
1770
1771    RETURN( db_status );
1772 #endif
1773 }
1774 #endif
1775
1776
1777
1778 #ifndef SINGLE_USER
1779 /* Free read-locked files associated with record or set
1780 */
1781 static int free_files(ld_ptr)
1782 struct lock_descr *ld_ptr;
1783 {
1784    int fl_lc;                   /* loop control */
1785    FILE_NO fno;
1786    LM_LOCKREQ *lockreq_ptr;
1787    int *appl_ptr;
1788    FILE_NO fref;
1789    FILE_NO *fl_ptr;
1790
1791    /* fill free packet */
1792    lock_pkt->nfiles = free_pkt->nfiles = 0; 
1793    for (fl_lc = ld_ptr->fl_cnt, fl_ptr = FL_LIST_ACCESS(ld_ptr);
1794         --fl_lc >= 0; ++fl_ptr) {
1795       fno = *fl_ptr;
1796       appl_ptr = &app_locks[fno];
1797       fref = file_refs[fno];
1798       if ( ld_ptr->fl_type == 'r' && *appl_ptr > 0 ) {
1799          /* free read lock */
1800          if ( --*appl_ptr == 0 && excl_locks[fno] == 0 ) {
1801             free_pkt->frefs[free_pkt->nfiles++] = fref;
1802             /* reset key scan position */
1803             if ( file_table[fno].ft_type == 'k' )
1804                key_reset(fno);
1805          }
1806       }
1807       else if ( --excl_locks[fno] == 0 ) {
1808          /* free exclusive access lock */
1809          if ( *appl_ptr > 0 ) {
1810             /* downgrade to read-lock */
1811             lockreq_ptr = &lock_pkt->locks[lock_pkt->nfiles++];
1812             lockreq_ptr->type = 'r';
1813             lockreq_ptr->fref = fref;
1814          }
1815          else {
1816             /* free excl-lock */
1817             free_pkt->frefs[free_pkt->nfiles++] = fref;
1818             dio_flush();
1819             /* reset key scan position */
1820             if ( file_table[fno].ft_type == 'k' )
1821                key_reset(fno);
1822          }
1823       }
1824       if ( ld_ptr->fl_kept ) {             
1825          /* Remove hold on lock */
1826          if ( --kept_locks[fno] < 0 ) return( dberr(S_BADLOCKS) );
1827          ld_ptr->fl_kept = FALSE; 
1828       }
1829    }
1830    FL_LIST_DEACCESS(ld_ptr);
1831    /* send any downgrades */
1832    if ( send_lock() == S_OKAY ) {
1833       /* free any files */
1834       send_free();
1835    }
1836    return( db_status );
1837 }
1838 #endif
1839
1840 #ifndef NO_TRANS
1841 /* free all locked files 
1842 */
1843 d_freeall(TASK_ONLY)
1844 TASK_DECL
1845 {
1846 #ifdef SINGLE_USER
1847    return (db_status = S_OKAY);
1848 #else
1849    int i;
1850    FILE_NO *fref_ptr;
1851    int *appl_ptr;
1852
1853    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
1854
1855    if ( ! dbopen ) RETURN( dberr(S_DBOPEN) );
1856
1857    if ( dbopen >= 2 )  /* exclusive access needs no locks */
1858       RETURN( db_status = S_OKAY );
1859
1860    if ( trans_id ) RETURN( dberr(S_TRFREE) );
1861
1862    free_pkt->nfiles = 0;
1863    for (i = 0, fref_ptr = file_refs, appl_ptr = app_locks;
1864         i < size_ft;
1865         ++i, ++fref_ptr, ++appl_ptr) {
1866       if (*appl_ptr) {
1867          *appl_ptr = FALSE;
1868          if (!excl_locks[i])
1869             free_pkt->frefs[free_pkt->nfiles++] = *fref_ptr;
1870       }
1871    }
1872    /* send free files packet */
1873    if ( send_free() != S_OKAY )
1874       RETURN( db_status );
1875    
1876    /* reset all lock descriptors */
1877    reset_locks();
1878
1879    /* reset all key file positions */
1880    key_reset(size_ft);
1881
1882    /* Clear cache pages and return */
1883    RETURN( dio_clear() );
1884 #endif
1885 }
1886 #endif
1887
1888
1889 #ifndef SINGLE_USER
1890 /* Reset lock descriptor tables
1891 */
1892 static void reset_locks()
1893 {
1894    int beg, end;
1895    int i;
1896    struct lock_descr *ld_ptr;
1897
1898    /* reset record lock descriptors */
1899    beg = 0;
1900    end = size_rt;
1901    for (i = beg, ld_ptr = &rec_locks[i]; i < end; ++i, ++ld_ptr) {
1902       if ( ld_ptr->fl_kept ) {
1903          ld_ptr->fl_type = 'r';
1904          ld_ptr->fl_kept = FALSE;
1905       }
1906       else if ( ld_ptr->fl_type != 'x' )
1907          ld_ptr->fl_type = 'f';
1908    }
1909    /* reset set lock descriptors */
1910    beg = 0;
1911    end = size_st;
1912    for (i = beg, ld_ptr = &set_locks[i]; i < end; ++i, ++ld_ptr) {
1913       if ( ld_ptr->fl_kept ) {
1914          ld_ptr->fl_type = 'r';
1915          ld_ptr->fl_kept = FALSE;
1916       }
1917       else if ( ld_ptr->fl_type != 'x' )
1918          ld_ptr->fl_type = 'f';
1919    }
1920    /* reset key lock descriptors */
1921    beg = 0;
1922    end = keyl_cnt;
1923    for (i = beg, ld_ptr = &key_locks[i]; i < end; ++i, ++ld_ptr) {
1924       if ( ld_ptr->fl_kept ) {
1925          ld_ptr->fl_type = 'r';
1926          ld_ptr->fl_kept = FALSE;
1927       }
1928       else if ( ld_ptr->fl_type != 'x' )
1929          ld_ptr->fl_type = 'f';
1930    }
1931 }
1932 #endif
1933
1934 #ifndef NO_TRANS
1935 /* Send free files packet
1936 */
1937 static int send_free()
1938 {
1939 #ifndef SINGLE_USER
1940    int send_size;
1941
1942    /* send any free packets */
1943    if ( free_pkt->nfiles ) {
1944       send_size = sizeof(LM_FREE) + (free_pkt->nfiles-1)*sizeof(INT);
1945       if ( send_size > fp_size )
1946          return ( dberr(S_SYSERR) );
1947
1948       if ( nw_send(lsn, (MESSAGE *)free_pkt, send_size) ) 
1949          return( neterr() );
1950    }
1951 #endif
1952    return( db_status = S_OKAY );
1953 }
1954 #endif
1955
1956
1957 #ifndef NO_TRANS
1958 /*------------------------------------------------------------------------
1959    Record Lock Bit Functions
1960 ------------------------------------------------------------------------*/
1961
1962 /* Set record lock bit of current record
1963 */
1964 d_rlbset(TASK_ONLY)
1965 TASK_DECL
1966 {
1967 #ifndef SINGLE_USER
1968    FILE_NO file;
1969    INT rid;
1970    int record_lock;
1971 #endif
1972
1973    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
1974
1975    if ( ! curr_rec ) RETURN( dberr(S_NOCR) );
1976    
1977 #ifndef SINGLE_USER
1978    file = NUM2INT((FILE_NO)((curr_rec >> FILESHIFT) & FILEMASK), ft_offset);
1979
1980    if ( dbopen == 1 && 
1981        (record_lock = (app_locks[file] >= 0 && !excl_locks[file])) ) {
1982       /* request record-lock on file */
1983       lock_pkt->nfiles = 1;
1984       lock_pkt->locks[0].type = 'R';
1985       lock_pkt->locks[0].fref = file_refs[file];
1986       if ( send_lock() != S_OKAY ) RETURN( db_status );
1987       if ( lock_reply.status != L_OKAY ) 
1988          RETURN( db_status = S_UNAVAIL );
1989    }
1990    if ( dio_rrlb(curr_rec, &rid) != S_OKAY )
1991       RETURN( db_status );
1992    if ( rid & RLBMASK )
1993       rlb_status = S_LOCKED;
1994    else {
1995       rid |= RLBMASK;
1996       rlb_status = dio_wrlb(curr_rec, rid);
1997    }
1998    if ( dbopen == 1 && record_lock ) {
1999       /* free or downgrade record-lock on file */
2000       if ( app_locks[file] ) {
2001          lock_pkt->nfiles = 1;
2002          lock_pkt->locks[0].type = 'r';
2003          lock_pkt->locks[0].fref = file_refs[file];
2004          if ( send_lock() != S_OKAY ) RETURN( db_status );
2005       }
2006       else {
2007          free_pkt->nfiles = 1;
2008          free_pkt->frefs[0] = file_refs[file];
2009          if ( send_free() != S_OKAY ) RETURN( db_status );
2010       }
2011    }
2012    RETURN( db_status = rlb_status );
2013 #else
2014    RETURN( db_status = S_OKAY );
2015 #endif
2016 }
2017 #endif
2018
2019 #ifndef NO_TRANS
2020 /* Clear record lock bit of current record
2021 */
2022 d_rlbclr(TASK_ONLY)
2023 TASK_DECL
2024 {
2025 #ifndef SINGLE_USER
2026    FILE_NO file;
2027    INT rid;
2028 #endif
2029
2030    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
2031
2032    if ( ! curr_rec ) RETURN( dberr(S_NOCR) );
2033
2034 #ifndef SINGLE_USER
2035    file = NUM2INT((FILE_NO)((curr_rec >> FILESHIFT) & FILEMASK), ft_offset);   
2036
2037    /* ensure that changes are allowed */
2038    if (dbopen == 1 && trans_id && app_locks[file] >= 0 && !excl_locks[file]) 
2039       RETURN( dberr(S_NOTLOCKED) );
2040    
2041    if ( dbopen == 1 && ! trans_id ) {
2042       /* request record-lock on file */
2043       lock_pkt->nfiles = 1;
2044       lock_pkt->locks[0].type = 'R';
2045       lock_pkt->locks[0].fref = file_refs[file];
2046       if ( send_lock() != S_OKAY ) RETURN( db_status );
2047       if ( lock_reply.status != L_OKAY ) 
2048          RETURN( db_status = S_UNAVAIL );
2049    }
2050
2051    /* read rlb */
2052    if ( dio_rrlb(curr_rec, &rid) != S_OKAY )
2053       RETURN( db_status );
2054
2055    /* clear rlb */
2056    rid &= ~RLBMASK;
2057    rlb_status = S_UNLOCKED;
2058    dio_wrlb(curr_rec, rid);
2059
2060    if ( dbopen == 1 && ! trans_id ) {
2061       /* free or downgrade record-lock on file */
2062       if ( app_locks[file] ) {
2063          lock_pkt->nfiles = 1;
2064          lock_pkt->locks[0].type = 'r';
2065          lock_pkt->locks[0].fref = file_refs[file];
2066          if ( send_lock() != S_OKAY ) RETURN( db_status );
2067       }
2068       else {
2069          free_pkt->nfiles = 1;
2070          free_pkt->frefs[0] = file_refs[file];
2071          if ( send_free() != S_OKAY ) RETURN( db_status );
2072       }
2073    }
2074 #else
2075    db_status = S_OKAY;
2076 #endif
2077    RETURN( db_status );
2078 }
2079 #endif
2080
2081
2082 #ifndef NO_TRANS
2083 /* Test record lock bit of current record
2084 */
2085 d_rlbtst(TASK_ONLY)
2086 TASK_DECL
2087 {
2088 #ifndef SINGLE_USER
2089    INT rid;
2090 #endif
2091
2092    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
2093
2094    if ( ! curr_rec ) RETURN( dberr(S_NOCR) );
2095    
2096 #ifndef SINGLE_USER
2097    if ( dio_rrlb(curr_rec, &rid) != S_OKAY )
2098       RETURN( db_status );
2099
2100    if ( rid & RLBMASK )
2101       db_status = S_LOCKED;
2102    else
2103       db_status = S_UNLOCKED;
2104
2105    RETURN( rlb_status = db_status );
2106 #else
2107    RETURN( db_status = S_UNLOCKED );
2108 #endif
2109
2110 }
2111 #endif
2112
2113
2114
2115 #ifndef NO_TRANS
2116 /*------------------------------------------------------------------------
2117    Database Transaction Processing Functions
2118 ------------------------------------------------------------------------*/
2119
2120 /* Begin transaction
2121 */
2122 d_trbegin(tid TASK_PARM)
2123 const char *tid;
2124 TASK_DECL
2125 {
2126    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
2127
2128    db_status = S_OKAY;
2129
2130    if ( ! dbopen ) RETURN( dberr(S_DBOPEN) );
2131
2132    if ( tid == NULL ) RETURN( dberr(S_TRANSID) );
2133    
2134
2135    if ( trans_id ) RETURN( dberr(S_TRACTIVE) );
2136
2137    /* changes were possible outside a transaction */
2138    dio_flush(); 
2139
2140    if ( use_ovfl ) {
2141       o_init();
2142    }
2143    trans_id = tid;
2144    RETURN( db_status );
2145 }
2146 #endif
2147
2148
2149 #ifndef NO_TRANS
2150 /* End transaction
2151 */
2152 d_trend(TASK_ONLY)
2153 TASK_DECL
2154 {
2155 #ifndef SINGLE_USER
2156    int ft_lc;                   /* loop control */
2157    LM_TRCOMMIT trcom_pkt;
2158    LM_TREND trend_pkt;
2159    LM_LOCKREQ *lockreq_ptr;
2160    FILE_NO *fref_ptr;
2161    int *appl_ptr, *keptl_ptr, *excl_ptr;
2162 #endif
2163
2164    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
2165
2166    db_status = S_OKAY;
2167    if( ! trans_id ) RETURN( dberr(S_TRNOTACT) );
2168
2169    if( trlog_flag ) 
2170       /* mark start of trx in archive log file */
2171       d_trmark(); 
2172
2173    /* flush data to database or overflow */
2174    if ( dio_flush() != S_OKAY ) RETURN( db_status );
2175
2176    if ( (dboptions & TRLOGGING) && use_ovfl ) {
2177       /* End trx using overflow file */
2178
2179       /* flush recovery data to overflow file */
2180       if ( o_flush() != S_OKAY ) RETURN( db_status );
2181
2182 #ifndef SINGLE_USER
2183       trcom_pkt.fcn = L_TRCOMMIT;
2184       strcpy(trcom_pkt.logfile, dblog);
2185       if ( nw_send(lsn, (MESSAGE *)&trcom_pkt, sizeof(LM_TRCOMMIT)) )
2186          RETURN( neterr() );
2187 #endif
2188       trcommit = TRUE;
2189
2190 #ifndef GENERAL
2191       if ( taf_add(dblog) != S_OKAY ) RETURN( db_status ); /* after nw_send */
2192 #endif
2193
2194       /* allow for user interrupt to test recovery */
2195       if ( db_txtest ) dberr(S_DEBUG);
2196
2197       if( cache_ovfl ) {
2198          /* update db from overflow file */
2199          if ( o_update() != S_OKAY ) RETURN( db_status );
2200       }
2201
2202       /* flush modified cache data to database */
2203       if ( dio_flush() != S_OKAY ) RETURN( db_status );
2204
2205 #ifndef GENERAL
2206       if ( taf_del(dblog) != S_OKAY ) RETURN( db_status ); /* before nw_send */
2207 #endif
2208    }
2209 #ifndef SINGLE_USER
2210       trend_pkt.fcn = L_TREND;
2211       if ( nw_send(lsn, (MESSAGE *)&trend_pkt, sizeof(LM_TREND)) )
2212          RETURN( neterr() );
2213 #endif
2214       trcommit = FALSE;
2215
2216    if( trlog_flag ) 
2217       /* mark end of trx in archive log file */
2218       d_trbound(); 
2219
2220    trans_id = NULL;
2221    o_init();                    /*[305] clear cache_ovfl flag */
2222
2223 #ifndef SINGLE_USER
2224    if ( dbopen == 1 ) {
2225       /* free unkept, non-exclusive file locks */
2226       lock_pkt->nfiles = free_pkt->nfiles = 0;
2227       for (ft_lc = size_ft, fref_ptr = file_refs, appl_ptr = app_locks,
2228                                 keptl_ptr = kept_locks, excl_ptr = excl_locks;
2229            --ft_lc >= 0; ++fref_ptr, ++appl_ptr, ++keptl_ptr, ++excl_ptr) {
2230          if (*excl_ptr)
2231             *appl_ptr = *keptl_ptr;
2232          else if ( *appl_ptr == -1 ) {
2233             if ( (*appl_ptr = *keptl_ptr) > 0 ) {
2234                lockreq_ptr = &lock_pkt->locks[lock_pkt->nfiles++];
2235                lockreq_ptr->type = 'r';
2236                lockreq_ptr->fref = *fref_ptr;
2237             }
2238             else
2239                free_pkt->frefs[free_pkt->nfiles++] = *fref_ptr;
2240          }
2241          else if ( *appl_ptr && (*appl_ptr = *keptl_ptr) == 0 )
2242             free_pkt->frefs[free_pkt->nfiles++] = *fref_ptr;
2243          *keptl_ptr = 0;
2244       }
2245       /* send lock downgrade request */
2246       if ( send_lock() != S_OKAY || send_free() != S_OKAY ) 
2247          RETURN( db_status );
2248
2249       /* clear lock descriptors */
2250       reset_locks();
2251
2252       /* reset all key file positions */
2253       key_reset(size_ft);
2254
2255       /* clear page buffers */
2256       dio_clear();
2257    }
2258 #endif
2259    RETURN( db_status );
2260 }
2261 #endif
2262
2263
2264 #ifndef NO_TRANS
2265 /* Abort transaction
2266 */
2267 d_trabort(TASK_ONLY)
2268 TASK_DECL
2269 {
2270 #ifdef SINGLE_USER
2271    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
2272    if (!trans_id)
2273       RETURN (dberr(S_TRNOTACT));
2274    trans_id = NULL;
2275    dio_pzclr();                 /*[425] clear page zero BEFORE dio_clear */
2276    dio_clear();                         /*[353] clear cache */
2277    RETURN (db_status = S_OKAY);
2278 #else
2279    int i;
2280    int *keptl_ptr;
2281    struct lock_descr *ld_ptr;
2282
2283    DB_ENTER(NO_DB_ID TASK_ID LOCK_SET(LOCK_IO));
2284
2285    db_status = S_OKAY;
2286    if ( ! trans_id ) RETURN( dberr(S_TRNOTACT) );
2287
2288    if ( dbopen == 1 ) {
2289       /* Revert any kept locks to unkept status */
2290       for (i = 0, keptl_ptr = kept_locks; i < size_ft; ++i, ++keptl_ptr)
2291          *keptl_ptr = 0;
2292       for (i = 0, ld_ptr = rec_locks; i < size_rt; ++i, ++ld_ptr)
2293          ld_ptr->fl_kept = FALSE;
2294       for (i = 0, ld_ptr = set_locks; i < size_st; ++i, ++ld_ptr)
2295          ld_ptr->fl_kept = FALSE;
2296       for (i = 0, ld_ptr = key_locks; i < keyl_cnt; ++i, ++ld_ptr)
2297          ld_ptr->fl_kept = FALSE;
2298    }
2299    trans_id = NULL;
2300    o_init();            /*[305] clear cache_ovfl flag */
2301
2302    dio_pzclr();         /*[425] clear page zero BEFORE d_freeall */
2303    if ( dbopen == 1 ) d_freeall(TASK_ONLY);
2304    dio_clear();
2305
2306    RETURN( db_status = S_OKAY );
2307 #endif
2308 }
2309 #endif
2310
2311 #ifndef SINGLE_USER
2312 /* Report a network error
2313 */
2314 neterr()
2315 {
2316     switch ( net_status ) {
2317         case N_OPENREJ:
2318             db_status = dberr( S_LMBUSY );
2319             break;
2320         case N_CALLNAME:
2321             db_status = dberr( S_NOLOCKMGR );
2322             break;
2323         case N_NAMEUSED:
2324             db_status = dberr( S_DUPUSERID );
2325             break;
2326         default:
2327             db_status = dberr( S_NETERR );
2328             break;
2329     }
2330     return( db_status );
2331 }
2332 #endif
2333
2334 int alloc_table(Table, new_size, old_size )
2335 CHAR_P *Table;
2336 #define table Table->ptr
2337 unsigned new_size;
2338 unsigned old_size;
2339 {
2340    CHAR_P Temp_table;
2341
2342    Temp_table.ptr = ALLOC(&Temp_table, new_size, varname);
2343    if ( Temp_table.ptr == NULL ) {
2344       return( dberr(S_NOMEMORY) );
2345    }
2346    byteset(&Temp_table.ptr[old_size], 0, new_size - old_size);
2347 #ifndef ONE_DB
2348    if ( old_size ) {
2349       bytecpy(Temp_table.ptr, table, old_size);
2350       MEM_UNLOCK(Table);
2351       FREE(Table);
2352    }
2353 #endif
2354    *Table = Temp_table;
2355    return( db_status );
2356 }
2357 /* vpp -nOS2 -dUNIX -nBSD -nVANILLA_BSD -nVMS -nMEMLOCK -nWINDOWS -nFAR_ALLOC -f/usr/users/master/config/nonwin dblfcns.c */