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