2 Fields and Table names are remapped to:
3 first char Upper case, the rest are lower case
5 The code generator (x.C) processes limited schema information and
6 creates code which operates a base class Db as schema describes.
8 x.C reads from stdin, and has 1 optional parameter (theDb class name)
9 comments are whitespace, form /*comment*/ or -- comment... <cr>
10 ./a.out < schema.txt <class_name=defaults to theDb>
11 this produces a source file s.C containing all
12 * table definitions in the form of: <Tbl>
13 constructed as: Entity Tbl(db);
14 * default locators in the form of <tbl>
15 constructed as: TblLoc tbl(Tbl);
16 <Tbl> = table name, first char capitalized.
17 <tbl> = table name, all lower case
18 * ikey_<Key_name> and rkey_<Key_name> class definitions
19 * key cmpr functions for ikey_<Key_name> and rkey_<Key_name>
20 * EntityObj functions: Allocate, Construct, Destruct, Deallocate;
21 * theDb class definition, with base class Db with
22 constructor and functions create, open, and close
24 x.C allowed input data as follow:
25 items in [] are optional
27 ** CREATE TABLE table;
28 * table = <table_name> ( <member> [, <member> ...] )
29 * member = <field_name> <dtype> [<xtype> ...]
30 * dtqual = ( [0-9...] ) | [UNSIGNED | SIGNED | ZEROFILL]
31 * dtype0 = BIT | TINYINT | SMALLINT | MEDIUMINT | INT | INTEGER | BIGINT |
32 REAL | DOUBLE | FLOAT | DECIMAL
33 * dtype1 = DATE | TIME | TIMESTAMP | YEAR |
34 CHAR | VARCHAR [BINARY] | BINARY | VARBINARY | BLOB | MEDIUMBLOB |
35 LONGBLOB | TINYTEXT | TEXT | MEDIUMTEXT | LONGTEXT | BOOL | BOOLEAN |
36 ENUM ( <enum_value> [, <enum_value> ...] )
37 * dtype = <dtype0> [<dtqual>] | <dtype1>
38 * xrefer = <table_name> ( <key_field> [, <key_field> ...] )
39 ON [DELETE | UPDATE] [RESTRICT | CASCADE | SET NULL | NO ACTION]
40 * def_int = [+|-][0-9...]
41 * def_dbl = <def_int>[.[0-9...]]
42 * def_str = '[notany(') | \any() ...]' | "[notany(") | \any() ...]"
43 * def_value = <def_str> | <def_int> | <def_dbl> | NULL
44 * xtype = [NOT] NULL | DEFAULT <def_value> | AUTO_INCREMENT |
45 UNIQUE [PRIMARY] [KEY] | PRIMARY [UNIQUE] [KEY] |
48 ** CREATE online modifier INDEX index;
49 * index = <index_name> ON <table_name> ( <key_field> [, <key_field> ...] );
50 * online = [ONLINE | OFFLINE]
51 * modifier = [UNIQUE | FULLTEXT | SPATIAL]
54 note: C++ type Schema field type
55 unsigned char: BOOLEAN, BIT, BINARY
56 [unsigned] char: CHAR, TINYINT
57 [unsigned] short: ENUM, SMALLINT
58 [unsigned] int: DECIMAL, MEDIUMINT, INT, INTEGER
59 [unsigned] long: BIGINT
62 char[n]: DATE[8], TIME[6], YEAR[4] TIMESTAMP[14], DATETIME[14]
63 char[]: VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT
64 unsigned char[]: VARBINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
69 CREATE TABLE user_newtalk (
70 user_id int NOT NULL default 0,
71 user_ip varbinary(40) NOT NULL default '',
72 user_last_timestamp varbinary(14) NULL default NULL
74 CREATE INDEX un_user_id ON user_newtalk (user_id);
75 CREATE INDEX un_user_ip ON user_newtalk (user_ip);
78 old_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
79 old_text mediumblob NOT NULL,
80 old_flags tinyblob NOT NULL
81 ) MAX_ROWS=10000000 AVG_ROW_LENGTH=10240; (MAX_ROWS,AVG_ROW_LENGTH are ignored)
85 To initialize/open a db instance:
93 int main(int ac, char **av)
95 if( db.create(dfn) ) {
96 fprintf(stderr,"create_db failed\n");
100 fprintf(stderr,"open failed\n");
107 Normally, almost everything is done with Key classes and locators.
108 There is a default locator for every entity (lower case tbl) in theDb.
109 defined similar to: Entity Tbl(db); TblLoc tbl(Tbl);
111 Locators provide access to the record member fields:
112 Access is provided by the .member() function.
113 value = tbl.Field(); // read access
114 tbl.Field(value); // write access
115 tbl.size_Field(); // size(value)
116 tbl._Field(); // addr(value)
117 tbl.Field(value,sz); // write access to varObj/blob field
118 tbl.set_wr(); // mark dirty
122 To create database records:
126 db.tbl.Allocate(); // allocates a Tbl record assigned to tbl locator
127 db.tbl.Field1(value1); // assignes values to new Tbl record fields
128 db.tbl.Field2(value2); // ...
129 db.tbl.Construct(); // runs theDb record constructor
132 the record constructor is normally generated by x.C and typically:
133 if_err( insertProhibit() ); // run consistancy checks
134 if_err( construct() ); // load id and reference
136 { rkey_Tbl_Key1 rkey(*this); // add all keys associated to new id
137 if_err( entity->index("Tbl_Key1")->Insert(rkey,&id) ); }
138 if_err( insertCascade() ); // run insert cascade functions
142 To access database records:
143 The TblLoc::ikey_Field key classes use immediate data for key values
144 The TblLoc::rkey_Field key classes use the current record for key values
146 The Db::Key class provides:
147 int Find(); // immedate ikey_ only
148 int Locate(int op=keyGE); // immedate ikey_ and relative rkey_
149 int First(); // relative rkey_ only
150 int Last(); // relative rkey_ only
151 int Next(); // relative rkey_ only
152 int First(pgRef &pos); // relative rkey_ only
153 int Next(pgRef &pos); // relative rkey_ only
155 To Locate/Find a table record (= EntityObj), use:
157 theDb db; db.open("/path/the.db");
158 int ret = TblLoc::ikey_Key1(db.tbl, key).Find();
159 if( ret != 0 ) printf(" not found, ret = %d\n",ret);
160 printf(" the record data is now %d\n", ++db.tbl.Data());
164 ** NOTE: <key field parameters> will be automatically constructed from
165 basic types, but for varObj types they should be explicity constructed
167 int ret = TblLoc::ikey_Key1(db.tbl, TblObj::t_Key1Field1(key, ksz)).Find();
169 Locate may be called with op=keyLT,keyLE,keyEQ,keyGE,keyGT
170 the index will be positioned to the appropriate boundry
171 keyEQ is mapped to keyLE when used with Locate
173 First/Next have a default cursor position associated to the index.
174 First/Next may return/use a cursor position locator which may be
175 used if multiple simultainious cursor positions are needed.
177 To iterate use Locate/First to set the cursor at a table record
178 then use Next to iterate until need records are exhausted.
180 theDb db; db.open("/path/the.db");
181 TblLoc::rkey_KeyField1 key1(db.tbl);
182 if( !(ret=key1.First()) ) do {
183 printf(" the record data is now %d\n", ++db.tbl.Data());
184 } while( !(ret=key1.Next()) );
190 To delete database records:
192 theDb db; db.open("/path/the.db");
193 while( !db.tbl.Last() ) {
194 db.tbl.Destruct(); // run theDb record destructor
195 db.tbl.Deallocate(); // release db storage assigned to db.tbl
198 the record destructor is normally generated by x.C and typically:
199 if_err( deleteProhibit() ); // run consistency checks
200 { rkey_Tbl_Key1 rkey(*this); // remove all keys associated to id
201 if_err( entity->index("Tbl_Key1")->Delete(rkey) ); }
202 if_err( destruct() ); // delete id and reference
203 if_err( deleteCascade() ); // run delete cascade functions
207 There are also "media" keys, which are bit field key records which
208 are organized by total "weight" = unsigned sum of bit fields. The
209 weight is recursively subdefined in left/right subfields, so that
210 all of the key record is encoded. This usually requires a little
211 over 3 times as much storage. This kind of key can index audio/video
212 data (and others, biometric, dna, images...). The key data can be:
213 built, recovered, and compared for both magnitude and error as sum
214 of squared/linear error. The work on this not complete at this time.
215 to insert (8 bit fields):
216 int ksz = Db::mediaKey::byte_size(sz, 8);
217 uint8_t *key = db.Tbl._key1(ksz);
218 Db::mediaKey::build(key, dat, 8, sz);
220 to access (8 bit fields):
221 int ksz = Db::mediaKey::byte_size(len, 8);
223 Db::mediaKey::build(key,dat,8,len);
224 PrefixLoc::ikey_Prefix_key_data ikey(db.prefix, key);
225 if( (ret=ikey.Find()) != 0 ) {
235 CPPFLAGS := -Wall -ggdb $(CFLAGS)
244 g++ -o $@ $(LDFLAGS) $+
251 prog.o: prog.C prog.h s.C db.h
258 a_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
259 a_name varchar(255) binary NOT NULL default '',
262 CREATE UNIQUE INDEX a_names ON a_tbl (a_name);
263 CREATE UNIQUE INDEX a_datum ON a_tbl (a_data);
278 void chk(int ret, const char *msg)
280 fprintf(stderr,"fail %s = %d\n",msg,ret);
284 void insert(const char *nm, int dat)
286 chk( db.a_tbl.Allocate(), "Allocate");
287 chk( db.a_tbl.A_name(nm), "A_name(nm)");
288 chk( db.a_tbl.A_data(dat, "A_data(dat)");
289 chk( db.a_tbl.Construct(), "Construct");
292 int main(int ac, char **av)
294 const char *dfn = ac > 1 ? av[1] : "the.db";
295 chk( db.create(dfn), "db.create");
296 chk( db.open(dfn), "db.open");
299 insert("a borrower", 321);
300 insert("nor lendor", 232);
303 chk( db.commit(), "commit()");
304 chk( db.close(), "close()");
305 chk( db.open(dfn, "db.reopen");
307 // lookup at datum using immedate key
309 A_tblLoc::ikey_A_datum ky(db.a_tbl,dat);
310 chk( ky.Find(), "ky.Find()");
311 printf("Found %d name %s\n",dat,db.a_tbl.A_name());
313 // look at datum using relative key
315 A_tblLoc::rkey_A_datum rky(db.a_tbl);
316 if( !(ret=rky.First()) ) do {
317 printf("Data %d name %s\n",db.a_tbl.A_data(),db.a_tbl.A_name());
318 } while( !(ret=rky.Next()) );
319 if( ret == Db::errNotFound ) ret = 0;
322 // get cursor position using immediate key
323 A_tblLoc::ikey_A_names iky(db.a_tbl,"b");
324 if( !(ret=iky.Locate()) ) {
325 // switch to relative key
326 A_tblLoc::rkey_A_names rky(db.a_tbl);
328 printf("Name %s data %d\n",db.a_tbl.A_name(),db.a_tbl.A_data());
329 } while( !(ret=rky.Next()) );
331 if( ret == Db::errNotFound ) ret = 0;
333 chk( db.commit(1), "commit(1)");
340 only one process allowed write access, no readers allowed
341 all allowed read lock while not write locked
342 to access database, typically:
346 if( access("/path/t.db", F_OK) ) db->create("/path/t.db");
347 if( !result ) result = openDb(rw);
350 int openDb(int rw) { return db->access("/path/tdb.db", SHM_KEY, rw); }
351 void closeDb() { detachDb(); db->close(); }
352 void commitDb() { db->commit(); } // detaches
353 void undoDb() { db->undo(); } // detaches
354 int attachDb(int rw) { return db->attach(rw); }
355 int detachDb() { return db->detach(); }
358 openDb(); detachDb(); ...
359 //typical read access
360 attachDb(); do_read(); detachDb(); ...
361 //typical write access
362 attachDb(1); do_write(); commitDb(); ...