sdb.3 (5388B)
1 .TH SDB 3 2 .SH NAME 3 sdb_add, sdb_Bopen, sdb_close, sdb_edit, sdb_flush, sdb_n, sdb_next, sdb_open, sdb_openf, sdb_query, sdb_remove, sdb_rewind \- simple database 4 .SH SYNOPSIS 5 .B #include <u.h> 6 .br 7 .B #include <libc.h> 8 .br 9 .B #include <bio.h> 10 .br 11 .B #include <str.h> 12 .br 13 .B #include <vec.h> 14 .br 15 .B #include <sdbr.h> 16 .br 17 .B #include <sdb.h> 18 .PP 19 .ft L 20 .nf 21 .ta \w'\fL 'u +\w'\fLString 'u 22 typedef struct { 23 String ln; 24 Sdbr *r; 25 Biobuf *b; 26 ulong n; 27 } Sdb; 28 .fi 29 .PP 30 .ta \w'\fLvoid 'u 31 .B 32 void sdb_add(Sdb *db, Sdbr r) 33 .PP 34 .B 35 void sdb_Bopen(Sdb *db, Biobuf *b) 36 .PP 37 .B 38 void sdb_close(Sdb *db) 39 .PP 40 .B 41 void sdb_edit(Sdb *db, Sdbr q, Sdbr r) 42 .PP 43 .B 44 void sdb_flush(Sdb *db) 45 .PP 46 .B 47 ulong sdb_n(Sdb db) 48 .PP 49 .B 50 int sdb_next(Sdb *db) 51 .PP 52 .B 53 void sdb_open(Sdb *db, char *file) 54 .PP 55 .B 56 void sdb_openf(Sdb *db, char *fmt, ...) 57 .PP 58 .B 59 int sdb_query(Sdb *db, Sdbr q) 60 .PP 61 .B 62 void sdb_remove(Sdb *db) 63 .PP 64 .B 65 void sdb_rewind(Sdb *db) 66 .SH DESCRIPTION 67 These functions provide a simple database system for storing and querying 68 collections of records using the same format as Plan 9's network database (ndb). 69 An 70 .B Sdb 71 database contains a vector of 72 .B Sdbr 73 records, a current line buffer, a 74 .B Biobuf 75 for I/O, and a current record position. 76 While ndb supports importing multiple database files, 77 sdb operates on a single file or input stream. 78 .PP 79 .I Sdb_open 80 opens a database file 81 .I file 82 for reading. 83 If 84 .I file 85 is nil or empty, it reads from standard input. 86 .PP 87 .I Sdb_openf 88 opens a database file using a formatted filename created with 89 .I fmt 90 and additional arguments. 91 .PP 92 .I Sdb_Bopen 93 initializes a database using an existing 94 .I Biobuf 95 .IR b . 96 .PP 97 .I Sdb_close 98 closes the database and frees all associated resources. 99 .PP 100 .I Sdb_n 101 returns the number of records currently loaded in the database. 102 .PP 103 .I Sdb_next 104 advances to the next record in the database. 105 If records are already loaded, it moves to the next loaded record. 106 Otherwise, it reads the next record from the input. 107 It returns the record number starting from 1, or 0 if no more records. 108 Records are parsed from the input where each record consists of 109 attribute=value pairs separated by whitespace. 110 Multi-line records are supported with continuation lines starting with whitespace. 111 Comments starting with '#' are ignored. 112 .PP 113 .I Sdb_rewind 114 resets the current record position to the beginning of the loaded records. 115 .PP 116 .I Sdb_add 117 adds record 118 .I r 119 to the database and sets the current position to the newly added record. 120 .PP 121 .I Sdb_query 122 searches the database for records matching query 123 .IR q . 124 It returns 1 if a matching record is found and sets the current position to that record, 125 or 0 if no match is found. 126 The search starts from the current position and continues through all records, 127 loading new records from input as needed. 128 .PP 129 .I Sdb_edit 130 finds all records matching query 131 .I q 132 and applies edits from record 133 .I r 134 to each matching record. 135 If no matching record is found, it adds query 136 .I q 137 as a new record. 138 .PP 139 .I Sdb_remove 140 removes the current record from the database. 141 .PP 142 .I Sdb_flush 143 reads all remaining records from the input and prints all records 144 in the database to standard output. 145 .SH EXAMPLES 146 .PP 147 Reading and querying a database: 148 .IP 149 .EX 150 Sdb db; 151 Sdbr q; 152 153 sdb_open(&db, "users.db"); 154 sdbr_init(&q); 155 sdbr_add(&q, Str("type"), Str("admin")); 156 if(sdb_query(&db, q)) 157 sdbr_print(db.r[db.n]); 158 sdbr_close(&q); 159 sdb_close(&db); 160 .EE 161 .PP 162 Adding records to a database: 163 .IP 164 .EX 165 Sdb db; 166 Sdbr r; 167 168 sdb_open(&db, ""); 169 sdbr_init(&r); 170 sdbr_add(&r, Str("name"), Str("Alice")); 171 sdbr_add(&r, Str("role"), Str("user")); 172 sdb_add(&db, r); 173 sdb_flush(&db); 174 sdbr_close(&r); 175 sdb_close(&db); 176 .EE 177 .PP 178 Iterating through all records: 179 .IP 180 .EX 181 Sdb db; 182 183 sdb_open(&db, "data.db"); 184 while(sdb_next(&db)) 185 sdbr_print(db.r[db.n]); 186 sdb_close(&db); 187 .EE 188 .PP 189 Editing records: 190 .IP 191 .EX 192 Sdb db; 193 Sdbr q, r; 194 195 sdb_open(&db, "users.db"); 196 sdbr_init(&q); 197 sdbr_init(&r); 198 sdbr_add(&q, Str("name"), Str("Bob")); 199 sdbr_add(&r, Str("status"), Str("active")); 200 sdb_edit(&db, q, r); 201 sdb_flush(&db); 202 sdbr_close(&q); 203 sdbr_close(&r); 204 sdb_close(&db); 205 .EE 206 .PP 207 Log analysis with range queries: 208 .IP 209 .EX 210 Sdb db; 211 Sdbr q; 212 String s; 213 214 sdb_open(&db, "access.log"); 215 sdbr_init(&q); 216 sdbr_str2r(&q, Str("level=error " 217 "timestamp=>=2024-01-15T14:00:00")); 218 while(sdb_query(&db, q)) { 219 s = sdbr_val(db.r[db.n], "component"); 220 if(sdbr_match("*auth*", s.s)) 221 print("AUTH ERROR: %s\en", 222 sdbr_val(db.r[db.n], "message").s); 223 if(!sdb_next(&db)) 224 break; 225 } 226 sdbr_close(&q); 227 sdb_close(&db); 228 .EE 229 .PP 230 Server monitoring with negation: 231 .IP 232 .EX 233 Sdb db; 234 Sdbr q; 235 String s; 236 237 sdb_open(&db, "servers.db"); 238 sdbr_init(&q); 239 sdbr_str2r(&q, Str("type=server !status=maintenance " 240 "location=datacenter1")); 241 while(sdb_query(&db, q)) { 242 s = sdbr_val(db.r[db.n], "hostname"); 243 print("Active server: %s\en", s.s); 244 if(!sdb_next(&db)) 245 break; 246 } 247 sdbr_close(&q); 248 sdb_close(&db); 249 .EE 250 .SH SOURCE 251 .B \*9/src/libsdb 252 .SH SEE ALSO 253 .MR ndb (1) , 254 .MR ndb (3) , 255 .MR ndb (7) , 256 .MR sdb (1) , 257 .MR sdbr (3) , 258 .MR bio (3) , 259 .MR str (3) , 260 .MR vec (3) 261 .SH DIAGNOSTICS 262 Functions call 263 .I sysfatal 264 if file operations fail. 265 .SH BUGS 266 .I Sdb_flush 267 only prints to standard output, so you cannot directly write to a database file. 268 But maybe that's good!