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