chickadee » mdh


An interface to a Multidimensional Hierarchical database. This egg includes code from the open source MUMPS system available at It provides a simple and efficient interface to a persistent file-based database of arbitrary size. The database can also be seen as a tree and can be traversed and inspected.

See also the MDH programming guide for a more detailed look. This egg just provides a Scheme layer on top of the MDH C++ API.


(import mdh)

Programming interface

Access to the database is done through "globals", named entities stored in the database, with an optional list of indexes specifiying multi-dimensional arrays. Up to 10 dimensions can be given.

global GLOBALprocedure

Allocates a an object representing a global persistent variable. The object should be freed using global-free when it is no longer required. There may be multiple references to the same global variable at the same time in existance. GLOBAL may be a string, symbol or number and will be converted to a string. The result of global is a wrapper procedure, invoking it with a (possibly empty) set of indices is creates a reference to a specific location than can be further accessed and queried.

(define g (global "foo"))

(global-set! (g) 123)
(global-ref (g)) => "123"

Indices for as many as 10 dimensions may be given:

(global-set! (g 1 2) "xxx")
(global-ref (g 1 2)) => "xxx"
global-object Xprocedure

Returns the object contained in the global reference or wrapper procedure X or #f, if X is not related to a global. If X is already a global object, it is returned unchanged.

global? Xprocedure

Returns true if X is a global object record structure instance.

global-reference? Xprocedure

Returns true if X is a global object reference for a given location in the database.

global-name Gprocedure

Returns the name of the global object G.

global-reference-name GRprocedure

Returns the name of the global addressed by the global reference GR.

global-set! GR VALUEprocedure

Sets the value of the element addressed by the global reference GR to VALUE. VALUE will be converted to a string before it is stored. INDEX may be a string, symbol or number and will also be converted to string. If the element doesn't exist yet for G, then it is created. If GR refers to a global, then this is equivalent to global-set! (GR) VALUE).

global-ref GRprocedure

Returns the value of the element addressed by the global reference GR. If no element exists at that position, then the empty string is returned.

global-count GRprocedure

Returns the number of descendants of the node specified by the global reference.

global-free Gprocedure

Releases the storage required for the global object or wrapper procedure G. After using this procedure, referencing the database through G or any global reference derived from it will signal an error.

global-kill GRprocedure

Removes the given element and all its descendants from the database.

global-next GRprocedure

Returns the next index for the last item addressed by the given reference. Use the empty string as the final index if you want to obtain the first valid index holding data. If no further index is defined, returns the empty string:

(define g (global "foo"))
(global-set! (g 1) "a")
(global-set! (g 2) "b")
(global-next (g ""))      => "1"
(global-next (g "1"))     => "w"
(global-next (g "2"))     => ""
global-previous GRprocedure

Similar to global-next but retrieves the previous index.

global-data GRprocedure

Returns a symbol or #f identifying the type of node addressed by the reference GR.

  • #f: element is undefined
  • leaf: element has a value and no descendants
  • empty: element has no value but has descendants
  • branch: element has a value and descendants
global-merge GR1 GR2procedure

Copies the element and all its descendants given by the reference GR2 to the position identified by the reference GR1.

^ NAME INDEX ...procedure

Creates a temporary global reference for NAME and returns its value using global-ref. NAME may be a global object, a global wrapper procedure or a name that is converted to a string.

(set! (^ NAME INDEX ...) VALUE)setter

Equivalent to (global-set! (global NAME) VALUE INDEX ...) but takes care to free the wrapper object of the global reference properly after assigning the value. NAME may be a global object or a name that is converted to a string.

^order NAME INDEX ...procedure
^data NAME INDEX ...procedure
^next NAME INDEX ...procedure
^previous NAME INDEX ...procedure
^count NAME INDEX ...procedure
^kill NAME INDEX ...procedure

These are all convenience procedures that perform the named operation with an existing global object or a temporarily allocated global reference if NAME is not a global object.


Flushes any unwritten operations to the database and commits all pending operations.


Performs a flush-globals and closes all access to the database. This procedure is called automatically on normal or abnormal exit of the process. Also see "Caveats", below.


It is crucial to properly flush or close the database on exit or the file holding the persistent data may be incomplete or corrupted. For normal exit this is taken care of by setting [implicit-]exit-handler and handling the case when the process terminates with an error. When signals cause a process abort then code wanting to properly close the database must invoke flush-globals or close-globals explicitly.

Stored values and index strings can be at most 10000 bytes long.

More than 10 dimensions are currently not supported.


The original MDH database is maintained by Kevin O'Kane, see also the AUTHORS file in the egg distribution.

This egg was written and is maintained by Felix Winkelmann, using a subset of the original MDH source code. Many thanks to Luke K for the inspiration to create this egg and for providing helpful comments and suggestions.


This egg is hosted on the CHICKEN Subversion repository:

If you want to check out the source code repository of this egg and you are not familiar with Subversion, see this page.

Version history

Initial release


GNU General Public License

Contents »