User Tools

Site Tools


mbbsemu:development:sqlite_database_specifications

SQLite Database Specifications

MajorBBS & WorldGroup modules make heavy use of Btrieve databases.

Before continuing, please read information about the Btrieve database format located here.

Conversion

When a module attempts to load a Btrieve database for the first time, MBBSEmu loads the associated database .DAT file. It then reads in the entire database and converts it to a SQLite database with the same name but with a .DB extension.

The database is created with three tables that describe all the data within it

  • metadata_t
  • keys_t
  • data_t

The 'metadata_t' table

This table contains metadata information about the file, analogous to the file header in the Btrieve .DAT file. The schema is as follows

CREATE TABLE metadata_t(record_length INTEGER NOT NULL, physical_record_length INTEGER NOT NULL, page_length INTEGER NOT NULL, variable_length_records INTEGER NOT NULL, version INTEGER NOT NULL, acs_name STRING, acs BLOB)

The record_length field is the length of all the records stored in the database in the data column in the data_t table. For variable length records, this is the length of the fixed portion, so every record will be at least this large and of course could be much larger.

The physical_record_length is the length of each fixed physical record in the Btrieve file, and stored for informational purposes and not used by MBBSEmu.

The page_length is the length of each page in the Btrieve file, and likewise stored only for information purposes and not used by MBBSEmu.

variable_length_records indicates whether the records in this database are of variable length. Each record has a minimum length of record_length.

version specifies the schema version of this database. It is used for schema upgrades, for example if MBBSEmu has an update that changes the schema number and adds/removes database fields, MBBSEmu can examine the version field and automatically upgrade the database if necessary.

acs_name and acs are related fields and contain information about the Alternate Collating Sequence. ACS is used to alter string keys in the database. The acs table is a byte array of size 256 which performs a simple string mapping for keys. ACS tables are often used for implementing case-insensitive string keys - for example the ACS table would map lower case characters to upper case and the engine treats the key as all upper case.

acs_name and acs are both null if ACS tables are not used for the database. Otherwise acs_name is used for informational purposes only, and acs is a blob of length 256.


There is only one row in this table which contains the metadata for the entire database.

The 'keys_t' table

This table contains information about all the keys in the database. Each Btrieve database defines at least one key and these are all stored in keys_t

The schema is as follows:

CREATE TABLE keys_t(id INTEGER PRIMARY KEY, number INTEGER NOT NULL, segment INTEGER NOT NULL, attributes INTEGER NOT NULL, data_type INTEGER NOT NULL, offset INTEGER NOT NULL, length INTEGER NOT NULL, null_value INTEGER NOT NULL, UNIQUE(number, segment));

The number field is the key number. Keys are numbered 0 -> N.

The segment field is the segment of the key, numbered 0 -> N. A key may contain multiple segments and these are known as composite keys. Composite keys would have the same number field but incrementing segment fields.

The attributes field is analogous to the Btrieve attributes. See here

The data_type field is analogous to the Btrieve data type. See here

The offset field is the 0-based offset where the key data appears in the record.

The length field is the length of the key data in bytes.

The null_value field is the null value of the key, if the attributes specifies that the field is nullable.


There could be multiple rows in this table depending on how many keys are in the original Btrieve database.

The 'data_t' table

This table contains all the data/records in the database, one row for each record.

The schema is dynamic based on the key, but always contains at least the following:

CREATE TABLE data_t(id INTEGER PRIMARY KEY, data BLOB NOT NULL, key_0 <type> |NOT NULL| |UNIQUE|, ..., key_n <type> |NOT NULL| |UNIQUE|);

The id field is the unique identifier of the data, corresponding to the physical offset in the original Btrieve database. Physical offset aren't imported so the id values you will see are typically autoincremented starting with 1. They just need to be unique from one another.

The data field is the actual data for the record. Btrieve stores records as a blob of bytes and this is it. The key values are embedded inside this data field as well.

Each key_<number> field corresponds to each unique key number in keys_t - one for each key. Depending on the key attributes, it could be NOT NULL or UNIQUE. This key value contains the raw key data to be used during queries. This data will match the data in the data field, and duplicates the data, but by having the data as a separate column in the database, we can query/sort on it, which is a key feature used by modules.

Caveats

SQLite allows multiple processes to access a database at the same time, but MBBSEmu expects exclusive access. If you try to edit a SQLite database while MBBSEmu is running, MBBSEmu may crash and/or the modules may crash. To ensure safety, completely shutdown MBBSEmu before messing with the databases.

Interoperability

The databases created are standard sqlite databases, and as such can be modified by other programs. You can back them up or edit them as you see fit. The sqlite3 program can open them up and inspect/edit them.

Say you want to edit your character in MajorMUD. You can do that! Try this sample program which gives 1 copper, 1 silver, 1 gold and 1 platinum on MMUD 1.11g-WG

#!/usr/bin/python

import sqlite3

conn = sqlite3.connect('WCCUSERS.DB')

c = conn.cursor()
t = ('Paladine',)
c.execute('SELECT data FROM data_t WHERE key_0=?', t)

data = c.fetchone()

print data[0]

b = bytearray(data[0])
b[0x60C] = 0;
b[0x60D] = 0;
b[0x60E] = 0;
b[0x60F] = 0x1; # copper

b[0x608] = 0;
b[0x609] = 0;
b[0x60A] = 0;
b[0x60B] = 0x1; # silver

b[0x607] = 0x1; # gold

b[0x603] = 0x1; # platinum

# and write it back
t = (buffer(b), 'Paladine',)
c = conn.cursor()
c.execute('UPDATE data_t SET data=? WHERE key_0=?', t)
conn.commit()

This program dumps out your user data, so you can pipe it to a file, and then edits your character and saves it. You'll have to execute the program when MBBSEmu is offline

mbbsemu/development/sqlite_database_specifications.txt · Last modified: 2023/10/06 23:41 by 127.0.0.1