1 /* Database access routines
2 Copyright (C) 1996, William M. Perry
4 This file is part of SXEmacs
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 /* Synched up with: Not in FSF. */
22 /* Written by Bill Perry */
23 /* Substantially rewritten by Martin Buchholz */
24 /* db 2.x support added by Andreas Jaeger */
33 #error HAVE_DATABASE not defined!!
36 #include "database.h" /* Our include file */
38 #ifdef HAVE_BERKELEY_DB
39 /* Work around Berkeley DB's use of int types which are defined
40 slightly differently in the not quite yet standard <inttypes.h>.
41 See db.h for details of why we're resorting to this... */
42 /* glibc 2.1 doesn't have this problem with DB 2.x */
43 #if !(defined __GLIBC__ && __GLIBC_MINOR__ >= 1)
44 #ifdef HAVE_INTTYPES_H
45 #define __BIT_TYPES_DEFINED__
48 typedef uint8_t u_int8_t;
49 typedef uint16_t u_int16_t;
50 typedef uint32_t u_int32_t;
51 #ifdef WE_DONT_NEED_QUADS
52 typedef uint64_t u_int64_t;
54 #endif /* WE_DONT_NEED_QUADS */
55 #endif /* HAVE_INTTYPES_H */
56 #endif /* !(defined __GLIBC__ && __GLIBC_MINOR__ >= 1) */
57 /* Berkeley DB wants __STDC__ to be defined; else if does `#define const' */
58 #if ! defined (__STDC__) && ! defined(__cplusplus)
61 #if defined(DB_H_FILE)
62 #include DB_H_FILE /* Berkeley db's header file */
64 #ifndef DB_VERSION_MAJOR
65 # define DB_VERSION_MAJOR 1
66 #endif /* DB_VERSION_MAJOR */
67 #ifndef DB_VERSION_MINOR
68 # define DB_VERSION_MINOR 0
69 #endif /* DB_VERSION_MINOR */
70 Lisp_Object Qberkeley_db;
71 Lisp_Object Qhash, Qbtree, Qrecno, Qunknown;
72 #if DB_VERSION_MAJOR > 2
75 #endif /* HAVE_BERKELEY_DB */
83 /* #### The following should be settable on a per-database level.
84 But the whole coding-system infrastructure should be rewritten someday.
85 We really need coding-system aliases. -- martin */
86 Lisp_Object Vdatabase_coding_system;
89 Lisp_Object Qdatabasep;
92 Lisp_Object(*get_subtype) (Lisp_Database *);
93 Lisp_Object(*get_type) (Lisp_Database *);
94 Lisp_Object(*get) (Lisp_Database *, Lisp_Object);
95 int (*put) (Lisp_Database *, Lisp_Object, Lisp_Object, Lisp_Object);
96 int (*rem) (Lisp_Database *, Lisp_Object);
97 void (*map) (Lisp_Database *, Lisp_Object);
98 void (*close) (Lisp_Database *);
99 Lisp_Object(*last_error) (Lisp_Database *);
102 struct Lisp_Database {
103 struct lcrecord_header header;
112 #ifdef HAVE_BERKELEY_DB
117 Lisp_Object coding_system;
121 #define XDATABASE(x) XRECORD (x, database, Lisp_Database)
122 #define XSETDATABASE(x, p) XSETRECORD (x, p, database)
123 #define DATABASEP(x) RECORDP (x, database)
124 #define CHECK_DATABASE(x) CHECK_RECORD (x, database)
125 #define CONCHECK_DATABASE(x) CONCHECK_RECORD (x, database)
126 #define DATABASE_LIVE_P(x) (x->live_p)
128 #define CHECK_LIVE_DATABASE(db) do { \
129 CHECK_DATABASE (db); \
130 if (!DATABASE_LIVE_P (XDATABASE(db))) \
131 signal_simple_error ("Attempting to access closed database", db); \
134 static Lisp_Database *allocate_database(void)
137 alloc_lcrecord_type(Lisp_Database, &lrecord_database);
141 #ifdef HAVE_BERKELEY_DB
142 db->db_handle = NULL;
145 db->dbm_handle = NULL;
151 db->coding_system = Fget_coding_system(Qbinary);
156 static Lisp_Object mark_database(Lisp_Object object)
158 Lisp_Database *db = XDATABASE(object);
163 print_database(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
166 Lisp_Database *db = XDATABASE(obj);
167 Lisp_Object tmp1, tmp2;
169 if (print_readably) {
170 error("printing unreadable object #<database 0x%x>",
173 write_c_string("#<database \"", printcharfun);
174 print_internal(db->fname, printcharfun, 0);
176 tmp1 = db->funcs->get_type(db);
177 tmp2 = db->funcs->get_subtype(db);
178 snprintf(buf, sizeof(buf), "\" (%s/%s/%s) 0x%x>",
179 (char *)string_data(XSYMBOL(tmp1)->name),
180 (char *)string_data(XSYMBOL(tmp2)->name),
181 (!DATABASE_LIVE_P(db) ? "closed" :
182 (db->access_ & O_WRONLY) ? "writeonly" :
183 (db->access_ & O_RDWR) ? "readwrite" : "readonly"),
185 write_c_string(buf, printcharfun);
188 static void finalize_database(void *header, int for_disksave)
190 Lisp_Database *db = (Lisp_Database *) header;
194 XSETDATABASE(object, db);
197 ("Can't dump an emacs containing database objects", object);
199 db->funcs->close(db);
202 DEFINE_LRECORD_IMPLEMENTATION("database", database,
203 mark_database, print_database,
204 finalize_database, 0, 0, 0, Lisp_Database);
206 DEFUN("close-database", Fclose_database, 1, 1, 0, /*
207 Close database DATABASE.
212 CHECK_LIVE_DATABASE(database);
213 db = XDATABASE(database);
214 db->funcs->close(db);
219 DEFUN("database-type", Fdatabase_type, 1, 1, 0, /*
220 Return the type of database DATABASE.
224 CHECK_DATABASE(database);
226 return XDATABASE(database)->funcs->get_type(XDATABASE(database));
229 DEFUN("database-subtype", Fdatabase_subtype, 1, 1, 0, /*
230 Return the subtype of database DATABASE, if any.
234 CHECK_DATABASE(database);
236 return XDATABASE(database)->funcs->get_subtype(XDATABASE(database));
239 DEFUN("database-live-p", Fdatabase_live_p, 1, 1, 0, /*
240 Return t if OBJECT is an active database.
244 return DATABASEP(object) && DATABASE_LIVE_P(XDATABASE(object)) ?
248 DEFUN("database-file-name", Fdatabase_file_name, 1, 1, 0, /*
249 Return the filename associated with the database DATABASE.
253 CHECK_DATABASE(database);
255 return XDATABASE(database)->fname;
258 DEFUN("databasep", Fdatabasep, 1, 1, 0, /*
259 Return t if OBJECT is a database.
263 return DATABASEP(object) ? Qt : Qnil;
267 static void dbm_map(Lisp_Database * db, Lisp_Object func)
269 datum keydatum, valdatum;
270 Lisp_Object key, val;
272 for (keydatum = dbm_firstkey(db->dbm_handle);
273 keydatum.dptr != NULL; keydatum = dbm_nextkey(db->dbm_handle)) {
274 valdatum = dbm_fetch(db->dbm_handle, keydatum);
276 make_string((unsigned char *)keydatum.dptr, keydatum.dsize);
278 make_string((unsigned char *)valdatum.dptr, valdatum.dsize);
279 call2(func, key, val);
283 static Lisp_Object dbm_get(Lisp_Database * db, Lisp_Object key)
285 datum keydatum, valdatum;
287 keydatum.dptr = (char *)XSTRING_DATA(key);
288 keydatum.dsize = XSTRING_LENGTH(key);
289 valdatum = dbm_fetch(db->dbm_handle, keydatum);
291 return (valdatum.dptr
292 ? make_string((unsigned char *)valdatum.dptr, valdatum.dsize)
297 dbm_put(Lisp_Database * db,
298 Lisp_Object key, Lisp_Object val, Lisp_Object replace)
300 datum keydatum, valdatum;
302 valdatum.dptr = (char *)XSTRING_DATA(val);
303 valdatum.dsize = XSTRING_LENGTH(val);
304 keydatum.dptr = (char *)XSTRING_DATA(key);
305 keydatum.dsize = XSTRING_LENGTH(key);
307 return !dbm_store(db->dbm_handle, keydatum, valdatum,
308 NILP(replace) ? DBM_INSERT : DBM_REPLACE);
311 static int dbm_remove(Lisp_Database * db, Lisp_Object key)
315 keydatum.dptr = (char *)XSTRING_DATA(key);
316 keydatum.dsize = XSTRING_LENGTH(key);
318 return dbm_delete(db->dbm_handle, keydatum);
321 static Lisp_Object dbm_type(Lisp_Database * db)
326 static Lisp_Object dbm_subtype(Lisp_Database * db)
331 static Lisp_Object dbm_lasterr(Lisp_Database * db)
333 return lisp_strerror(db->dberrno);
336 static void dbm_closeit(Lisp_Database * db)
338 if (db->dbm_handle) {
339 dbm_close(db->dbm_handle);
340 db->dbm_handle = NULL;
344 static DB_FUNCS ndbm_func_block = {
354 #endif /* HAVE_DBM */
356 #ifdef HAVE_BERKELEY_DB
357 static Lisp_Object berkdb_type(Lisp_Database * db)
362 static Lisp_Object berkdb_subtype(Lisp_Database * db)
367 switch (db->db_handle->type) {
374 #if DB_VERSION_MAJOR > 2
378 #ifdef HAVE_DB_UNKNOWN
386 static Lisp_Object berkdb_lasterr(Lisp_Database * db)
388 return lisp_strerror(db->dberrno);
391 static Lisp_Object berkdb_get(Lisp_Database * db, Lisp_Object key)
393 DBT keydatum, valdatum;
396 /* DB Version 2 requires DBT's to be zeroed before use. */
400 keydatum.data = XSTRING_DATA(key);
401 keydatum.size = XSTRING_LENGTH(key);
403 #if DB_VERSION_MAJOR == 1
404 status = db->db_handle->get(db->db_handle, &keydatum, &valdatum, 0);
407 db->db_handle->get(db->db_handle, NULL, &keydatum, &valdatum, 0);
408 #endif /* DB_VERSION_MAJOR */
411 /* #### Not mule-ized! will crash! */
412 return make_string((Bufbyte *) valdatum.data, valdatum.size);
414 #if DB_VERSION_MAJOR == 1
415 db->dberrno = (status == 1) ? -1 : errno;
417 db->dberrno = (status < 0) ? -1 : errno;
418 #endif /* DB_VERSION_MAJOR */
424 berkdb_put(Lisp_Database * db,
425 Lisp_Object key, Lisp_Object val, Lisp_Object replace)
427 DBT keydatum, valdatum;
430 /* DB Version 2 requires DBT's to be zeroed before use. */
434 keydatum.data = XSTRING_DATA(key);
435 keydatum.size = XSTRING_LENGTH(key);
436 valdatum.data = XSTRING_DATA(val);
437 valdatum.size = XSTRING_LENGTH(val);
438 #if DB_VERSION_MAJOR == 1
439 status = db->db_handle->put(db->db_handle, &keydatum, &valdatum,
440 NILP(replace) ? R_NOOVERWRITE : 0);
441 db->dberrno = (status == 1) ? -1 : errno;
443 status = db->db_handle->put(db->db_handle, NULL, &keydatum, &valdatum,
444 NILP(replace) ? DB_NOOVERWRITE : 0);
445 db->dberrno = (status < 0) ? -1 : errno;
446 #endif /* DV_VERSION_MAJOR = 2 */
451 static int berkdb_remove(Lisp_Database * db, Lisp_Object key)
456 /* DB Version 2 requires DBT's to be zeroed before use. */
459 keydatum.data = XSTRING_DATA(key);
460 keydatum.size = XSTRING_LENGTH(key);
462 #if DB_VERSION_MAJOR == 1
463 status = db->db_handle->del(db->db_handle, &keydatum, 0);
465 status = db->db_handle->del(db->db_handle, NULL, &keydatum, 0);
466 #endif /* DB_VERSION_MAJOR */
471 #if DB_VERSION_MAJOR == 1
472 db->dberrno = (status == 1) ? -1 : errno;
474 db->dberrno = (status < 0) ? -1 : errno;
475 #endif /* DB_VERSION_MAJOR */
480 static void berkdb_map(Lisp_Database * db, Lisp_Object func)
482 DBT keydatum, valdatum;
483 Lisp_Object key, val;
484 DB *dbp = db->db_handle;
490 #if DB_VERSION_MAJOR == 1
491 for (status = dbp->seq(dbp, &keydatum, &valdatum, R_FIRST);
493 status = dbp->seq(dbp, &keydatum, &valdatum, R_NEXT)) {
494 /* #### Needs mule-izing */
495 key = make_string((Bufbyte *) keydatum.data, keydatum.size);
496 val = make_string((Bufbyte *) valdatum.data, valdatum.size);
497 call2(func, key, val);
503 #if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6
504 status = dbp->cursor(dbp, NULL, &dbcp, 0);
506 status = dbp->cursor(dbp, NULL, &dbcp);
508 for (status = dbcp->c_get(dbcp, &keydatum, &valdatum, DB_FIRST);
510 status = dbcp->c_get(dbcp, &keydatum, &valdatum, DB_NEXT))
512 /* #### Needs mule-izing */
514 make_string((Bufbyte *) keydatum.data,
517 make_string((Bufbyte *) valdatum.data,
519 call2(func, key, val);
523 #endif /* DB_VERSION_MAJOR */
526 static void berkdb_close(Lisp_Database * db)
529 #if DB_VERSION_MAJOR == 1
530 db->db_handle->sync(db->db_handle, 0);
531 db->db_handle->close(db->db_handle);
533 db->db_handle->sync(db->db_handle, 0);
534 db->db_handle->close(db->db_handle, 0);
535 #endif /* DB_VERSION_MAJOR */
536 db->db_handle = NULL;
540 static DB_FUNCS berk_func_block = {
550 #endif /* HAVE_BERKELEY_DB */
552 DEFUN("database-last-error", Fdatabase_last_error, 0, 1, 0, /*
553 Return the last error associated with DATABASE.
558 return lisp_strerror(errno);
560 CHECK_DATABASE(database);
562 return XDATABASE(database)->funcs->last_error(XDATABASE(database));
565 DEFUN("open-database", Fopen_database, 1, 5, 0, /*
566 Return a new database object opened on FILE.
567 Optional arguments TYPE and SUBTYPE specify the database type.
568 Optional argument ACCESS specifies the access rights, which may be any
569 combination of 'r' 'w' and '+', for read, write, and creation flags.
570 Optional argument MODE gives the permissions to use when opening FILE,
571 and defaults to 0755.
573 (file, type, subtype, access_, mode))
575 /* This function can GC */
578 Lisp_Database *db = NULL;
580 struct gcpro gcpro1, gcpro2;
583 GCPRO2(file, access_);
584 file = Fexpand_file_name(file, Qnil);
587 TO_EXTERNAL_FORMAT(LISP_STRING, file,
588 C_STRING_ALLOCA, filename, Qfile_name);
591 accessmask = O_RDWR | O_CREAT;
594 CHECK_STRING(access_);
595 acc = (char *)XSTRING_DATA(access_);
597 if (strchr(acc, '+'))
598 accessmask |= O_CREAT;
601 char *rp = strchr(acc, 'r');
602 char *wp = strchr(acc, 'w');
604 accessmask |= O_RDWR;
606 accessmask |= O_WRONLY;
608 accessmask |= O_RDONLY;
613 modemask = 0755; /* rwxr-xr-x */
616 modemask = XINT(mode);
620 if (NILP(type) || EQ(type, Qdbm)) {
621 DBM *dbase = dbm_open(filename, accessmask, modemask);
625 db = allocate_database();
626 db->dbm_handle = dbase;
627 db->funcs = &ndbm_func_block;
630 #endif /* HAVE_DBM */
632 #ifdef HAVE_BERKELEY_DB
633 if (NILP(type) || EQ(type, Qberkeley_db)) {
636 #if DB_VERSION_MAJOR != 1
640 if (EQ(subtype, Qhash) || NILP(subtype))
641 real_subtype = DB_HASH;
642 else if (EQ(subtype, Qbtree))
643 real_subtype = DB_BTREE;
644 else if (EQ(subtype, Qrecno))
645 real_subtype = DB_RECNO;
646 #if DB_VERSION_MAJOR > 2
647 else if (EQ(subtype, Qqueue))
648 real_subtype = DB_QUEUE;
651 signal_simple_error("Unsupported subtype", subtype);
653 #if DB_VERSION_MAJOR == 1
655 dbopen(filename, accessmask, modemask, real_subtype, NULL);
659 /* Berkeley DB Version 2 has only the accessmask DB_CREATE and DB_RDONLY,
660 other flags shouldn't be set */
662 accessmask = DB_CREATE;
665 CHECK_STRING(access_);
666 acc = (char *)XSTRING_DATA(access_);
669 if (strchr(acc, '+'))
670 accessmask |= DB_CREATE;
672 if (strchr(acc, 'r') && !strchr(acc, 'w'))
673 accessmask |= DB_RDONLY;
675 #if DB_VERSION_MAJOR == 2
676 status = db_open(filename, real_subtype, accessmask,
677 modemask, NULL, NULL, &dbase);
681 status = db_create(&dbase, NULL, 0);
684 #if DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1)
685 status = dbase->open(dbase, filename, NULL,
686 real_subtype, accessmask, modemask);
687 #else /* DB_VERSION >= 4.1 */
688 /* DB_AUTO_COMMIT requires transaction support, don't try it */
689 status = dbase->open(dbase, NULL, filename, NULL, real_subtype,
690 accessmask, modemask);
691 #endif /* DB_VERSION < 4.1 */
693 dbase->close(dbase, 0);
696 #endif /* DB_VERSION_MAJOR > 2 */
697 /* Normalize into system specific file modes. Only for printing */
698 accessmask = accessmask & DB_RDONLY ? O_RDONLY : O_RDWR;
699 #endif /* DB_VERSION_MAJOR */
701 db = allocate_database();
702 db->db_handle = dbase;
703 db->funcs = &berk_func_block;
706 #endif /* HAVE_BERKELEY_DB */
708 signal_simple_error("Unsupported database type", type);
715 db->access_ = accessmask;
719 XSETDATABASE(retval, db);
724 DEFUN("put-database", Fput_database, 3, 4, 0, /*
725 Store KEY and VALUE in DATABASE.
726 If optional fourth arg REPLACE is non-nil,
727 replace any existing entry in the database.
729 (key, value, database, replace))
731 CHECK_LIVE_DATABASE(database);
735 Lisp_Database *db = XDATABASE(database);
736 int status = db->funcs->put(db, key, value, replace);
737 return status ? Qt : Qnil;
741 DEFUN("remove-database", Fremove_database, 2, 2, 0, /*
742 Remove KEY from DATABASE.
746 CHECK_LIVE_DATABASE(database);
749 Lisp_Database *db = XDATABASE(database);
750 int status = db->funcs->rem(db, key);
751 return status ? Qt : Qnil;
755 DEFUN("get-database", Fget_database, 2, 3, 0, /*
756 Return value for KEY in DATABASE.
757 If there is no corresponding value, return DEFAULT (defaults to nil).
759 (key, database, default_))
761 CHECK_LIVE_DATABASE(database);
764 Lisp_Database *db = XDATABASE(database);
765 Lisp_Object retval = db->funcs->get(db, key);
766 return NILP(retval) ? default_ : retval;
770 DEFUN("map-database", Fmapdatabase, 2, 2, 0, /*
771 Map FUNCTION over entries in DATABASE, calling it with two args,
772 each key and value in the database.
774 (function, database))
776 CHECK_LIVE_DATABASE(database);
778 XDATABASE(database)->funcs->map(XDATABASE(database), function);
783 void syms_of_database(void)
785 INIT_LRECORD_IMPLEMENTATION(database);
787 defsymbol(&Qdatabasep, "databasep");
789 defsymbol(&Qdbm, "dbm");
791 #ifdef HAVE_BERKELEY_DB
792 defsymbol(&Qberkeley_db, "berkeley-db");
793 defsymbol(&Qhash, "hash");
794 defsymbol(&Qbtree, "btree");
795 defsymbol(&Qrecno, "recno");
796 #if DB_VERSION_MAJOR > 2
797 defsymbol(&Qqueue, "queue");
799 defsymbol(&Qunknown, "unknown");
802 DEFSUBR(Fopen_database);
804 DEFSUBR(Fmapdatabase);
805 DEFSUBR(Fput_database);
806 DEFSUBR(Fget_database);
807 DEFSUBR(Fremove_database);
808 DEFSUBR(Fdatabase_type);
809 DEFSUBR(Fdatabase_subtype);
810 DEFSUBR(Fdatabase_last_error);
811 DEFSUBR(Fdatabase_live_p);
812 DEFSUBR(Fdatabase_file_name);
813 DEFSUBR(Fclose_database);
816 void vars_of_database(void)
821 #ifdef HAVE_BERKELEY_DB
822 Fprovide(Qberkeley_db);
825 #if 0 /* #### implement me! */
827 DEFVAR_LISP("database-coding-system", &Vdatabase_coding_system /*
828 Coding system used to convert data in database files.
830 Vdatabase_coding_system = Qnil;