1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <vdb/extern.h>
28
29 #include "database-priv.h"
30 #include "dbmgr-priv.h"
31 #include "schema-priv.h"
32 #include "schema-parse.h"
33 #include "linker-priv.h"
34
35 #include <kdb/kdb-priv.h>
36 #include <vdb/manager.h>
37 #include <vdb/database.h>
38 #include <kdb/manager.h>
39 #include <kdb/database.h>
40 #include <kdb/meta.h>
41 #include <klib/debug.h>
42 #include <klib/log.h>
43 #include <klib/rc.h>
44 #include <sysalloc.h>
45
46 #include <stdlib.h>
47 #include <string.h>
48 #include <assert.h>
49
50
51 /*--------------------------------------------------------------------------
52 * VDatabase
53 * opaque connection to a database within file system
54 */
55
56
57 /* StoreSchema
58 */
VDatabaseStoreSchema(VDatabase * self)59 rc_t VDatabaseStoreSchema ( VDatabase *self )
60 {
61 /* open schema node */
62 KMDataNode *node;
63 rc_t rc = KMetadataOpenNodeUpdate ( self -> meta, & node, "schema" );
64 if ( rc == 0 )
65 {
66 size_t num_writ;
67 char expr [ 256 ];
68 rc = VSchemaToText ( self -> schema, expr, sizeof expr - 1, & num_writ,
69 "%N%V", self -> sdb -> name, self -> sdb -> version );
70 if ( rc != 0 )
71 LOGERR ( klogInt, rc, "failed to determine database schema" );
72 else
73 {
74 expr [ num_writ ] = 0;
75 rc = KMDataNodeWriteAttr ( node, "name", expr );
76 if ( rc != 0 )
77 PLOGERR (klogInt, ( klogInt, rc, "failed to write database type '$(expr)'", "expr=%s", expr ));
78 else
79 {
80 /* truncate existing schema */
81 rc = KMDataNodeWrite ( node, "", 0 );
82 if ( rc == 0 )
83 {
84 rc = VSchemaDump ( self -> schema, sdmCompact, expr,
85 ( rc_t ( CC * ) ( void*, const void*, size_t ) ) KMDataNodeAppend, node );
86 }
87 if ( rc != 0 )
88 PLOGERR (klogInt, ( klogInt, rc, "failed to write database schema '$(expr)'", "expr=%s", expr ));
89 }
90 }
91
92 KMDataNodeRelease ( node );
93 }
94 return rc;
95 }
96
97
98 /* OpenUpdate
99 * finish create operation
100 */
101 static
VDatabaseOpenUpdate(VDatabase * self,const char * decl)102 rc_t VDatabaseOpenUpdate ( VDatabase *self, const char *decl )
103 {
104 /* open metadata */
105 rc_t rc = KDatabaseOpenMetadataUpdate ( self -> kdb, & self -> meta );
106 if ( rc == 0 )
107 {
108 /* fetch stored schema */
109 rc = VDatabaseLoadSchema ( self );
110 if ( rc == 0 )
111 {
112 /* fetch requested schema */
113 const SDatabase *sdb = self -> sdb;
114 if ( decl != NULL && decl [ 0 ] != 0 )
115 {
116 uint32_t type;
117 const SNameOverload *name;
118
119 if ( self -> dad != NULL )
120 {
121 const SDBMember *mbr = SDatabaseFind ( self -> dad -> sdb,
122 self -> schema, & name, & type, decl, "VDatabaseOpenUpdate" );
123 if ( mbr == NULL || type != eDBMember )
124 {
125 PLOGMSG ( klogWarn, ( klogWarn, "expression '$(expr)' is not a database member",
126 "expr=%s", decl ));
127 sdb = NULL;
128 }
129 else
130 {
131 sdb = mbr -> db;
132 assert ( sdb != NULL );
133 }
134 }
135 else
136 {
137 sdb = VSchemaFind ( self -> schema,
138 & name, & type, decl, "VDatabaseOpenUpdate", true );
139 if ( sdb != NULL && type != eDatabase )
140 {
141 PLOGMSG ( klogWarn, ( klogWarn, "expression '$(expr)' is not a database",
142 "expr=%s", decl ));
143 sdb = NULL;
144 }
145 }
146 }
147
148 /* error if the two definitions differ */
149 if ( sdb != NULL && self -> sdb != NULL && sdb != self -> sdb )
150 rc = RC ( rcVDB, rcDatabase, rcOpening, rcSchema, rcIncorrect );
151 else if ( sdb == NULL && self -> sdb == NULL )
152 rc = RC ( rcVDB, rcDatabase, rcOpening, rcSchema, rcNotFound );
153 else if ( self -> sdb == NULL )
154 {
155 /* write schema to metadata */
156 self -> sdb = sdb;
157 rc = VDatabaseStoreSchema ( self );
158 }
159 else if ( sdb != NULL )
160 {
161 /* use latest schema but don't overwrite in metadata */
162 self -> sdb = sdb;
163 }
164 }
165 }
166
167 DBGMSG(DBG_VDB, DBG_FLAG(DBG_VDB_VDB), ("VDatabaseOpenUpdate = %d\n", rc));
168
169 return rc;
170 }
171
172
173 /* CreateDB
174 * VCreateDB
175 * create a new or open an existing database
176 *
177 * "db" [ OUT ] - return parameter for newly opened database
178 *
179 * "schema" [ IN ] - schema object containg database
180 * declaration to be used in creating db [ needed by manager ].
181 *
182 * "decl" [ IN ] - type and optionally version of db schema
183 *
184 * "cmode" [ IN ] - creation mode
185 *
186 * "path" [ IN ] - NUL terminated string in
187 * wd-native character set giving path to database
188 */
VDBManagerVCreateDB(VDBManager * self,VDatabase ** dbp,const VSchema * schema,const char * decl,KCreateMode cmode,const char * path,va_list args)189 LIB_EXPORT rc_t CC VDBManagerVCreateDB ( VDBManager *self, VDatabase **dbp,
190 const VSchema *schema, const char *decl,
191 KCreateMode cmode, const char *path, va_list args )
192 {
193 rc_t rc;
194
195 if ( dbp == NULL )
196 rc = RC ( rcVDB, rcMgr, rcCreating, rcParam, rcNull );
197 else
198 {
199 if ( self == NULL )
200 rc = RC ( rcVDB, rcMgr, rcCreating, rcSelf, rcNull );
201 else if ( schema == NULL )
202 rc = RC ( rcVDB, rcMgr, rcOpening, rcSchema, rcNull );
203 else if ( decl == NULL )
204 rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcNull );
205 else if ( decl [ 0 ] == 0 )
206 rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcEmpty );
207 else
208 {
209 rc = VDatabaseMake ( dbp, self, NULL, schema );
210 if ( rc == 0 )
211 {
212 VDatabase *db = * dbp;
213
214 rc = KDBManagerVCreateDB ( self -> kmgr, & db -> kdb, cmode, path, args );
215 if ( rc == 0 )
216 {
217 rc = VDatabaseOpenUpdate ( db, decl );
218 if ( rc == 0 )
219 return 0;
220
221 rc = ResetRCContext ( rc, rcVDB, rcMgr, rcCreating );
222 }
223
224 VDatabaseWhack ( db );
225 }
226 }
227
228 * dbp = NULL;
229 }
230 return rc;
231 }
232
VDBManagerCreateDB(VDBManager * self,VDatabase ** db,const VSchema * schema,const char * decl,KCreateMode cmode,const char * path,...)233 LIB_EXPORT rc_t CC VDBManagerCreateDB ( VDBManager *self, VDatabase **db,
234 const VSchema *schema, const char *decl,
235 KCreateMode cmode, const char *path, ... )
236 {
237 rc_t rc;
238 va_list args;
239
240 va_start ( args, path );
241 rc = VDBManagerVCreateDB ( self, db, schema, decl, cmode, path, args );
242 va_end ( args );
243
244 return rc;
245 }
246
VDatabaseVCreateDB(VDatabase * self,VDatabase ** dbp,const char * decl,KCreateMode cmode,const char * name,va_list args)247 LIB_EXPORT rc_t CC VDatabaseVCreateDB ( VDatabase *self, VDatabase **dbp,
248 const char *decl, KCreateMode cmode, const char *name, va_list args )
249 {
250 rc_t rc;
251
252 if ( dbp == NULL )
253 rc = RC ( rcVDB, rcDatabase, rcCreating, rcParam, rcNull );
254 else
255 {
256 if ( self == NULL )
257 rc = RC ( rcVDB, rcDatabase, rcCreating, rcSelf, rcNull );
258 else if ( decl == NULL )
259 rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcNull );
260 else if ( decl [ 0 ] == 0 )
261 rc = RC ( rcVDB, rcMgr, rcOpening, rcName, rcEmpty );
262 else if ( self -> read_only )
263 rc = RC ( rcVDB, rcDatabase, rcCreating, rcDatabase, rcReadonly );
264 else
265 {
266 rc = VDatabaseMake ( dbp, self -> mgr, self, self -> schema );
267 if ( rc == 0 )
268 {
269 VDatabase *db = * dbp;
270
271 rc = KDatabaseVCreateDB ( self -> kdb, & db -> kdb, cmode, name, args );
272 if ( rc == 0 )
273 {
274 rc = VDatabaseOpenUpdate ( db, decl );
275 if ( rc == 0 )
276 return 0;
277
278 rc = ResetRCContext ( rc, rcVDB, rcDatabase, rcCreating );
279 }
280
281 VDatabaseWhack ( db );
282 }
283 }
284
285 * dbp = NULL;
286 }
287 return rc;
288 }
289
VDatabaseCreateDB(VDatabase * self,VDatabase ** db,const char * decl,KCreateMode cmode,const char * name,...)290 LIB_EXPORT rc_t CC VDatabaseCreateDB ( VDatabase *self, VDatabase **db,
291 const char *decl, KCreateMode cmode, const char *name, ... )
292 {
293 rc_t rc;
294 va_list args;
295
296 va_start ( args, name );
297 rc = VDatabaseVCreateDB ( self, db, decl, cmode, name, args );
298 va_end ( args );
299
300 return rc;
301 }
302
VDatabaseVDropDB(VDatabase * self,const char * name,va_list args)303 LIB_EXPORT rc_t CC VDatabaseVDropDB ( VDatabase *self,
304 const char *name, va_list args)
305 {
306 return KDatabaseVDropDB(self->kdb, name, args);
307 }
308
VDatabaseDropDB(VDatabase * self,const char * name,...)309 LIB_EXPORT rc_t CC VDatabaseDropDB ( VDatabase *self,
310 const char *name, ... )
311 {
312 rc_t rc;
313 va_list args;
314
315 va_start ( args, name );
316 rc = VDatabaseVDropDB(self, name, args);
317 va_end ( args );
318
319 return rc;
320 }
321
VDatabaseVDropTable(VDatabase * self,const char * name,va_list args)322 LIB_EXPORT rc_t CC VDatabaseVDropTable ( VDatabase *self,
323 const char *name, va_list args)
324 {
325 return KDatabaseVDropTable(self->kdb, name, args);
326 }
327
VDatabaseDropTable(VDatabase * self,const char * name,...)328 LIB_EXPORT rc_t CC VDatabaseDropTable ( VDatabase *self,
329 const char *name, ... )
330 {
331 rc_t rc;
332 va_list args;
333
334 va_start ( args, name );
335 rc = VDatabaseVDropTable(self, name, args);
336 va_end ( args );
337
338 return rc;
339 }
340
341
342 /* OpenDBUpdate
343 * VOpenDBUpdate
344 * open a database for read/write
345 *
346 * "db" [ OUT ] - return parameter for newly opened database
347 *
348 * "schema" [ IN, NULL OKAY ] - schema object containg database
349 * declaration to be used in creating db [ needed by manager ].
350 *
351 * "path" [ IN ] - NUL terminated string in
352 * wd-native character set giving path to database
353 */
VDBManagerVOpenDBUpdate(VDBManager * self,VDatabase ** dbp,const VSchema * schema,const char * path,va_list args)354 LIB_EXPORT rc_t CC VDBManagerVOpenDBUpdate ( VDBManager *self, VDatabase **dbp,
355 const VSchema *schema, const char *path, va_list args )
356 {
357 rc_t rc;
358
359 if ( dbp == NULL )
360 rc = RC ( rcVDB, rcMgr, rcOpening, rcParam, rcNull );
361 else
362 {
363 if ( self == NULL )
364 rc = RC ( rcVDB, rcMgr, rcOpening, rcSelf, rcNull );
365 else
366 {
367 if ( schema == NULL )
368 schema = self -> schema;
369
370 rc = VDatabaseMake ( dbp, self, NULL, schema );
371 if ( rc == 0 )
372 {
373 VDatabase *db = * dbp;
374
375 rc = KDBManagerVOpenDBUpdate ( self -> kmgr, & db -> kdb, path, args );
376 if ( rc == 0 )
377 {
378 rc = VDatabaseOpenUpdate ( db, NULL );
379 if ( rc == 0 )
380 return 0;
381 }
382
383 VDatabaseWhack ( db );
384 }
385 }
386
387 * dbp = NULL;
388 }
389 return rc;
390 }
391
VDBManagerOpenDBUpdate(VDBManager * self,VDatabase ** db,const VSchema * schema,const char * path,...)392 LIB_EXPORT rc_t CC VDBManagerOpenDBUpdate ( VDBManager *self, VDatabase **db,
393 const VSchema *schema, const char *path, ... )
394 {
395 rc_t rc;
396 va_list args;
397
398 va_start ( args, path );
399 rc = VDBManagerVOpenDBUpdate ( self, db, schema, path, args );
400 va_end ( args );
401
402 return rc;
403 }
404
VDatabaseVOpenDBUpdate(VDatabase * self,VDatabase ** dbp,const char * name,va_list args)405 LIB_EXPORT rc_t CC VDatabaseVOpenDBUpdate ( VDatabase *self, VDatabase **dbp,
406 const char *name, va_list args )
407 {
408 rc_t rc;
409
410 if ( dbp == NULL )
411 rc = RC ( rcVDB, rcDatabase, rcOpening, rcParam, rcNull );
412 else
413 {
414 if ( self == NULL )
415 rc = RC ( rcVDB, rcDatabase, rcOpening, rcSelf, rcNull );
416 else if ( self -> read_only )
417 rc = RC ( rcVDB, rcDatabase, rcOpening, rcDatabase, rcReadonly );
418 else
419 {
420 rc = VDatabaseMake ( dbp, self -> mgr, self, self -> schema );
421 if ( rc == 0 )
422 {
423 VDatabase *db = * dbp;
424
425 rc = KDatabaseVOpenDBUpdate ( self -> kdb, & db -> kdb, name, args );
426 if ( rc == 0 )
427 {
428 rc = VDatabaseOpenUpdate ( db, NULL );
429 if ( rc == 0 )
430 return 0;
431 }
432
433 VDatabaseWhack ( db );
434 }
435 }
436
437 * dbp = NULL;
438 }
439 return rc;
440 }
441
VDatabaseOpenDBUpdate(VDatabase * self,VDatabase ** db,const char * name,...)442 LIB_EXPORT rc_t CC VDatabaseOpenDBUpdate ( VDatabase *self, VDatabase **db, const char *name, ... )
443 {
444 rc_t rc;
445 va_list args;
446
447 va_start ( args, name );
448 rc = VDatabaseVOpenDBUpdate ( self, db, name, args );
449 va_end ( args );
450
451 return rc;
452 }
453
454 /* Lock
455 * apply lock
456 *
457 * if object is already locked, the operation is idempotent
458 * and returns an rc state of rcLocked
459 *
460 * "type" [ IN ] - a KDBPathType
461 * valid values are kptDatabase, kptTable and kptIndex
462 *
463 * "path" [ IN ] - NUL terminated path
464 */
VDatabaseVLock(VDatabase * self,uint32_t type,const char * name,va_list args)465 LIB_EXPORT rc_t CC VDatabaseVLock ( VDatabase *self, uint32_t type, const char *name, va_list args )
466 {
467 rc_t rc;
468
469 if ( self == NULL )
470 rc = RC ( rcVDB, rcDatabase, rcLocking, rcSelf, rcNull );
471 else
472 rc = KDatabaseVLock ( self -> kdb, type, name, args );
473
474 return rc;
475 }
476
VDatabaseLock(VDatabase * self,uint32_t type,const char * name,...)477 LIB_EXPORT rc_t CC VDatabaseLock ( VDatabase *self, uint32_t type, const char *name, ... )
478 {
479 rc_t rc;
480
481 va_list args;
482 va_start ( args, name );
483
484 rc = VDatabaseVLock ( self, type, name, args );
485
486 va_end ( args );
487
488 return rc;
489 }
490
491 /* Unlock
492 * remove lock
493 *
494 * if object is already unlocked, the operation is idempotent
495 * and returns an rc state of rcUnlocked
496 *
497 * "type" [ IN ] - a KDBPathType
498 * valid values are kptDatabase, kptTable and kptIndex
499 *
500 * "path" [ IN ] - NUL terminated path
501 */
VDatabaseVUnlock(VDatabase * self,uint32_t type,const char * name,va_list args)502 LIB_EXPORT rc_t CC VDatabaseVUnlock ( VDatabase *self, uint32_t type, const char *name, va_list args )
503 {
504 rc_t rc;
505
506 if ( self == NULL )
507 rc = RC ( rcVDB, rcDatabase, rcUnlocking, rcSelf, rcNull );
508 else
509 rc = KDatabaseVUnlock ( self -> kdb, type, name, args );
510
511 return rc;
512 }
513
VDatabaseUnlock(VDatabase * self,uint32_t type,const char * name,...)514 LIB_EXPORT rc_t CC VDatabaseUnlock ( VDatabase *self, uint32_t type, const char *name, ... )
515 {
516 rc_t rc;
517
518 va_list args;
519 va_start ( args, name );
520
521 rc = VDatabaseVUnlock ( self, type, name, args );
522
523 va_end ( args );
524
525 return rc;
526 }
527
528
529 /* OpenMetadataUpdate
530 * opens metadata for update
531 *
532 * "meta" [ OUT ] - return parameter for metadata
533 */
VDatabaseOpenMetadataUpdate(VDatabase * self,KMetadata ** meta)534 LIB_EXPORT rc_t CC VDatabaseOpenMetadataUpdate ( VDatabase *self, KMetadata **meta )
535 {
536 rc_t rc;
537 if ( meta == NULL )
538 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
539 else
540 {
541 * meta = NULL;
542
543 if ( self == NULL )
544 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
545 else
546 {
547 /* we operate under the notion of
548 single-threaded operation, so hand out
549 read or update capable object */
550 rc = KMetadataAddRef ( self -> meta );
551 if ( rc == 0 )
552 * meta = self -> meta;
553 }
554 }
555
556 return rc;
557 }
558
559
560 /* ColumnCreateParams
561 * sets the creation parameters for physical columns
562 *
563 * "cmode" [ IN ] - creation mode
564 *
565 * "checksum" [ IN ] - the type of checksum information to
566 * apply when writing blobs
567 *
568 * "pgsize" [ IN, DEFAULT ZERO ] - size of internal column "pages"
569 * the default value is indicated by 0 ( zero ).
570 * NB - CURRENTLY THE ONLY SUPPORTED PAGE SIZE IS 1 ( ONE ) BYTE.
571 */
VDatabaseColumnCreateParams(VDatabase * self,KCreateMode cmode,KChecksum checksum,size_t pgsize)572 LIB_EXPORT rc_t CC VDatabaseColumnCreateParams ( VDatabase *self,
573 KCreateMode cmode, KChecksum checksum, size_t pgsize )
574 {
575 if ( self == NULL )
576 return RC ( rcVDB, rcTable, rcUpdating, rcSelf, rcNull );
577
578 KDatabaseSetCmode ( self->kdb, cmode );
579 KDatabaseSetChecksum ( self->kdb, checksum );
580
581 self -> pgsize = pgsize;
582
583 return 0;
584 }
585
586
587 /* OpenManager
588 * duplicate reference to manager
589 * NB - returned reference must be released
590 */
VDatabaseOpenManagerUpdate(VDatabase * self,VDBManager ** mgr)591 LIB_EXPORT rc_t CC VDatabaseOpenManagerUpdate ( VDatabase *self, VDBManager **mgr )
592 {
593 rc_t rc;
594
595 if ( mgr == NULL )
596 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
597 else
598 {
599 if ( self == NULL )
600 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
601 else
602 {
603 rc = VDBManagerAddRef ( self -> mgr );
604 if ( rc == 0 )
605 {
606 * mgr = self -> mgr;
607 return 0;
608 }
609 }
610
611 * mgr = NULL;
612 }
613
614 return rc;
615 }
616
617
618 /* OpenParent
619 * duplicate reference to parent database
620 * NB - returned reference must be released
621 */
VDatabaseOpenParentUpdate(VDatabase * self,VDatabase ** par)622 LIB_EXPORT rc_t CC VDatabaseOpenParentUpdate ( VDatabase *self, VDatabase **par )
623 {
624 rc_t rc;
625
626 if ( par == NULL )
627 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
628 else
629 {
630 if ( self == NULL )
631 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
632 else if ( self -> dad != NULL && self -> dad -> read_only )
633 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcDatabase, rcReadonly );
634 else
635 {
636 rc = VDatabaseAddRef ( self -> dad );
637 if ( rc == 0 )
638 {
639 * par = self -> dad;
640 return 0;
641 }
642 }
643
644 * par = NULL;
645 }
646
647 return rc;
648 }
649
650
651 /* OpenKDatabase
652 * returns a new reference to underlying KDatabase
653 */
VDatabaseOpenKDatabaseUpdate(VDatabase * self,KDatabase ** kdb)654 LIB_EXPORT rc_t CC VDatabaseOpenKDatabaseUpdate ( VDatabase *self, KDatabase **kdb )
655 {
656 rc_t rc;
657
658 if ( kdb == NULL )
659 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
660 else
661 {
662 if ( self == NULL )
663 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
664 else if ( self -> read_only )
665 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcDatabase, rcReadonly );
666 else
667 {
668 rc = KDatabaseAddRef ( self -> kdb );
669 if ( rc == 0 )
670 {
671 * kdb = self -> kdb;
672 return 0;
673 }
674 }
675
676 * kdb = NULL;
677 }
678
679 return rc;
680 }
681