1 /*************************************************************************************************
2 * The abstract database API of Tokyo Cabinet
3 * Copyright (C) 2006-2012 FAL Labs
4 * This file is part of Tokyo Cabinet.
5 * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of
6 * the GNU Lesser General Public License as published by the Free Software Foundation; either
7 * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope
8 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10 * License for more details.
11 * You should have received a copy of the GNU Lesser General Public License along with Tokyo
12 * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13 * Boston, MA 02111-1307 USA.
14 *************************************************************************************************/
15
16
17 #include "tcutil.h"
18 #include "tchdb.h"
19 #include "tcbdb.h"
20 #include "tcfdb.h"
21 #include "tctdb.h"
22 #include "tcadb.h"
23 #include "myconf.h"
24
25 #define ADBDIRMODE 00755 // permission of created directories
26 #define ADBMULPREFIX "adbmul-" // prefix of multiple database files
27
28 typedef struct { // type of structure for multiple database
29 TCADB **adbs; // inner database objects
30 int num; // number of inner databases
31 int iter; // index of the iterator
32 char *path; // path of the base directory
33 } ADBMUL;
34
35 typedef struct { // type of structure for mapper to B+ tree database
36 TCADB *adb; // source database object
37 TCBDB *bdb; // destination database object
38 TCLIST *recs; // cached records
39 int64_t rsiz; // total size of cached records
40 int64_t csiz; // capacity of cached records
41 ADBMAPPROC proc; // mapping function
42 void *op; // opaque object for the mapping function
43 } ADBMAPBDB;
44
45
46 /* private function prototypes */
47 static ADBMUL *tcadbmulnew(int num);
48 static void tcadbmuldel(ADBMUL *mul);
49 static bool tcadbmulopen(ADBMUL *mul, const char *name);
50 static bool tcadbmulclose(ADBMUL *mul);
51 static bool tcadbmulput(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
52 static bool tcadbmulputkeep(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
53 static bool tcadbmulputcat(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
54 static bool tcadbmulout(ADBMUL *mul, const void *kbuf, int ksiz);
55 static void *tcadbmulget(ADBMUL *mul, const void *kbuf, int ksiz, int *sp);
56 static int tcadbmulvsiz(ADBMUL *mul, const void *kbuf, int ksiz);
57 static bool tcadbmuliterinit(ADBMUL *mul);
58 static void *tcadbmuliternext(ADBMUL *mul, int *sp);
59 static TCLIST *tcadbmulfwmkeys(ADBMUL *mul, const void *pbuf, int psiz, int max);
60 static int tcadbmuladdint(ADBMUL *mul, const void *kbuf, int ksiz, int num);
61 static double tcadbmuladddouble(ADBMUL *mul, const void *kbuf, int ksiz, double num);
62 static bool tcadbmulsync(ADBMUL *mul);
63 static bool tcadbmuloptimize(ADBMUL *mul, const char *params);
64 static bool tcadbmulvanish(ADBMUL *mul);
65 static bool tcadbmulcopy(ADBMUL *mul, const char *path);
66 static bool tcadbmultranbegin(ADBMUL *mul);
67 static bool tcadbmultrancommit(ADBMUL *mul);
68 static bool tcadbmultranabort(ADBMUL *mul);
69 static const char *tcadbmulpath(ADBMUL *mul);
70 static uint64_t tcadbmulrnum(ADBMUL *mul);
71 static uint64_t tcadbmulsize(ADBMUL *mul);
72 static TCLIST *tcadbmulmisc(ADBMUL *mul, const char *name, const TCLIST *args);
73 static bool tcadbmulputproc(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz,
74 TCPDPROC proc, void *op);
75 static bool tcadbmulforeach(ADBMUL *mul, TCITER iter, void *op);
76 static int tcadbmulidx(ADBMUL *mul, const void *kbuf, int ksiz);
77 static bool tcadbmapbdbiter(const void *kbuf, int ksiz, const void *vbuf, int vsiz, void *op);
78 static bool tcadbmapbdbdump(ADBMAPBDB *map);
79 static int tcadbmapreccmplexical(const TCLISTDATUM *a, const TCLISTDATUM *b);
80 static int tcadbmapreccmpdecimal(const TCLISTDATUM *a, const TCLISTDATUM *b);
81 static int tcadbmapreccmpint32(const TCLISTDATUM *a, const TCLISTDATUM *b);
82 static int tcadbmapreccmpint64(const TCLISTDATUM *a, const TCLISTDATUM *b);
83 static int tcadbtdbqrygetout(const void *pkbuf, int pksiz, TCMAP *cols, void *op);
84
85
86
87 /*************************************************************************************************
88 * API
89 *************************************************************************************************/
90
91
92 /* Create an abstract database object. */
tcadbnew(void)93 TCADB *tcadbnew(void){
94 TCADB *adb;
95 TCMALLOC(adb, sizeof(*adb));
96 adb->omode = ADBOVOID;
97 adb->mdb = NULL;
98 adb->ndb = NULL;
99 adb->hdb = NULL;
100 adb->bdb = NULL;
101 adb->fdb = NULL;
102 adb->tdb = NULL;
103 adb->capnum = -1;
104 adb->capsiz = -1;
105 adb->capcnt = 0;
106 adb->cur = NULL;
107 adb->skel = NULL;
108 return adb;
109 }
110
111
112 /* Delete an abstract database object. */
tcadbdel(TCADB * adb)113 void tcadbdel(TCADB *adb){
114 assert(adb);
115 if(adb->omode != ADBOVOID) tcadbclose(adb);
116 if(adb->skel){
117 ADBSKEL *skel = adb->skel;
118 if(skel->del) skel->del(skel->opq);
119 TCFREE(skel);
120 }
121 TCFREE(adb);
122 }
123
124
125 /* Open an abstract database. */
tcadbopen(TCADB * adb,const char * name)126 bool tcadbopen(TCADB *adb, const char *name){
127 assert(adb && name);
128 if(adb->omode != ADBOVOID) return false;
129 TCLIST *elems = tcstrsplit(name, "#");
130 char *path = tclistshift2(elems);
131 if(!path){
132 tclistdel(elems);
133 return false;
134 }
135 int dbgfd = -1;
136 int64_t bnum = -1;
137 int64_t capnum = -1;
138 int64_t capsiz = -1;
139 bool owmode = true;
140 bool ocmode = true;
141 bool otmode = false;
142 bool onlmode = false;
143 bool onbmode = false;
144 int8_t apow = -1;
145 int8_t fpow = -1;
146 bool tlmode = false;
147 bool tdmode = false;
148 bool tbmode = false;
149 bool ttmode = false;
150 int32_t rcnum = -1;
151 int64_t xmsiz = -1;
152 int32_t dfunit = -1;
153 int32_t lmemb = -1;
154 int32_t nmemb = -1;
155 int32_t lcnum = -1;
156 int32_t ncnum = -1;
157 int32_t width = -1;
158 int64_t limsiz = -1;
159 TCLIST *idxs = NULL;
160 int ln = TCLISTNUM(elems);
161 for(int i = 0; i < ln; i++){
162 const char *elem = TCLISTVALPTR(elems, i);
163 char *pv = strchr(elem, '=');
164 if(!pv) continue;
165 *(pv++) = '\0';
166 if(!tcstricmp(elem, "dbgfd")){
167 dbgfd = tcatoi(pv);
168 } else if(!tcstricmp(elem, "bnum")){
169 bnum = tcatoix(pv);
170 } else if(!tcstricmp(elem, "capnum")){
171 capnum = tcatoix(pv);
172 } else if(!tcstricmp(elem, "capsiz")){
173 capsiz = tcatoix(pv);
174 } else if(!tcstricmp(elem, "mode")){
175 owmode = strchr(pv, 'w') || strchr(pv, 'W');
176 ocmode = strchr(pv, 'c') || strchr(pv, 'C');
177 otmode = strchr(pv, 't') || strchr(pv, 'T');
178 onlmode = strchr(pv, 'e') || strchr(pv, 'E');
179 onbmode = strchr(pv, 'f') || strchr(pv, 'F');
180 } else if(!tcstricmp(elem, "apow")){
181 apow = tcatoix(pv);
182 } else if(!tcstricmp(elem, "fpow")){
183 fpow = tcatoix(pv);
184 } else if(!tcstricmp(elem, "opts")){
185 if(strchr(pv, 'l') || strchr(pv, 'L')) tlmode = true;
186 if(strchr(pv, 'd') || strchr(pv, 'D')) tdmode = true;
187 if(strchr(pv, 'b') || strchr(pv, 'B')) tbmode = true;
188 if(strchr(pv, 't') || strchr(pv, 'T')) ttmode = true;
189 } else if(!tcstricmp(elem, "rcnum")){
190 rcnum = tcatoix(pv);
191 } else if(!tcstricmp(elem, "xmsiz")){
192 xmsiz = tcatoix(pv);
193 } else if(!tcstricmp(elem, "dfunit")){
194 dfunit = tcatoix(pv);
195 } else if(!tcstricmp(elem, "lmemb")){
196 lmemb = tcatoix(pv);
197 } else if(!tcstricmp(elem, "nmemb")){
198 nmemb = tcatoix(pv);
199 } else if(!tcstricmp(elem, "lcnum")){
200 lcnum = tcatoix(pv);
201 } else if(!tcstricmp(elem, "ncnum")){
202 ncnum = tcatoix(pv);
203 } else if(!tcstricmp(elem, "width")){
204 width = tcatoix(pv);
205 } else if(!tcstricmp(elem, "limsiz")){
206 limsiz = tcatoix(pv);
207 } else if(!tcstricmp(elem, "idx")){
208 if(!idxs) idxs = tclistnew();
209 TCLISTPUSH(idxs, pv, strlen(pv));
210 }
211 }
212 tclistdel(elems);
213 adb->omode = ADBOVOID;
214 if(adb->skel){
215 ADBSKEL *skel = adb->skel;
216 if(!skel->open || !skel->open(skel->opq, name)){
217 if(idxs) tclistdel(idxs);
218 TCFREE(path);
219 return false;
220 }
221 adb->omode = ADBOSKEL;
222 } else if(!tcstricmp(path, "*")){
223 adb->mdb = bnum > 0 ? tcmdbnew2(bnum) : tcmdbnew();
224 adb->capnum = capnum;
225 adb->capsiz = capsiz;
226 adb->capcnt = 0;
227 adb->omode = ADBOMDB;
228 } else if(!tcstricmp(path, "+")){
229 adb->ndb = tcndbnew();
230 adb->capnum = capnum;
231 adb->capsiz = capsiz;
232 adb->capcnt = 0;
233 adb->omode = ADBONDB;
234 } else if(tcstribwm(path, ".tch") || tcstribwm(path, ".hdb")){
235 TCHDB *hdb = tchdbnew();
236 if(dbgfd >= 0) tchdbsetdbgfd(hdb, dbgfd);
237 tchdbsetmutex(hdb);
238 int opts = 0;
239 if(tlmode) opts |= HDBTLARGE;
240 if(tdmode) opts |= HDBTDEFLATE;
241 if(tbmode) opts |= HDBTBZIP;
242 if(ttmode) opts |= HDBTTCBS;
243 tchdbtune(hdb, bnum, apow, fpow, opts);
244 tchdbsetcache(hdb, rcnum);
245 if(xmsiz >= 0) tchdbsetxmsiz(hdb, xmsiz);
246 if(dfunit >= 0) tchdbsetdfunit(hdb, dfunit);
247 int omode = owmode ? HDBOWRITER : HDBOREADER;
248 if(ocmode) omode |= HDBOCREAT;
249 if(otmode) omode |= HDBOTRUNC;
250 if(onlmode) omode |= HDBONOLCK;
251 if(onbmode) omode |= HDBOLCKNB;
252 if(!tchdbopen(hdb, path, omode)){
253 tchdbdel(hdb);
254 if(idxs) tclistdel(idxs);
255 TCFREE(path);
256 return false;
257 }
258 adb->hdb = hdb;
259 adb->omode = ADBOHDB;
260 } else if(tcstribwm(path, ".tcb") || tcstribwm(path, ".bdb")){
261 TCBDB *bdb = tcbdbnew();
262 if(dbgfd >= 0) tcbdbsetdbgfd(bdb, dbgfd);
263 tcbdbsetmutex(bdb);
264 int opts = 0;
265 if(tlmode) opts |= BDBTLARGE;
266 if(tdmode) opts |= BDBTDEFLATE;
267 if(tbmode) opts |= BDBTBZIP;
268 if(ttmode) opts |= BDBTTCBS;
269 tcbdbtune(bdb, lmemb, nmemb, bnum, apow, fpow, opts);
270 tcbdbsetcache(bdb, lcnum, ncnum);
271 if(xmsiz >= 0) tcbdbsetxmsiz(bdb, xmsiz);
272 if(dfunit >= 0) tcbdbsetdfunit(bdb, dfunit);
273 if(capnum > 0) tcbdbsetcapnum(bdb, capnum);
274 int omode = owmode ? BDBOWRITER : BDBOREADER;
275 if(ocmode) omode |= BDBOCREAT;
276 if(otmode) omode |= BDBOTRUNC;
277 if(onlmode) omode |= BDBONOLCK;
278 if(onbmode) omode |= BDBOLCKNB;
279 if(!tcbdbopen(bdb, path, omode)){
280 tcbdbdel(bdb);
281 if(idxs) tclistdel(idxs);
282 TCFREE(path);
283 return false;
284 }
285 adb->bdb = bdb;
286 adb->cur = tcbdbcurnew(bdb);
287 adb->omode = ADBOBDB;
288 } else if(tcstribwm(path, ".tcf") || tcstribwm(path, ".fdb")){
289 TCFDB *fdb = tcfdbnew();
290 if(dbgfd >= 0) tcfdbsetdbgfd(fdb, dbgfd);
291 tcfdbsetmutex(fdb);
292 tcfdbtune(fdb, width, limsiz);
293 int omode = owmode ? FDBOWRITER : FDBOREADER;
294 if(ocmode) omode |= FDBOCREAT;
295 if(otmode) omode |= FDBOTRUNC;
296 if(onlmode) omode |= FDBONOLCK;
297 if(onbmode) omode |= FDBOLCKNB;
298 if(!tcfdbopen(fdb, path, omode)){
299 tcfdbdel(fdb);
300 if(idxs) tclistdel(idxs);
301 TCFREE(path);
302 return false;
303 }
304 adb->fdb = fdb;
305 adb->omode = ADBOFDB;
306 } else if(tcstribwm(path, ".tct") || tcstribwm(path, ".tdb")){
307 TCTDB *tdb = tctdbnew();
308 if(dbgfd >= 0) tctdbsetdbgfd(tdb, dbgfd);
309 tctdbsetmutex(tdb);
310 int opts = 0;
311 if(tlmode) opts |= TDBTLARGE;
312 if(tdmode) opts |= TDBTDEFLATE;
313 if(tbmode) opts |= TDBTBZIP;
314 if(ttmode) opts |= TDBTTCBS;
315 tctdbtune(tdb, bnum, apow, fpow, opts);
316 tctdbsetcache(tdb, rcnum, lcnum, ncnum);
317 if(xmsiz >= 0) tctdbsetxmsiz(tdb, xmsiz);
318 if(dfunit >= 0) tctdbsetdfunit(tdb, dfunit);
319 int omode = owmode ? TDBOWRITER : TDBOREADER;
320 if(ocmode) omode |= TDBOCREAT;
321 if(otmode) omode |= TDBOTRUNC;
322 if(onlmode) omode |= TDBONOLCK;
323 if(onbmode) omode |= TDBOLCKNB;
324 if(!tctdbopen(tdb, path, omode)){
325 tctdbdel(tdb);
326 if(idxs) tclistdel(idxs);
327 TCFREE(path);
328 return false;
329 }
330 if(idxs){
331 int xnum = TCLISTNUM(idxs);
332 for(int i = 0; i < xnum; i++){
333 const char *expr = TCLISTVALPTR(idxs, i);
334 int type = TDBITLEXICAL;
335 char *pv = strchr(expr, ':');
336 if(pv){
337 *(pv++) = '\0';
338 type = tctdbstrtoindextype(pv);
339 }
340 if(type >= 0) tctdbsetindex(tdb, expr, type | TDBITKEEP);
341 }
342 }
343 adb->tdb = tdb;
344 adb->omode = ADBOTDB;
345 }
346 if(idxs) tclistdel(idxs);
347 TCFREE(path);
348 if(adb->omode == ADBOVOID) return false;
349 return true;
350 }
351
352
353 /* Close an abstract database object. */
tcadbclose(TCADB * adb)354 bool tcadbclose(TCADB *adb){
355 assert(adb);
356 int err = false;
357 ADBSKEL *skel;
358 switch(adb->omode){
359 case ADBOMDB:
360 tcmdbdel(adb->mdb);
361 adb->mdb = NULL;
362 break;
363 case ADBONDB:
364 tcndbdel(adb->ndb);
365 adb->ndb = NULL;
366 break;
367 case ADBOHDB:
368 if(!tchdbclose(adb->hdb)) err = true;
369 tchdbdel(adb->hdb);
370 adb->hdb = NULL;
371 break;
372 case ADBOBDB:
373 tcbdbcurdel(adb->cur);
374 if(!tcbdbclose(adb->bdb)) err = true;
375 tcbdbdel(adb->bdb);
376 adb->bdb = NULL;
377 break;
378 case ADBOFDB:
379 if(!tcfdbclose(adb->fdb)) err = true;
380 tcfdbdel(adb->fdb);
381 adb->fdb = NULL;
382 break;
383 case ADBOTDB:
384 if(!tctdbclose(adb->tdb)) err = true;
385 tctdbdel(adb->tdb);
386 adb->tdb = NULL;
387 break;
388 case ADBOSKEL:
389 skel = adb->skel;
390 if(skel->close){
391 if(!skel->close(skel->opq)) err = true;
392 } else {
393 err = true;
394 }
395 break;
396 default:
397 err = true;
398 break;
399 }
400 adb->omode = ADBOVOID;
401 return !err;
402 }
403
404
405 /* Store a record into an abstract database object. */
tcadbput(TCADB * adb,const void * kbuf,int ksiz,const void * vbuf,int vsiz)406 bool tcadbput(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
407 assert(adb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
408 bool err = false;
409 char numbuf[TCNUMBUFSIZ];
410 ADBSKEL *skel;
411 switch(adb->omode){
412 case ADBOMDB:
413 if(adb->capnum > 0 || adb->capsiz > 0){
414 tcmdbput3(adb->mdb, kbuf, ksiz, vbuf, vsiz);
415 adb->capcnt++;
416 if((adb->capcnt & 0xff) == 0){
417 if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
418 tcmdbcutfront(adb->mdb, 0x100);
419 if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
420 tcmdbcutfront(adb->mdb, 0x200);
421 }
422 } else {
423 tcmdbput(adb->mdb, kbuf, ksiz, vbuf, vsiz);
424 }
425 break;
426 case ADBONDB:
427 tcndbput(adb->ndb, kbuf, ksiz, vbuf, vsiz);
428 if(adb->capnum > 0 || adb->capsiz > 0){
429 adb->capcnt++;
430 if((adb->capcnt & 0xff) == 0){
431 if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum + 0x100)
432 tcndbcutfringe(adb->ndb, 0x100);
433 if(adb->capsiz > 0 && tcndbmsiz(adb->ndb) > adb->capsiz)
434 tcndbcutfringe(adb->ndb, 0x200);
435 }
436 }
437 break;
438 case ADBOHDB:
439 if(!tchdbput(adb->hdb, kbuf, ksiz, vbuf, vsiz)) err = true;
440 break;
441 case ADBOBDB:
442 if(!tcbdbput(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
443 break;
444 case ADBOFDB:
445 if(!tcfdbput2(adb->fdb, kbuf, ksiz, vbuf, vsiz)) err = true;
446 break;
447 case ADBOTDB:
448 if(ksiz < 1){
449 ksiz = sprintf(numbuf, "%lld", (long long)tctdbgenuid(adb->tdb));
450 kbuf = numbuf;
451 }
452 if(!tctdbput2(adb->tdb, kbuf, ksiz, vbuf, vsiz)) err = true;
453 break;
454 case ADBOSKEL:
455 skel = adb->skel;
456 if(skel->put){
457 if(!skel->put(skel->opq, kbuf, ksiz, vbuf, vsiz)) err = true;
458 } else {
459 err = true;
460 }
461 break;
462 default:
463 err = true;
464 break;
465 }
466 return !err;
467 }
468
469
470 /* Store a string record into an abstract object. */
tcadbput2(TCADB * adb,const char * kstr,const char * vstr)471 bool tcadbput2(TCADB *adb, const char *kstr, const char *vstr){
472 assert(adb && kstr && vstr);
473 return tcadbput(adb, kstr, strlen(kstr), vstr, strlen(vstr));
474 }
475
476
477 /* Store a new record into an abstract database object. */
tcadbputkeep(TCADB * adb,const void * kbuf,int ksiz,const void * vbuf,int vsiz)478 bool tcadbputkeep(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
479 assert(adb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
480 bool err = false;
481 char numbuf[TCNUMBUFSIZ];
482 ADBSKEL *skel;
483 switch(adb->omode){
484 case ADBOMDB:
485 if(tcmdbputkeep(adb->mdb, kbuf, ksiz, vbuf, vsiz)){
486 if(adb->capnum > 0 || adb->capsiz > 0){
487 adb->capcnt++;
488 if((adb->capcnt & 0xff) == 0){
489 if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
490 tcmdbcutfront(adb->mdb, 0x100);
491 if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
492 tcmdbcutfront(adb->mdb, 0x200);
493 }
494 }
495 } else {
496 err = true;
497 }
498 break;
499 case ADBONDB:
500 if(tcndbputkeep(adb->ndb, kbuf, ksiz, vbuf, vsiz)){
501 if(adb->capnum > 0 || adb->capsiz > 0){
502 adb->capcnt++;
503 if((adb->capcnt & 0xff) == 0){
504 if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum + 0x100)
505 tcndbcutfringe(adb->ndb, 0x100);
506 if(adb->capsiz > 0 && tcndbmsiz(adb->ndb) > adb->capsiz)
507 tcndbcutfringe(adb->ndb, 0x200);
508 }
509 }
510 } else {
511 err = true;
512 }
513 break;
514 case ADBOHDB:
515 if(!tchdbputkeep(adb->hdb, kbuf, ksiz, vbuf, vsiz)) err = true;
516 break;
517 case ADBOBDB:
518 if(!tcbdbputkeep(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
519 break;
520 case ADBOFDB:
521 if(!tcfdbputkeep2(adb->fdb, kbuf, ksiz, vbuf, vsiz)) err = true;
522 break;
523 case ADBOTDB:
524 if(ksiz < 1){
525 ksiz = sprintf(numbuf, "%lld", (long long)tctdbgenuid(adb->tdb));
526 kbuf = numbuf;
527 }
528 if(!tctdbputkeep2(adb->tdb, kbuf, ksiz, vbuf, vsiz)) err = true;
529 break;
530 case ADBOSKEL:
531 skel = adb->skel;
532 if(skel->putkeep){
533 if(!skel->putkeep(skel->opq, kbuf, ksiz, vbuf, vsiz)) err = true;
534 } else {
535 err = true;
536 }
537 break;
538 default:
539 err = true;
540 break;
541 }
542 return !err;
543 }
544
545
546 /* Store a new string record into an abstract database object. */
tcadbputkeep2(TCADB * adb,const char * kstr,const char * vstr)547 bool tcadbputkeep2(TCADB *adb, const char *kstr, const char *vstr){
548 assert(adb && kstr && vstr);
549 return tcadbputkeep(adb, kstr, strlen(kstr), vstr, strlen(vstr));
550 }
551
552
553 /* Concatenate a value at the end of the existing record in an abstract database object. */
tcadbputcat(TCADB * adb,const void * kbuf,int ksiz,const void * vbuf,int vsiz)554 bool tcadbputcat(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
555 assert(adb && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
556 bool err = false;
557 char numbuf[TCNUMBUFSIZ];
558 ADBSKEL *skel;
559 switch(adb->omode){
560 case ADBOMDB:
561 if(adb->capnum > 0 || adb->capsiz > 0){
562 tcmdbputcat3(adb->mdb, kbuf, ksiz, vbuf, vsiz);
563 adb->capcnt++;
564 if((adb->capcnt & 0xff) == 0){
565 if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
566 tcmdbcutfront(adb->mdb, 0x100);
567 if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
568 tcmdbcutfront(adb->mdb, 0x200);
569 }
570 } else {
571 tcmdbputcat(adb->mdb, kbuf, ksiz, vbuf, vsiz);
572 }
573 break;
574 case ADBONDB:
575 tcndbputcat(adb->ndb, kbuf, ksiz, vbuf, vsiz);
576 if(adb->capnum > 0 || adb->capsiz > 0){
577 adb->capcnt++;
578 if((adb->capcnt & 0xff) == 0){
579 if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum + 0x100)
580 tcndbcutfringe(adb->ndb, 0x100);
581 if(adb->capsiz > 0 && tcndbmsiz(adb->ndb) > adb->capsiz)
582 tcndbcutfringe(adb->ndb, 0x200);
583 }
584 }
585 break;
586 case ADBOHDB:
587 if(!tchdbputcat(adb->hdb, kbuf, ksiz, vbuf, vsiz)) err = true;
588 break;
589 case ADBOBDB:
590 if(!tcbdbputcat(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
591 break;
592 case ADBOFDB:
593 if(!tcfdbputcat2(adb->fdb, kbuf, ksiz, vbuf, vsiz)) err = true;
594 break;
595 case ADBOTDB:
596 if(ksiz < 1){
597 ksiz = sprintf(numbuf, "%lld", (long long)tctdbgenuid(adb->tdb));
598 kbuf = numbuf;
599 }
600 if(!tctdbputcat2(adb->tdb, kbuf, ksiz, vbuf, vsiz)) err = true;
601 break;
602 case ADBOSKEL:
603 skel = adb->skel;
604 if(skel->putcat){
605 if(!skel->putcat(skel->opq, kbuf, ksiz, vbuf, vsiz)) err = true;
606 } else {
607 err = true;
608 }
609 break;
610 default:
611 err = true;
612 break;
613 }
614 return !err;
615 }
616
617
618 /* Concatenate a string value at the end of the existing record in an abstract database object. */
tcadbputcat2(TCADB * adb,const char * kstr,const char * vstr)619 bool tcadbputcat2(TCADB *adb, const char *kstr, const char *vstr){
620 assert(adb && kstr && vstr);
621 return tcadbputcat(adb, kstr, strlen(kstr), vstr, strlen(vstr));
622 }
623
624
625 /* Remove a record of an abstract database object. */
tcadbout(TCADB * adb,const void * kbuf,int ksiz)626 bool tcadbout(TCADB *adb, const void *kbuf, int ksiz){
627 assert(adb && kbuf && ksiz >= 0);
628 bool err = false;
629 ADBSKEL *skel;
630 switch(adb->omode){
631 case ADBOMDB:
632 if(!tcmdbout(adb->mdb, kbuf, ksiz)) err = true;
633 break;
634 case ADBONDB:
635 if(!tcndbout(adb->ndb, kbuf, ksiz)) err = true;
636 break;
637 case ADBOHDB:
638 if(!tchdbout(adb->hdb, kbuf, ksiz)) err = true;
639 break;
640 case ADBOBDB:
641 if(!tcbdbout(adb->bdb, kbuf, ksiz)) err = true;
642 break;
643 case ADBOFDB:
644 if(!tcfdbout2(adb->fdb, kbuf, ksiz)) err = true;
645 break;
646 case ADBOTDB:
647 if(!tctdbout(adb->tdb, kbuf, ksiz)) err = true;
648 break;
649 case ADBOSKEL:
650 skel = adb->skel;
651 if(skel->out){
652 if(!skel->out(skel->opq, kbuf, ksiz)) err = true;
653 } else {
654 err = true;
655 }
656 break;
657 default:
658 err = true;
659 break;
660 }
661 return !err;
662 }
663
664
665 /* Remove a string record of an abstract database object. */
tcadbout2(TCADB * adb,const char * kstr)666 bool tcadbout2(TCADB *adb, const char *kstr){
667 assert(adb && kstr);
668 return tcadbout(adb, kstr, strlen(kstr));
669 }
670
671
672 /* Retrieve a record in an abstract database object. */
tcadbget(TCADB * adb,const void * kbuf,int ksiz,int * sp)673 void *tcadbget(TCADB *adb, const void *kbuf, int ksiz, int *sp){
674 assert(adb && kbuf && ksiz >= 0 && sp);
675 char *rv;
676 ADBSKEL *skel;
677 switch(adb->omode){
678 case ADBOMDB:
679 rv = tcmdbget(adb->mdb, kbuf, ksiz, sp);
680 break;
681 case ADBONDB:
682 rv = tcndbget(adb->ndb, kbuf, ksiz, sp);
683 break;
684 case ADBOHDB:
685 rv = tchdbget(adb->hdb, kbuf, ksiz, sp);
686 break;
687 case ADBOBDB:
688 rv = tcbdbget(adb->bdb, kbuf, ksiz, sp);
689 break;
690 case ADBOFDB:
691 rv = tcfdbget2(adb->fdb, kbuf, ksiz, sp);
692 break;
693 case ADBOTDB:
694 rv = tctdbget2(adb->tdb, kbuf, ksiz, sp);
695 break;
696 case ADBOSKEL:
697 skel = adb->skel;
698 if(skel->get){
699 rv = skel->get(skel->opq, kbuf, ksiz, sp);
700 } else {
701 rv = NULL;
702 }
703 break;
704 default:
705 rv = NULL;
706 break;
707 }
708 return rv;
709 }
710
711
712 /* Retrieve a string record in an abstract database object. */
tcadbget2(TCADB * adb,const char * kstr)713 char *tcadbget2(TCADB *adb, const char *kstr){
714 assert(adb && kstr);
715 int vsiz;
716 return tcadbget(adb, kstr, strlen(kstr), &vsiz);
717 }
718
719
720 /* Get the size of the value of a record in an abstract database object. */
tcadbvsiz(TCADB * adb,const void * kbuf,int ksiz)721 int tcadbvsiz(TCADB *adb, const void *kbuf, int ksiz){
722 assert(adb && kbuf && ksiz >= 0);
723 int rv;
724 ADBSKEL *skel;
725 switch(adb->omode){
726 case ADBOMDB:
727 rv = tcmdbvsiz(adb->mdb, kbuf, ksiz);
728 break;
729 case ADBONDB:
730 rv = tcndbvsiz(adb->ndb, kbuf, ksiz);
731 break;
732 case ADBOHDB:
733 rv = tchdbvsiz(adb->hdb, kbuf, ksiz);
734 break;
735 case ADBOBDB:
736 rv = tcbdbvsiz(adb->bdb, kbuf, ksiz);
737 break;
738 case ADBOFDB:
739 rv = tcfdbvsiz2(adb->fdb, kbuf, ksiz);
740 break;
741 case ADBOTDB:
742 rv = tctdbvsiz(adb->tdb, kbuf, ksiz);
743 break;
744 case ADBOSKEL:
745 skel = adb->skel;
746 if(skel->vsiz){
747 rv = skel->vsiz(skel->opq, kbuf, ksiz);
748 } else {
749 rv = -1;
750 }
751 break;
752 default:
753 rv = -1;
754 break;
755 }
756 return rv;
757 }
758
759
760 /* Get the size of the value of a string record in an abstract database object. */
tcadbvsiz2(TCADB * adb,const char * kstr)761 int tcadbvsiz2(TCADB *adb, const char *kstr){
762 assert(adb && kstr);
763 return tcadbvsiz(adb, kstr, strlen(kstr));
764 }
765
766
767 /* Initialize the iterator of an abstract database object. */
tcadbiterinit(TCADB * adb)768 bool tcadbiterinit(TCADB *adb){
769 assert(adb);
770 bool err = false;
771 ADBSKEL *skel;
772 switch(adb->omode){
773 case ADBOMDB:
774 tcmdbiterinit(adb->mdb);
775 break;
776 case ADBONDB:
777 tcndbiterinit(adb->ndb);
778 break;
779 case ADBOHDB:
780 if(!tchdbiterinit(adb->hdb)) err = true;
781 break;
782 case ADBOBDB:
783 if(!tcbdbcurfirst(adb->cur)){
784 int ecode = tcbdbecode(adb->bdb);
785 if(ecode != TCESUCCESS && ecode != TCEINVALID && ecode != TCEKEEP && ecode != TCENOREC)
786 err = true;
787 }
788 break;
789 case ADBOFDB:
790 if(!tcfdbiterinit(adb->fdb)) err = true;
791 break;
792 case ADBOTDB:
793 if(!tctdbiterinit(adb->tdb)) err = true;
794 break;
795 case ADBOSKEL:
796 skel = adb->skel;
797 if(skel->iterinit){
798 if(!skel->iterinit(skel->opq)) err = true;
799 } else {
800 err = true;
801 }
802 break;
803 default:
804 err = true;
805 break;
806 }
807 return !err;
808 }
809
810
811 /* Get the next key of the iterator of an abstract database object. */
tcadbiternext(TCADB * adb,int * sp)812 void *tcadbiternext(TCADB *adb, int *sp){
813 assert(adb && sp);
814 char *rv;
815 ADBSKEL *skel;
816 switch(adb->omode){
817 case ADBOMDB:
818 rv = tcmdbiternext(adb->mdb, sp);
819 break;
820 case ADBONDB:
821 rv = tcndbiternext(adb->ndb, sp);
822 break;
823 case ADBOHDB:
824 rv = tchdbiternext(adb->hdb, sp);
825 break;
826 case ADBOBDB:
827 rv = tcbdbcurkey(adb->cur, sp);
828 tcbdbcurnext(adb->cur);
829 break;
830 case ADBOFDB:
831 rv = tcfdbiternext2(adb->fdb, sp);
832 break;
833 case ADBOTDB:
834 rv = tctdbiternext(adb->tdb, sp);
835 break;
836 case ADBOSKEL:
837 skel = adb->skel;
838 if(skel->iternext){
839 rv = skel->iternext(skel->opq, sp);
840 } else {
841 rv = NULL;
842 }
843 break;
844 default:
845 rv = NULL;
846 break;
847 }
848 return rv;
849 }
850
851
852 /* Get the next key string of the iterator of an abstract database object. */
tcadbiternext2(TCADB * adb)853 char *tcadbiternext2(TCADB *adb){
854 assert(adb);
855 int vsiz;
856 return tcadbiternext(adb, &vsiz);
857 }
858
859
860 /* Get forward matching keys in an abstract database object. */
tcadbfwmkeys(TCADB * adb,const void * pbuf,int psiz,int max)861 TCLIST *tcadbfwmkeys(TCADB *adb, const void *pbuf, int psiz, int max){
862 assert(adb && pbuf && psiz >= 0);
863 TCLIST *rv;
864 ADBSKEL *skel;
865 switch(adb->omode){
866 case ADBOMDB:
867 rv = tcmdbfwmkeys(adb->mdb, pbuf, psiz, max);
868 break;
869 case ADBONDB:
870 rv = tcndbfwmkeys(adb->ndb, pbuf, psiz, max);
871 break;
872 case ADBOHDB:
873 rv = tchdbfwmkeys(adb->hdb, pbuf, psiz, max);
874 break;
875 case ADBOBDB:
876 rv = tcbdbfwmkeys(adb->bdb, pbuf, psiz, max);
877 break;
878 case ADBOFDB:
879 rv = tcfdbrange4(adb->fdb, pbuf, psiz, max);
880 break;
881 case ADBOTDB:
882 rv = tctdbfwmkeys(adb->tdb, pbuf, psiz, max);
883 break;
884 case ADBOSKEL:
885 skel = adb->skel;
886 if(skel->fwmkeys){
887 rv = skel->fwmkeys(skel->opq, pbuf, psiz, max);
888 } else {
889 rv = NULL;
890 }
891 break;
892 default:
893 rv = tclistnew();
894 break;
895 }
896 return rv;
897 }
898
899
900 /* Get forward matching string keys in an abstract database object. */
tcadbfwmkeys2(TCADB * adb,const char * pstr,int max)901 TCLIST *tcadbfwmkeys2(TCADB *adb, const char *pstr, int max){
902 assert(adb && pstr);
903 return tcadbfwmkeys(adb, pstr, strlen(pstr), max);
904 }
905
906
907 /* Add an integer to a record in an abstract database object. */
tcadbaddint(TCADB * adb,const void * kbuf,int ksiz,int num)908 int tcadbaddint(TCADB *adb, const void *kbuf, int ksiz, int num){
909 assert(adb && kbuf && ksiz >= 0);
910 int rv;
911 char numbuf[TCNUMBUFSIZ];
912 ADBSKEL *skel;
913 switch(adb->omode){
914 case ADBOMDB:
915 rv = tcmdbaddint(adb->mdb, kbuf, ksiz, num);
916 if(adb->capnum > 0 || adb->capsiz > 0){
917 adb->capcnt++;
918 if((adb->capcnt & 0xff) == 0){
919 if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
920 tcmdbcutfront(adb->mdb, 0x100);
921 if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
922 tcmdbcutfront(adb->mdb, 0x200);
923 }
924 }
925 break;
926 case ADBONDB:
927 rv = tcndbaddint(adb->ndb, kbuf, ksiz, num);
928 if(adb->capnum > 0 || adb->capsiz > 0){
929 adb->capcnt++;
930 if((adb->capcnt & 0xff) == 0){
931 if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum + 0x100)
932 tcndbcutfringe(adb->ndb, 0x100);
933 if(adb->capsiz > 0 && tcndbmsiz(adb->ndb) > adb->capsiz)
934 tcndbcutfringe(adb->ndb, 0x200);
935 }
936 }
937 break;
938 case ADBOHDB:
939 rv = tchdbaddint(adb->hdb, kbuf, ksiz, num);
940 break;
941 case ADBOBDB:
942 rv = tcbdbaddint(adb->bdb, kbuf, ksiz, num);
943 break;
944 case ADBOFDB:
945 rv = tcfdbaddint(adb->fdb, tcfdbkeytoid(kbuf, ksiz), num);
946 break;
947 case ADBOTDB:
948 if(ksiz < 1){
949 ksiz = sprintf(numbuf, "%lld", (long long)tctdbgenuid(adb->tdb));
950 kbuf = numbuf;
951 }
952 rv = tctdbaddint(adb->tdb, kbuf, ksiz, num);
953 break;
954 case ADBOSKEL:
955 skel = adb->skel;
956 if(skel->addint){
957 rv = skel->addint(skel->opq, kbuf, ksiz, num);
958 } else {
959 rv = INT_MIN;
960 }
961 break;
962 default:
963 rv = INT_MIN;
964 break;
965 }
966 return rv;
967 }
968
969
970 /* Add a real number to a record in an abstract database object. */
tcadbadddouble(TCADB * adb,const void * kbuf,int ksiz,double num)971 double tcadbadddouble(TCADB *adb, const void *kbuf, int ksiz, double num){
972 assert(adb && kbuf && ksiz >= 0);
973 double rv;
974 char numbuf[TCNUMBUFSIZ];
975 ADBSKEL *skel;
976 switch(adb->omode){
977 case ADBOMDB:
978 rv = tcmdbadddouble(adb->mdb, kbuf, ksiz, num);
979 if(adb->capnum > 0 || adb->capsiz > 0){
980 adb->capcnt++;
981 if((adb->capcnt & 0xff) == 0){
982 if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
983 tcmdbcutfront(adb->mdb, 0x100);
984 if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
985 tcmdbcutfront(adb->mdb, 0x200);
986 }
987 }
988 break;
989 case ADBONDB:
990 rv = tcndbadddouble(adb->ndb, kbuf, ksiz, num);
991 if(adb->capnum > 0 || adb->capsiz > 0){
992 adb->capcnt++;
993 if((adb->capcnt & 0xff) == 0){
994 if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum + 0x100)
995 tcndbcutfringe(adb->ndb, 0x100);
996 if(adb->capsiz > 0 && tcndbmsiz(adb->ndb) > adb->capsiz)
997 tcndbcutfringe(adb->ndb, 0x200);
998 }
999 }
1000 break;
1001 case ADBOHDB:
1002 rv = tchdbadddouble(adb->hdb, kbuf, ksiz, num);
1003 break;
1004 case ADBOBDB:
1005 rv = tcbdbadddouble(adb->bdb, kbuf, ksiz, num);
1006 break;
1007 case ADBOFDB:
1008 rv = tcfdbadddouble(adb->fdb, tcfdbkeytoid(kbuf, ksiz), num);
1009 break;
1010 case ADBOTDB:
1011 if(ksiz < 1){
1012 ksiz = sprintf(numbuf, "%lld", (long long)tctdbgenuid(adb->tdb));
1013 kbuf = numbuf;
1014 }
1015 rv = tctdbadddouble(adb->tdb, kbuf, ksiz, num);
1016 break;
1017 case ADBOSKEL:
1018 skel = adb->skel;
1019 if(skel->adddouble){
1020 rv = skel->adddouble(skel->opq, kbuf, ksiz, num);
1021 } else {
1022 rv = nan("");
1023 }
1024 break;
1025 default:
1026 rv = nan("");
1027 break;
1028 }
1029 return rv;
1030 }
1031
1032
1033 /* Synchronize updated contents of an abstract database object with the file and the device. */
tcadbsync(TCADB * adb)1034 bool tcadbsync(TCADB *adb){
1035 assert(adb);
1036 bool err = false;
1037 ADBSKEL *skel;
1038 switch(adb->omode){
1039 case ADBOMDB:
1040 if(adb->capnum > 0){
1041 while(tcmdbrnum(adb->mdb) > adb->capnum){
1042 tcmdbcutfront(adb->mdb, 1);
1043 }
1044 }
1045 if(adb->capsiz > 0){
1046 while(tcmdbmsiz(adb->mdb) > adb->capsiz && tcmdbrnum(adb->mdb) > 0){
1047 tcmdbcutfront(adb->mdb, 1);
1048 }
1049 }
1050 adb->capcnt = 0;
1051 break;
1052 case ADBONDB:
1053 if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum)
1054 tcndbcutfringe(adb->ndb, tcndbrnum(adb->ndb) - adb->capnum);
1055 if(adb->capsiz > 0){
1056 while(tcndbmsiz(adb->ndb) > adb->capsiz && tcndbrnum(adb->ndb) > 0){
1057 tcndbcutfringe(adb->ndb, 0x100);
1058 }
1059 }
1060 adb->capcnt = 0;
1061 break;
1062 case ADBOHDB:
1063 if(!tchdbsync(adb->hdb)) err = true;
1064 break;
1065 case ADBOBDB:
1066 if(!tcbdbsync(adb->bdb)) err = true;
1067 break;
1068 case ADBOFDB:
1069 if(!tcfdbsync(adb->fdb)) err = true;
1070 break;
1071 case ADBOTDB:
1072 if(!tctdbsync(adb->tdb)) err = true;
1073 break;
1074 case ADBOSKEL:
1075 skel = adb->skel;
1076 if(skel->sync){
1077 if(!skel->sync(skel->opq)) err = true;
1078 } else {
1079 err = true;
1080 }
1081 break;
1082 default:
1083 err = true;
1084 break;
1085 }
1086 return !err;
1087 }
1088
1089
1090 /* Optimize the storage of an abstract database object. */
tcadboptimize(TCADB * adb,const char * params)1091 bool tcadboptimize(TCADB *adb, const char *params){
1092 assert(adb);
1093 TCLIST *elems = params ? tcstrsplit(params, "#") : tclistnew();
1094 int64_t bnum = -1;
1095 int64_t capnum = -1;
1096 int64_t capsiz = -1;
1097 int8_t apow = -1;
1098 int8_t fpow = -1;
1099 bool tdefault = true;
1100 bool tlmode = false;
1101 bool tdmode = false;
1102 bool tbmode = false;
1103 bool ttmode = false;
1104 int32_t lmemb = -1;
1105 int32_t nmemb = -1;
1106 int32_t width = -1;
1107 int64_t limsiz = -1;
1108 int ln = TCLISTNUM(elems);
1109 for(int i = 0; i < ln; i++){
1110 const char *elem = TCLISTVALPTR(elems, i);
1111 char *pv = strchr(elem, '=');
1112 if(!pv) continue;
1113 *(pv++) = '\0';
1114 if(!tcstricmp(elem, "bnum")){
1115 bnum = tcatoix(pv);
1116 } else if(!tcstricmp(elem, "capnum")){
1117 capnum = tcatoix(pv);
1118 } else if(!tcstricmp(elem, "capsiz")){
1119 capsiz = tcatoix(pv);
1120 } else if(!tcstricmp(elem, "apow")){
1121 apow = tcatoix(pv);
1122 } else if(!tcstricmp(elem, "fpow")){
1123 fpow = tcatoix(pv);
1124 } else if(!tcstricmp(elem, "opts")){
1125 tdefault = false;
1126 if(strchr(pv, 'l') || strchr(pv, 'L')) tlmode = true;
1127 if(strchr(pv, 'd') || strchr(pv, 'D')) tdmode = true;
1128 if(strchr(pv, 'b') || strchr(pv, 'B')) tbmode = true;
1129 if(strchr(pv, 't') || strchr(pv, 'T')) ttmode = true;
1130 } else if(!tcstricmp(elem, "lmemb")){
1131 lmemb = tcatoix(pv);
1132 } else if(!tcstricmp(elem, "nmemb")){
1133 nmemb = tcatoix(pv);
1134 } else if(!tcstricmp(elem, "width")){
1135 width = tcatoix(pv);
1136 } else if(!tcstricmp(elem, "limsiz")){
1137 limsiz = tcatoix(pv);
1138 }
1139 }
1140 tclistdel(elems);
1141 bool err = false;
1142 int opts;
1143 ADBSKEL *skel;
1144 switch(adb->omode){
1145 case ADBOMDB:
1146 adb->capnum = capnum;
1147 adb->capsiz = capsiz;
1148 tcadbsync(adb);
1149 break;
1150 case ADBONDB:
1151 adb->capnum = capnum;
1152 adb->capsiz = capsiz;
1153 tcadbsync(adb);
1154 break;
1155 case ADBOHDB:
1156 opts = 0;
1157 if(tdefault){
1158 opts = UINT8_MAX;
1159 } else {
1160 if(tlmode) opts |= HDBTLARGE;
1161 if(tdmode) opts |= HDBTDEFLATE;
1162 if(tbmode) opts |= HDBTBZIP;
1163 if(ttmode) opts |= HDBTTCBS;
1164 }
1165 if(!tchdboptimize(adb->hdb, bnum, apow, fpow, opts)) err = true;
1166 break;
1167 case ADBOBDB:
1168 opts = 0;
1169 if(tdefault){
1170 opts = UINT8_MAX;
1171 } else {
1172 if(tlmode) opts |= BDBTLARGE;
1173 if(tdmode) opts |= BDBTDEFLATE;
1174 if(tbmode) opts |= BDBTBZIP;
1175 if(ttmode) opts |= BDBTTCBS;
1176 }
1177 if(!tcbdboptimize(adb->bdb, lmemb, nmemb, bnum, apow, fpow, opts)) err = true;
1178 break;
1179 case ADBOFDB:
1180 if(!tcfdboptimize(adb->fdb, width, limsiz)) err = true;
1181 break;
1182 case ADBOTDB:
1183 opts = 0;
1184 if(tdefault){
1185 opts = UINT8_MAX;
1186 } else {
1187 if(tlmode) opts |= TDBTLARGE;
1188 if(tdmode) opts |= TDBTDEFLATE;
1189 if(tbmode) opts |= TDBTBZIP;
1190 if(ttmode) opts |= TDBTTCBS;
1191 }
1192 if(!tctdboptimize(adb->tdb, bnum, apow, fpow, opts)) err = true;
1193 break;
1194 case ADBOSKEL:
1195 skel = adb->skel;
1196 if(skel->optimize){
1197 if(!skel->optimize(skel->opq, params)) err = true;
1198 } else {
1199 err = true;
1200 }
1201 break;
1202 default:
1203 err = true;
1204 break;
1205 }
1206 return !err;
1207 }
1208
1209
1210 /* Remove all records of an abstract database object. */
tcadbvanish(TCADB * adb)1211 bool tcadbvanish(TCADB *adb){
1212 assert(adb);
1213 bool err = false;
1214 ADBSKEL *skel;
1215 switch(adb->omode){
1216 case ADBOMDB:
1217 tcmdbvanish(adb->mdb);
1218 break;
1219 case ADBONDB:
1220 tcndbvanish(adb->ndb);
1221 break;
1222 case ADBOHDB:
1223 if(!tchdbvanish(adb->hdb)) err = true;
1224 break;
1225 case ADBOBDB:
1226 if(!tcbdbvanish(adb->bdb)) err = true;
1227 break;
1228 case ADBOFDB:
1229 if(!tcfdbvanish(adb->fdb)) err = true;
1230 break;
1231 case ADBOTDB:
1232 if(!tctdbvanish(adb->tdb)) err = true;
1233 break;
1234 case ADBOSKEL:
1235 skel = adb->skel;
1236 if(skel->vanish){
1237 if(!skel->vanish(skel->opq)) err = true;
1238 } else {
1239 err = true;
1240 }
1241 break;
1242 default:
1243 err = true;
1244 break;
1245 }
1246 return !err;
1247 }
1248
1249
1250 /* Copy the database file of an abstract database object. */
tcadbcopy(TCADB * adb,const char * path)1251 bool tcadbcopy(TCADB *adb, const char *path){
1252 assert(adb && path);
1253 bool err = false;
1254 ADBSKEL *skel;
1255 switch(adb->omode){
1256 case ADBOMDB:
1257 case ADBONDB:
1258 if(*path == '@'){
1259 char tsbuf[TCNUMBUFSIZ];
1260 sprintf(tsbuf, "%llu", (unsigned long long)(tctime() * 1000000));
1261 const char *args[2];
1262 args[0] = path + 1;
1263 args[1] = tsbuf;
1264 if(tcsystem(args, sizeof(args) / sizeof(*args)) != 0) err = true;
1265 } else {
1266 TCADB *tadb = tcadbnew();
1267 if(tcadbopen(tadb, path)){
1268 tcadbiterinit(adb);
1269 char *kbuf;
1270 int ksiz;
1271 while((kbuf = tcadbiternext(adb, &ksiz)) != NULL){
1272 int vsiz;
1273 char *vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
1274 if(vbuf){
1275 if(!tcadbput(tadb, kbuf, ksiz, vbuf, vsiz)) err = true;
1276 TCFREE(vbuf);
1277 }
1278 TCFREE(kbuf);
1279 }
1280 if(!tcadbclose(tadb)) err = true;
1281 } else {
1282 err = true;
1283 }
1284 tcadbdel(tadb);
1285 }
1286 break;
1287 case ADBOHDB:
1288 if(!tchdbcopy(adb->hdb, path)) err = true;
1289 break;
1290 case ADBOBDB:
1291 if(!tcbdbcopy(adb->bdb, path)) err = true;
1292 break;
1293 case ADBOFDB:
1294 if(!tcfdbcopy(adb->fdb, path)) err = true;
1295 break;
1296 case ADBOTDB:
1297 if(!tctdbcopy(adb->tdb, path)) err = true;
1298 break;
1299 case ADBOSKEL:
1300 skel = adb->skel;
1301 if(skel->copy){
1302 if(!skel->copy(skel->opq, path)) err = true;
1303 } else {
1304 err = true;
1305 }
1306 break;
1307 default:
1308 err = true;
1309 break;
1310 }
1311 return !err;
1312 }
1313
1314
1315 /* Begin the transaction of an abstract database object. */
tcadbtranbegin(TCADB * adb)1316 bool tcadbtranbegin(TCADB *adb){
1317 assert(adb);
1318 bool err = false;
1319 ADBSKEL *skel;
1320 switch(adb->omode){
1321 case ADBOMDB:
1322 err = true;
1323 break;
1324 case ADBONDB:
1325 err = true;
1326 break;
1327 case ADBOHDB:
1328 if(!tchdbtranbegin(adb->hdb)) err = true;
1329 break;
1330 case ADBOBDB:
1331 if(!tcbdbtranbegin(adb->bdb)) err = true;
1332 break;
1333 case ADBOFDB:
1334 if(!tcfdbtranbegin(adb->fdb)) err = true;
1335 break;
1336 case ADBOTDB:
1337 if(!tctdbtranbegin(adb->tdb)) err = true;
1338 break;
1339 case ADBOSKEL:
1340 skel = adb->skel;
1341 if(skel->tranbegin){
1342 if(!skel->tranbegin(skel->opq)) err = true;
1343 } else {
1344 err = true;
1345 }
1346 break;
1347 default:
1348 err = true;
1349 break;
1350 }
1351 return !err;
1352 }
1353
1354
1355 /* Commit the transaction of an abstract database object. */
tcadbtrancommit(TCADB * adb)1356 bool tcadbtrancommit(TCADB *adb){
1357 assert(adb);
1358 bool err = false;
1359 ADBSKEL *skel;
1360 switch(adb->omode){
1361 case ADBOMDB:
1362 err = true;
1363 break;
1364 case ADBONDB:
1365 err = true;
1366 break;
1367 case ADBOHDB:
1368 if(!tchdbtrancommit(adb->hdb)) err = true;
1369 break;
1370 case ADBOBDB:
1371 if(!tcbdbtrancommit(adb->bdb)) err = true;
1372 break;
1373 case ADBOFDB:
1374 if(!tcfdbtrancommit(adb->fdb)) err = true;
1375 break;
1376 case ADBOTDB:
1377 if(!tctdbtrancommit(adb->tdb)) err = true;
1378 break;
1379 case ADBOSKEL:
1380 skel = adb->skel;
1381 if(skel->trancommit){
1382 if(!skel->trancommit(skel->opq)) err = true;
1383 } else {
1384 err = true;
1385 }
1386 break;
1387 default:
1388 err = true;
1389 break;
1390 }
1391 return !err;
1392 }
1393
1394
1395 /* Abort the transaction of an abstract database object. */
tcadbtranabort(TCADB * adb)1396 bool tcadbtranabort(TCADB *adb){
1397 assert(adb);
1398 bool err = false;
1399 ADBSKEL *skel;
1400 switch(adb->omode){
1401 case ADBOMDB:
1402 err = true;
1403 break;
1404 case ADBONDB:
1405 err = true;
1406 break;
1407 case ADBOHDB:
1408 if(!tchdbtranabort(adb->hdb)) err = true;
1409 break;
1410 case ADBOBDB:
1411 if(!tcbdbtranabort(adb->bdb)) err = true;
1412 break;
1413 case ADBOFDB:
1414 if(!tcfdbtranabort(adb->fdb)) err = true;
1415 break;
1416 case ADBOTDB:
1417 if(!tctdbtranabort(adb->tdb)) err = true;
1418 break;
1419 case ADBOSKEL:
1420 skel = adb->skel;
1421 if(skel->tranabort){
1422 if(!skel->tranabort(skel->opq)) err = true;
1423 } else {
1424 err = true;
1425 }
1426 break;
1427 default:
1428 err = true;
1429 break;
1430 }
1431 return !err;
1432 }
1433
1434
1435 /* Get the file path of an abstract database object. */
tcadbpath(TCADB * adb)1436 const char *tcadbpath(TCADB *adb){
1437 assert(adb);
1438 const char *rv;
1439 ADBSKEL *skel;
1440 switch(adb->omode){
1441 case ADBOMDB:
1442 rv = "*";
1443 break;
1444 case ADBONDB:
1445 rv = "+";
1446 break;
1447 case ADBOHDB:
1448 rv = tchdbpath(adb->hdb);
1449 break;
1450 case ADBOBDB:
1451 rv = tcbdbpath(adb->bdb);
1452 break;
1453 case ADBOFDB:
1454 rv = tcfdbpath(adb->fdb);
1455 break;
1456 case ADBOTDB:
1457 rv = tctdbpath(adb->tdb);
1458 break;
1459 case ADBOSKEL:
1460 skel = adb->skel;
1461 if(skel->path){
1462 rv = skel->path(skel->opq);
1463 } else {
1464 rv = NULL;
1465 }
1466 break;
1467 default:
1468 rv = NULL;
1469 break;
1470 }
1471 return rv;
1472 }
1473
1474
1475 /* Get the number of records of an abstract database object. */
tcadbrnum(TCADB * adb)1476 uint64_t tcadbrnum(TCADB *adb){
1477 assert(adb);
1478 uint64_t rv;
1479 ADBSKEL *skel;
1480 switch(adb->omode){
1481 case ADBOMDB:
1482 rv = tcmdbrnum(adb->mdb);
1483 break;
1484 case ADBONDB:
1485 rv = tcndbrnum(adb->ndb);
1486 break;
1487 case ADBOHDB:
1488 rv = tchdbrnum(adb->hdb);
1489 break;
1490 case ADBOBDB:
1491 rv = tcbdbrnum(adb->bdb);
1492 break;
1493 case ADBOFDB:
1494 rv = tcfdbrnum(adb->fdb);
1495 break;
1496 case ADBOTDB:
1497 rv = tctdbrnum(adb->tdb);
1498 break;
1499 case ADBOSKEL:
1500 skel = adb->skel;
1501 if(skel->rnum){
1502 rv = skel->rnum(skel->opq);
1503 } else {
1504 rv = 0;
1505 }
1506 break;
1507 default:
1508 rv = 0;
1509 break;
1510 }
1511 return rv;
1512 }
1513
1514
1515 /* Get the size of the database of an abstract database object. */
tcadbsize(TCADB * adb)1516 uint64_t tcadbsize(TCADB *adb){
1517 assert(adb);
1518 uint64_t rv;
1519 ADBSKEL *skel;
1520 switch(adb->omode){
1521 case ADBOMDB:
1522 rv = tcmdbmsiz(adb->mdb);
1523 break;
1524 case ADBONDB:
1525 rv = tcndbmsiz(adb->ndb);
1526 break;
1527 case ADBOHDB:
1528 rv = tchdbfsiz(adb->hdb);
1529 break;
1530 case ADBOBDB:
1531 rv = tcbdbfsiz(adb->bdb);
1532 break;
1533 case ADBOFDB:
1534 rv = tcfdbfsiz(adb->fdb);
1535 break;
1536 case ADBOTDB:
1537 rv = tctdbfsiz(adb->tdb);
1538 break;
1539 case ADBOSKEL:
1540 skel = adb->skel;
1541 if(skel->size){
1542 rv = skel->size(skel->opq);
1543 } else {
1544 rv = 0;
1545 }
1546 break;
1547 default:
1548 rv = 0;
1549 break;
1550 }
1551 return rv;
1552 }
1553
1554
1555 /* Call a versatile function for miscellaneous operations of an abstract database object. */
tcadbmisc(TCADB * adb,const char * name,const TCLIST * args)1556 TCLIST *tcadbmisc(TCADB *adb, const char *name, const TCLIST *args){
1557 assert(adb && name && args);
1558 int argc = TCLISTNUM(args);
1559 TCLIST *rv;
1560 ADBSKEL *skel;
1561 switch(adb->omode){
1562 case ADBOMDB:
1563 if(!strcmp(name, "put") || !strcmp(name, "putkeep") || !strcmp(name, "putcat")){
1564 if(argc > 1){
1565 rv = tclistnew2(1);
1566 const char *kbuf;
1567 int ksiz;
1568 TCLISTVAL(kbuf, args, 0, ksiz);
1569 const char *vbuf;
1570 int vsiz;
1571 TCLISTVAL(vbuf, args, 1, vsiz);
1572 bool err = false;
1573 if(!strcmp(name, "put")){
1574 tcmdbput(adb->mdb, kbuf, ksiz, vbuf, vsiz);
1575 } else if(!strcmp(name, "putkeep")){
1576 if(!tcmdbputkeep(adb->mdb, kbuf, ksiz, vbuf, vsiz)) err = true;
1577 } else if(!strcmp(name, "putcat")){
1578 tcmdbputcat(adb->mdb, kbuf, ksiz, vbuf, vsiz);
1579 }
1580 if(err){
1581 tclistdel(rv);
1582 rv = NULL;
1583 }
1584 } else {
1585 rv = NULL;
1586 }
1587 } else if(!strcmp(name, "out")){
1588 if(argc > 0){
1589 rv = tclistnew2(1);
1590 const char *kbuf;
1591 int ksiz;
1592 TCLISTVAL(kbuf, args, 0, ksiz);
1593 if(!tcmdbout(adb->mdb, kbuf, ksiz)){
1594 tclistdel(rv);
1595 rv = NULL;
1596 }
1597 } else {
1598 rv = NULL;
1599 }
1600 } else if(!strcmp(name, "get")){
1601 if(argc > 0){
1602 rv = tclistnew2(1);
1603 const char *kbuf;
1604 int ksiz;
1605 TCLISTVAL(kbuf, args, 0, ksiz);
1606 int vsiz;
1607 char *vbuf = tcmdbget(adb->mdb, kbuf, ksiz, &vsiz);
1608 if(vbuf){
1609 TCLISTPUSH(rv, vbuf, vsiz);
1610 TCFREE(vbuf);
1611 } else {
1612 tclistdel(rv);
1613 rv = NULL;
1614 }
1615 } else {
1616 rv = NULL;
1617 }
1618 } else if(!strcmp(name, "putlist")){
1619 rv = tclistnew2(1);
1620 argc--;
1621 for(int i = 0; i < argc; i += 2){
1622 const char *kbuf, *vbuf;
1623 int ksiz, vsiz;
1624 TCLISTVAL(kbuf, args, i, ksiz);
1625 TCLISTVAL(vbuf, args, i + 1, vsiz);
1626 tcmdbput(adb->mdb, kbuf, ksiz, vbuf, vsiz);
1627 }
1628 } else if(!strcmp(name, "outlist")){
1629 rv = tclistnew2(1);
1630 for(int i = 0; i < argc; i++){
1631 const char *kbuf;
1632 int ksiz;
1633 TCLISTVAL(kbuf, args, i, ksiz);
1634 tcmdbout(adb->mdb, kbuf, ksiz);
1635 }
1636 } else if(!strcmp(name, "getlist")){
1637 rv = tclistnew2(argc * 2);
1638 for(int i = 0; i < argc; i++){
1639 const char *kbuf;
1640 int ksiz;
1641 TCLISTVAL(kbuf, args, i, ksiz);
1642 int vsiz;
1643 char *vbuf = tcmdbget(adb->mdb, kbuf, ksiz, &vsiz);
1644 if(vbuf){
1645 TCLISTPUSH(rv, kbuf, ksiz);
1646 TCLISTPUSH(rv, vbuf, vsiz);
1647 TCFREE(vbuf);
1648 }
1649 }
1650 } else if(!strcmp(name, "getpart")){
1651 if(argc > 0){
1652 const char *kbuf;
1653 int ksiz;
1654 TCLISTVAL(kbuf, args, 0, ksiz);
1655 int off = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
1656 if(off < 0) off = 0;
1657 if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
1658 int len = argc > 2 ? tcatoi(TCLISTVALPTR(args, 2)) : -1;
1659 if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
1660 int vsiz;
1661 char *vbuf = tcmdbget(adb->mdb, kbuf, ksiz, &vsiz);
1662 if(vbuf){
1663 if(off < vsiz){
1664 rv = tclistnew2(1);
1665 vsiz -= off;
1666 if(vsiz > len) vsiz = len;
1667 if(off > 0) memmove(vbuf, vbuf + off, vsiz);
1668 tclistpushmalloc(rv, vbuf, vsiz);
1669 } else {
1670 rv = NULL;
1671 TCFREE(vbuf);
1672 }
1673 } else {
1674 rv = NULL;
1675 }
1676 } else {
1677 rv = NULL;
1678 }
1679 } else if(!strcmp(name, "iterinit")){
1680 rv = tclistnew2(1);
1681 if(argc > 0){
1682 const char *kbuf;
1683 int ksiz;
1684 TCLISTVAL(kbuf, args, 0, ksiz);
1685 tcmdbiterinit2(adb->mdb, kbuf, ksiz);
1686 } else {
1687 tcmdbiterinit(adb->mdb);
1688 }
1689 } else if(!strcmp(name, "iternext")){
1690 rv = tclistnew2(1);
1691 int ksiz;
1692 char *kbuf = tcmdbiternext(adb->mdb, &ksiz);
1693 if(kbuf){
1694 TCLISTPUSH(rv, kbuf, ksiz);
1695 int vsiz;
1696 char *vbuf = tcmdbget(adb->mdb, kbuf, ksiz, &vsiz);
1697 if(vbuf){
1698 TCLISTPUSH(rv, vbuf, vsiz);
1699 TCFREE(vbuf);
1700 }
1701 TCFREE(kbuf);
1702 } else {
1703 tclistdel(rv);
1704 rv = NULL;
1705 }
1706 } else if(!strcmp(name, "sync")){
1707 rv = tclistnew2(1);
1708 if(!tcadbsync(adb)){
1709 tclistdel(rv);
1710 rv = NULL;
1711 }
1712 } else if(!strcmp(name, "optimize")){
1713 rv = tclistnew2(1);
1714 const char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
1715 if(!tcadboptimize(adb, params)){
1716 tclistdel(rv);
1717 rv = NULL;
1718 }
1719 } else if(!strcmp(name, "vanish")){
1720 rv = tclistnew2(1);
1721 if(!tcadbvanish(adb)){
1722 tclistdel(rv);
1723 rv = NULL;
1724 }
1725 } else if(!strcmp(name, "regex")){
1726 if(argc > 0){
1727 const char *regex = TCLISTVALPTR(args, 0);
1728 int options = REG_EXTENDED | REG_NOSUB;
1729 if(*regex == '*'){
1730 options |= REG_ICASE;
1731 regex++;
1732 }
1733 regex_t rbuf;
1734 if(regcomp(&rbuf, regex, options) == 0){
1735 rv = tclistnew();
1736 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
1737 if(max < 1) max = INT_MAX;
1738 tcmdbiterinit(adb->mdb);
1739 char *kbuf;
1740 int ksiz;
1741 while(max > 0 && (kbuf = tcmdbiternext(adb->mdb, &ksiz))){
1742 if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
1743 int vsiz;
1744 char *vbuf = tcmdbget(adb->mdb, kbuf, ksiz, &vsiz);
1745 if(vbuf){
1746 TCLISTPUSH(rv, kbuf, ksiz);
1747 TCLISTPUSH(rv, vbuf, vsiz);
1748 TCFREE(vbuf);
1749 max--;
1750 }
1751 }
1752 TCFREE(kbuf);
1753 }
1754 regfree(&rbuf);
1755 } else {
1756 rv = NULL;
1757 }
1758 } else {
1759 rv = NULL;
1760 }
1761 } else {
1762 rv = NULL;
1763 }
1764 break;
1765 case ADBONDB:
1766 if(!strcmp(name, "put") || !strcmp(name, "putkeep") || !strcmp(name, "putcat")){
1767 if(argc > 1){
1768 rv = tclistnew2(1);
1769 const char *kbuf;
1770 int ksiz;
1771 TCLISTVAL(kbuf, args, 0, ksiz);
1772 const char *vbuf;
1773 int vsiz;
1774 TCLISTVAL(vbuf, args, 1, vsiz);
1775 bool err = false;
1776 if(!strcmp(name, "put")){
1777 tcndbput(adb->ndb, kbuf, ksiz, vbuf, vsiz);
1778 } else if(!strcmp(name, "putkeep")){
1779 if(!tcndbputkeep(adb->ndb, kbuf, ksiz, vbuf, vsiz)) err = true;
1780 } else if(!strcmp(name, "putcat")){
1781 tcndbputcat(adb->ndb, kbuf, ksiz, vbuf, vsiz);
1782 }
1783 if(err){
1784 tclistdel(rv);
1785 rv = NULL;
1786 }
1787 } else {
1788 rv = NULL;
1789 }
1790 } else if(!strcmp(name, "out")){
1791 if(argc > 0){
1792 rv = tclistnew2(1);
1793 const char *kbuf;
1794 int ksiz;
1795 TCLISTVAL(kbuf, args, 0, ksiz);
1796 if(!tcndbout(adb->ndb, kbuf, ksiz)){
1797 tclistdel(rv);
1798 rv = NULL;
1799 }
1800 } else {
1801 rv = NULL;
1802 }
1803 } else if(!strcmp(name, "get")){
1804 if(argc > 0){
1805 rv = tclistnew2(1);
1806 const char *kbuf;
1807 int ksiz;
1808 TCLISTVAL(kbuf, args, 0, ksiz);
1809 int vsiz;
1810 char *vbuf = tcndbget(adb->ndb, kbuf, ksiz, &vsiz);
1811 if(vbuf){
1812 TCLISTPUSH(rv, vbuf, vsiz);
1813 TCFREE(vbuf);
1814 } else {
1815 tclistdel(rv);
1816 rv = NULL;
1817 }
1818 } else {
1819 rv = NULL;
1820 }
1821 } else if(!strcmp(name, "putlist")){
1822 rv = tclistnew2(1);
1823 argc--;
1824 for(int i = 0; i < argc; i += 2){
1825 const char *kbuf, *vbuf;
1826 int ksiz, vsiz;
1827 TCLISTVAL(kbuf, args, i, ksiz);
1828 TCLISTVAL(vbuf, args, i + 1, vsiz);
1829 tcndbput(adb->ndb, kbuf, ksiz, vbuf, vsiz);
1830 }
1831 } else if(!strcmp(name, "outlist")){
1832 rv = tclistnew2(1);
1833 for(int i = 0; i < argc; i++){
1834 const char *kbuf;
1835 int ksiz;
1836 TCLISTVAL(kbuf, args, i, ksiz);
1837 tcndbout(adb->ndb, kbuf, ksiz);
1838 }
1839 } else if(!strcmp(name, "getlist")){
1840 rv = tclistnew2(argc * 2);
1841 for(int i = 0; i < argc; i++){
1842 const char *kbuf;
1843 int ksiz;
1844 TCLISTVAL(kbuf, args, i, ksiz);
1845 int vsiz;
1846 char *vbuf = tcndbget(adb->ndb, kbuf, ksiz, &vsiz);
1847 if(vbuf){
1848 TCLISTPUSH(rv, kbuf, ksiz);
1849 TCLISTPUSH(rv, vbuf, vsiz);
1850 TCFREE(vbuf);
1851 }
1852 }
1853 } else if(!strcmp(name, "getpart")){
1854 if(argc > 0){
1855 const char *kbuf;
1856 int ksiz;
1857 TCLISTVAL(kbuf, args, 0, ksiz);
1858 int off = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
1859 if(off < 0) off = 0;
1860 if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
1861 int len = argc > 2 ? tcatoi(TCLISTVALPTR(args, 2)) : -1;
1862 if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
1863 int vsiz;
1864 char *vbuf = tcndbget(adb->ndb, kbuf, ksiz, &vsiz);
1865 if(vbuf){
1866 if(off < vsiz){
1867 rv = tclistnew2(1);
1868 vsiz -= off;
1869 if(vsiz > len) vsiz = len;
1870 if(off > 0) memmove(vbuf, vbuf + off, vsiz);
1871 tclistpushmalloc(rv, vbuf, vsiz);
1872 } else {
1873 rv = NULL;
1874 TCFREE(vbuf);
1875 }
1876 } else {
1877 rv = NULL;
1878 }
1879 } else {
1880 rv = NULL;
1881 }
1882 } else if(!strcmp(name, "iterinit")){
1883 rv = tclistnew2(1);
1884 if(argc > 0){
1885 const char *kbuf;
1886 int ksiz;
1887 TCLISTVAL(kbuf, args, 0, ksiz);
1888 tcndbiterinit2(adb->ndb, kbuf, ksiz);
1889 } else {
1890 tcndbiterinit(adb->ndb);
1891 }
1892 } else if(!strcmp(name, "iternext")){
1893 rv = tclistnew2(1);
1894 int ksiz;
1895 char *kbuf = tcndbiternext(adb->ndb, &ksiz);
1896 if(kbuf){
1897 TCLISTPUSH(rv, kbuf, ksiz);
1898 int vsiz;
1899 char *vbuf = tcndbget(adb->ndb, kbuf, ksiz, &vsiz);
1900 if(vbuf){
1901 TCLISTPUSH(rv, vbuf, vsiz);
1902 TCFREE(vbuf);
1903 }
1904 TCFREE(kbuf);
1905 } else {
1906 tclistdel(rv);
1907 rv = NULL;
1908 }
1909 } else if(!strcmp(name, "sync")){
1910 rv = tclistnew2(1);
1911 if(!tcadbsync(adb)){
1912 tclistdel(rv);
1913 rv = NULL;
1914 }
1915 } else if(!strcmp(name, "optimize")){
1916 rv = tclistnew2(1);
1917 const char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
1918 if(!tcadboptimize(adb, params)){
1919 tclistdel(rv);
1920 rv = NULL;
1921 }
1922 } else if(!strcmp(name, "vanish")){
1923 rv = tclistnew2(1);
1924 if(!tcadbvanish(adb)){
1925 tclistdel(rv);
1926 rv = NULL;
1927 }
1928 } else if(!strcmp(name, "regex")){
1929 if(argc > 0){
1930 const char *regex = TCLISTVALPTR(args, 0);
1931 int options = REG_EXTENDED | REG_NOSUB;
1932 if(*regex == '*'){
1933 options |= REG_ICASE;
1934 regex++;
1935 }
1936 regex_t rbuf;
1937 if(regcomp(&rbuf, regex, options) == 0){
1938 rv = tclistnew();
1939 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
1940 if(max < 1) max = INT_MAX;
1941 tcndbiterinit(adb->ndb);
1942 char *kbuf;
1943 int ksiz;
1944 while(max > 0 && (kbuf = tcndbiternext(adb->ndb, &ksiz))){
1945 if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
1946 int vsiz;
1947 char *vbuf = tcndbget(adb->ndb, kbuf, ksiz, &vsiz);
1948 if(vbuf){
1949 TCLISTPUSH(rv, kbuf, ksiz);
1950 TCLISTPUSH(rv, vbuf, vsiz);
1951 TCFREE(vbuf);
1952 max--;
1953 }
1954 }
1955 TCFREE(kbuf);
1956 }
1957 regfree(&rbuf);
1958 } else {
1959 rv = NULL;
1960 }
1961 } else {
1962 rv = NULL;
1963 }
1964 } else if(!strcmp(name, "range")){
1965 rv = tclistnew();
1966 int bksiz = 0;
1967 const char *bkbuf = NULL;
1968 if(argc > 0) TCLISTVAL(bkbuf, args, 0, bksiz);
1969 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
1970 if(max < 1) max = INT_MAX;
1971 int eksiz = 0;
1972 const char *ekbuf = NULL;
1973 if(argc > 2) TCLISTVAL(ekbuf, args, 2, eksiz);
1974 if(bkbuf){
1975 tcndbiterinit2(adb->ndb, bkbuf, bksiz);
1976 } else {
1977 tcndbiterinit(adb->ndb);
1978 }
1979 char *kbuf;
1980 int ksiz;
1981 while(max > 0 && (kbuf = tcndbiternext(adb->ndb, &ksiz)) != NULL){
1982 if(ekbuf && tccmplexical(kbuf, ksiz, ekbuf, eksiz, NULL) >= 0){
1983 TCFREE(kbuf);
1984 break;
1985 }
1986 int vsiz;
1987 char *vbuf = tcndbget(adb->ndb, kbuf, ksiz, &vsiz);
1988 if(vbuf){
1989 TCLISTPUSH(rv, kbuf, ksiz);
1990 TCLISTPUSH(rv, vbuf, vsiz);
1991 TCFREE(vbuf);
1992 max--;
1993 }
1994 TCFREE(kbuf);
1995 }
1996 } else {
1997 rv = NULL;
1998 }
1999 break;
2000 case ADBOHDB:
2001 if(!strcmp(name, "put") || !strcmp(name, "putkeep") || !strcmp(name, "putcat")){
2002 if(argc > 1){
2003 rv = tclistnew2(1);
2004 const char *kbuf;
2005 int ksiz;
2006 TCLISTVAL(kbuf, args, 0, ksiz);
2007 const char *vbuf;
2008 int vsiz;
2009 TCLISTVAL(vbuf, args, 1, vsiz);
2010 bool err = false;
2011 if(!strcmp(name, "put")){
2012 if(!tchdbput(adb->hdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2013 } else if(!strcmp(name, "putkeep")){
2014 if(!tchdbputkeep(adb->hdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2015 } else if(!strcmp(name, "putcat")){
2016 if(!tchdbputcat(adb->hdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2017 }
2018 if(err){
2019 tclistdel(rv);
2020 rv = NULL;
2021 }
2022 } else {
2023 rv = NULL;
2024 }
2025 } else if(!strcmp(name, "out")){
2026 if(argc > 0){
2027 rv = tclistnew2(1);
2028 const char *kbuf;
2029 int ksiz;
2030 TCLISTVAL(kbuf, args, 0, ksiz);
2031 if(!tchdbout(adb->hdb, kbuf, ksiz)){
2032 tclistdel(rv);
2033 rv = NULL;
2034 }
2035 } else {
2036 rv = NULL;
2037 }
2038 } else if(!strcmp(name, "get")){
2039 if(argc > 0){
2040 rv = tclistnew2(1);
2041 const char *kbuf;
2042 int ksiz;
2043 TCLISTVAL(kbuf, args, 0, ksiz);
2044 int vsiz;
2045 char *vbuf = tchdbget(adb->hdb, kbuf, ksiz, &vsiz);
2046 if(vbuf){
2047 TCLISTPUSH(rv, vbuf, vsiz);
2048 TCFREE(vbuf);
2049 } else {
2050 tclistdel(rv);
2051 rv = NULL;
2052 }
2053 } else {
2054 rv = NULL;
2055 }
2056 } else if(!strcmp(name, "putlist")){
2057 rv = tclistnew2(1);
2058 bool err = false;
2059 argc--;
2060 for(int i = 0; i < argc; i += 2){
2061 const char *kbuf;
2062 int ksiz;
2063 TCLISTVAL(kbuf, args, i, ksiz);
2064 int vsiz;
2065 const char *vbuf = tclistval(args, i + 1, &vsiz);
2066 if(!tchdbput(adb->hdb, kbuf, ksiz, vbuf, vsiz)){
2067 err = true;
2068 break;
2069 }
2070 }
2071 if(err){
2072 tclistdel(rv);
2073 rv = NULL;
2074 }
2075 } else if(!strcmp(name, "outlist")){
2076 rv = tclistnew2(1);
2077 bool err = false;
2078 for(int i = 0; i < argc; i++){
2079 const char *kbuf;
2080 int ksiz;
2081 TCLISTVAL(kbuf, args, i, ksiz);
2082 if(!tchdbout(adb->hdb, kbuf, ksiz) && tchdbecode(adb->hdb) != TCENOREC){
2083 err = true;
2084 break;
2085 }
2086 }
2087 if(err){
2088 tclistdel(rv);
2089 rv = NULL;
2090 }
2091 } else if(!strcmp(name, "getlist")){
2092 rv = tclistnew2(argc * 2);
2093 bool err = false;
2094 for(int i = 0; i < argc; i++){
2095 const char *kbuf;
2096 int ksiz;
2097 TCLISTVAL(kbuf, args, i, ksiz);
2098 int vsiz;
2099 char *vbuf = tchdbget(adb->hdb, kbuf, ksiz, &vsiz);
2100 if(vbuf){
2101 TCLISTPUSH(rv, kbuf, ksiz);
2102 TCLISTPUSH(rv, vbuf, vsiz);
2103 TCFREE(vbuf);
2104 } else if(tchdbecode(adb->hdb) != TCENOREC){
2105 err = true;
2106 }
2107 }
2108 if(err){
2109 tclistdel(rv);
2110 rv = NULL;
2111 }
2112 } else if(!strcmp(name, "getpart")){
2113 if(argc > 0){
2114 const char *kbuf;
2115 int ksiz;
2116 TCLISTVAL(kbuf, args, 0, ksiz);
2117 int off = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2118 if(off < 0) off = 0;
2119 if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
2120 int len = argc > 2 ? tcatoi(TCLISTVALPTR(args, 2)) : -1;
2121 if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
2122 int vsiz;
2123 char *vbuf = tchdbget(adb->hdb, kbuf, ksiz, &vsiz);
2124 if(vbuf){
2125 if(off < vsiz){
2126 rv = tclistnew2(1);
2127 vsiz -= off;
2128 if(vsiz > len) vsiz = len;
2129 if(off > 0) memmove(vbuf, vbuf + off, vsiz);
2130 tclistpushmalloc(rv, vbuf, vsiz);
2131 } else {
2132 rv = NULL;
2133 TCFREE(vbuf);
2134 }
2135 } else {
2136 rv = NULL;
2137 }
2138 } else {
2139 rv = NULL;
2140 }
2141 } else if(!strcmp(name, "iterinit")){
2142 rv = tclistnew2(1);
2143 bool err = false;
2144 if(argc > 0){
2145 const char *kbuf;
2146 int ksiz;
2147 TCLISTVAL(kbuf, args, 0, ksiz);
2148 if(!tchdbiterinit2(adb->hdb, kbuf, ksiz)) err = true;
2149 } else {
2150 if(!tchdbiterinit(adb->hdb)) err = true;
2151 }
2152 if(err){
2153 tclistdel(rv);
2154 rv = NULL;
2155 }
2156 } else if(!strcmp(name, "iternext")){
2157 rv = tclistnew2(1);
2158 int ksiz;
2159 char *kbuf = tchdbiternext(adb->hdb, &ksiz);
2160 if(kbuf){
2161 TCLISTPUSH(rv, kbuf, ksiz);
2162 int vsiz;
2163 char *vbuf = tchdbget(adb->hdb, kbuf, ksiz, &vsiz);
2164 if(vbuf){
2165 TCLISTPUSH(rv, vbuf, vsiz);
2166 TCFREE(vbuf);
2167 }
2168 TCFREE(kbuf);
2169 } else {
2170 tclistdel(rv);
2171 rv = NULL;
2172 }
2173 } else if(!strcmp(name, "sync")){
2174 rv = tclistnew2(1);
2175 if(!tcadbsync(adb)){
2176 tclistdel(rv);
2177 rv = NULL;
2178 }
2179 } else if(!strcmp(name, "optimize")){
2180 rv = tclistnew2(1);
2181 const char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
2182 if(!tcadboptimize(adb, params)){
2183 tclistdel(rv);
2184 rv = NULL;
2185 }
2186 } else if(!strcmp(name, "vanish")){
2187 rv = tclistnew2(1);
2188 if(!tcadbvanish(adb)){
2189 tclistdel(rv);
2190 rv = NULL;
2191 }
2192 } else if(!strcmp(name, "error")){
2193 rv = tclistnew2(1);
2194 int ecode = tchdbecode(adb->hdb);
2195 tclistprintf(rv, "%d: %s", ecode, tchdberrmsg(ecode));
2196 uint8_t flags = tchdbflags(adb->hdb);
2197 if(flags & HDBFFATAL) tclistprintf(rv, "fatal");
2198 } else if(!strcmp(name, "defrag")){
2199 rv = tclistnew2(1);
2200 int64_t step = argc > 0 ? tcatoi(TCLISTVALPTR(args, 0)) : -1;
2201 if(!tchdbdefrag(adb->hdb, step)){
2202 tclistdel(rv);
2203 rv = NULL;
2204 }
2205 } else if(!strcmp(name, "cacheclear")){
2206 rv = tclistnew2(1);
2207 if(!tchdbcacheclear(adb->hdb)){
2208 tclistdel(rv);
2209 rv = NULL;
2210 }
2211 } else if(!strcmp(name, "regex")){
2212 if(argc > 0){
2213 const char *regex = TCLISTVALPTR(args, 0);
2214 int options = REG_EXTENDED | REG_NOSUB;
2215 if(*regex == '*'){
2216 options |= REG_ICASE;
2217 regex++;
2218 }
2219 regex_t rbuf;
2220 if(regcomp(&rbuf, regex, options) == 0){
2221 rv = tclistnew();
2222 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2223 if(max < 1) max = INT_MAX;
2224 tchdbiterinit(adb->hdb);
2225 TCXSTR *kxstr = tcxstrnew();
2226 TCXSTR *vxstr = tcxstrnew();
2227 while(max > 0 && tchdbiternext3(adb->hdb, kxstr, vxstr)){
2228 const char *kbuf = TCXSTRPTR(kxstr);
2229 if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
2230 TCLISTPUSH(rv, kbuf, TCXSTRSIZE(kxstr));
2231 TCLISTPUSH(rv, TCXSTRPTR(vxstr), TCXSTRSIZE(vxstr));
2232 max--;
2233 }
2234 }
2235 tcxstrdel(vxstr);
2236 tcxstrdel(kxstr);
2237 regfree(&rbuf);
2238 } else {
2239 rv = NULL;
2240 }
2241 } else {
2242 rv = NULL;
2243 }
2244 } else {
2245 rv = NULL;
2246 }
2247 break;
2248 case ADBOBDB:
2249 if(!strcmp(name, "put") || !strcmp(name, "putkeep") || !strcmp(name, "putcat") ||
2250 !strcmp(name, "putdup") || !strcmp(name, "putdupback")){
2251 if(argc > 1){
2252 rv = tclistnew2(1);
2253 const char *kbuf;
2254 int ksiz;
2255 TCLISTVAL(kbuf, args, 0, ksiz);
2256 const char *vbuf;
2257 int vsiz;
2258 TCLISTVAL(vbuf, args, 1, vsiz);
2259 bool err = false;
2260 if(!strcmp(name, "put")){
2261 if(!tcbdbput(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2262 } else if(!strcmp(name, "putkeep")){
2263 if(!tcbdbputkeep(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2264 } else if(!strcmp(name, "putcat")){
2265 if(!tcbdbputcat(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2266 } else if(!strcmp(name, "putdup")){
2267 if(!tcbdbputdup(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2268 } else if(!strcmp(name, "putdupback")){
2269 if(!tcbdbputdupback(adb->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2270 }
2271 if(err){
2272 tclistdel(rv);
2273 rv = NULL;
2274 }
2275 } else {
2276 rv = NULL;
2277 }
2278 } else if(!strcmp(name, "out")){
2279 if(argc > 0){
2280 rv = tclistnew2(1);
2281 const char *kbuf;
2282 int ksiz;
2283 TCLISTVAL(kbuf, args, 0, ksiz);
2284 if(!tcbdbout(adb->bdb, kbuf, ksiz)){
2285 tclistdel(rv);
2286 rv = NULL;
2287 }
2288 } else {
2289 rv = NULL;
2290 }
2291 } else if(!strcmp(name, "get")){
2292 if(argc > 0){
2293 rv = tclistnew2(1);
2294 const char *kbuf;
2295 int ksiz;
2296 TCLISTVAL(kbuf, args, 0, ksiz);
2297 TCLIST *vals = tcbdbget4(adb->bdb, kbuf, ksiz);
2298 if(vals){
2299 tclistdel(rv);
2300 rv = vals;
2301 } else {
2302 tclistdel(rv);
2303 rv = NULL;
2304 }
2305 } else {
2306 rv = NULL;
2307 }
2308 } else if(!strcmp(name, "putlist")){
2309 rv = tclistnew2(1);
2310 bool err = false;
2311 argc--;
2312 for(int i = 0; i < argc; i += 2){
2313 const char *kbuf, *vbuf;
2314 int ksiz, vsiz;
2315 TCLISTVAL(kbuf, args, i, ksiz);
2316 TCLISTVAL(vbuf, args, i + 1, vsiz);
2317 if(!tcbdbputdup(adb->bdb, kbuf, ksiz, vbuf, vsiz)){
2318 err = true;
2319 break;
2320 }
2321 }
2322 if(err){
2323 tclistdel(rv);
2324 rv = NULL;
2325 }
2326 } else if(!strcmp(name, "outlist")){
2327 rv = tclistnew2(1);
2328 bool err = false;
2329 for(int i = 0; i < argc; i++){
2330 const char *kbuf;
2331 int ksiz;
2332 TCLISTVAL(kbuf, args, i, ksiz);
2333 if(!tcbdbout3(adb->bdb, kbuf, ksiz) && tcbdbecode(adb->bdb) != TCENOREC){
2334 err = true;
2335 break;
2336 }
2337 }
2338 if(err){
2339 tclistdel(rv);
2340 rv = NULL;
2341 }
2342 } else if(!strcmp(name, "getlist")){
2343 rv = tclistnew2(argc * 2);
2344 bool err = false;
2345 for(int i = 0; i < argc; i++){
2346 const char *kbuf;
2347 int ksiz;
2348 TCLISTVAL(kbuf, args, i, ksiz);
2349 TCLIST *vals = tcbdbget4(adb->bdb, kbuf, ksiz);
2350 if(vals){
2351 int vnum = TCLISTNUM(vals);
2352 for(int j = 0; j < vnum; j++){
2353 TCLISTPUSH(rv, kbuf, ksiz);
2354 const char *vbuf;
2355 int vsiz;
2356 TCLISTVAL(vbuf, vals, j, vsiz);
2357 TCLISTPUSH(rv, vbuf, vsiz);
2358 }
2359 tclistdel(vals);
2360 } else if(tcbdbecode(adb->bdb) != TCENOREC){
2361 err = true;
2362 }
2363 }
2364 if(err){
2365 tclistdel(rv);
2366 rv = NULL;
2367 }
2368 } else if(!strcmp(name, "getpart")){
2369 if(argc > 0){
2370 const char *kbuf;
2371 int ksiz;
2372 TCLISTVAL(kbuf, args, 0, ksiz);
2373 int off = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2374 if(off < 0) off = 0;
2375 if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
2376 int len = argc > 2 ? tcatoi(TCLISTVALPTR(args, 2)) : -1;
2377 if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
2378 int vsiz;
2379 char *vbuf = tcbdbget(adb->bdb, kbuf, ksiz, &vsiz);
2380 if(vbuf){
2381 if(off < vsiz){
2382 rv = tclistnew2(1);
2383 vsiz -= off;
2384 if(vsiz > len) vsiz = len;
2385 if(off > 0) memmove(vbuf, vbuf + off, vsiz);
2386 tclistpushmalloc(rv, vbuf, vsiz);
2387 } else {
2388 rv = NULL;
2389 TCFREE(vbuf);
2390 }
2391 } else {
2392 rv = NULL;
2393 }
2394 } else {
2395 rv = NULL;
2396 }
2397 } else if(!strcmp(name, "iterinit")){
2398 rv = tclistnew2(1);
2399 bool err = false;
2400 if(argc > 0){
2401 const char *kbuf;
2402 int ksiz;
2403 TCLISTVAL(kbuf, args, 0, ksiz);
2404 if(!tcbdbcurjump(adb->cur, kbuf, ksiz)) err = true;
2405 } else {
2406 if(!tcbdbcurfirst(adb->cur)) err = true;
2407 }
2408 if(err){
2409 tclistdel(rv);
2410 rv = NULL;
2411 }
2412 } else if(!strcmp(name, "iternext")){
2413 rv = tclistnew2(1);
2414 int ksiz;
2415 const char *kbuf = tcbdbcurkey3(adb->cur, &ksiz);
2416 if(kbuf){
2417 TCLISTPUSH(rv, kbuf, ksiz);
2418 int vsiz;
2419 const char *vbuf = tcbdbcurval3(adb->cur, &vsiz);
2420 if(vbuf) TCLISTPUSH(rv, vbuf, vsiz);
2421 tcbdbcurnext(adb->cur);
2422 } else {
2423 tclistdel(rv);
2424 rv = NULL;
2425 }
2426 } else if(!strcmp(name, "sync")){
2427 rv = tclistnew2(1);
2428 if(!tcadbsync(adb)){
2429 tclistdel(rv);
2430 rv = NULL;
2431 }
2432 } else if(!strcmp(name, "optimize")){
2433 rv = tclistnew2(1);
2434 const char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
2435 if(!tcadboptimize(adb, params)){
2436 tclistdel(rv);
2437 rv = NULL;
2438 }
2439 } else if(!strcmp(name, "vanish")){
2440 rv = tclistnew2(1);
2441 if(!tcadbvanish(adb)){
2442 tclistdel(rv);
2443 rv = NULL;
2444 }
2445 } else if(!strcmp(name, "error")){
2446 rv = tclistnew2(1);
2447 int ecode = tcbdbecode(adb->bdb);
2448 tclistprintf(rv, "%d: %s", ecode, tcbdberrmsg(ecode));
2449 uint8_t flags = tcbdbflags(adb->bdb);
2450 if(flags & BDBFFATAL) tclistprintf(rv, "fatal");
2451 } else if(!strcmp(name, "defrag")){
2452 rv = tclistnew2(1);
2453 int64_t step = argc > 0 ? tcatoi(TCLISTVALPTR(args, 0)) : -1;
2454 if(!tcbdbdefrag(adb->bdb, step)){
2455 tclistdel(rv);
2456 rv = NULL;
2457 }
2458 } else if(!strcmp(name, "cacheclear")){
2459 rv = tclistnew2(1);
2460 if(!tcbdbcacheclear(adb->bdb)){
2461 tclistdel(rv);
2462 rv = NULL;
2463 }
2464 } else if(!strcmp(name, "regex")){
2465 if(argc > 0){
2466 const char *regex = TCLISTVALPTR(args, 0);
2467 int options = REG_EXTENDED | REG_NOSUB;
2468 if(*regex == '*'){
2469 options |= REG_ICASE;
2470 regex++;
2471 }
2472 regex_t rbuf;
2473 if(regcomp(&rbuf, regex, options) == 0){
2474 rv = tclistnew();
2475 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2476 if(max < 1) max = INT_MAX;
2477 BDBCUR *cur = tcbdbcurnew(adb->bdb);
2478 tcbdbcurfirst(cur);
2479 TCXSTR *kxstr = tcxstrnew();
2480 TCXSTR *vxstr = tcxstrnew();
2481 while(max > 0 && tcbdbcurrec(cur, kxstr, vxstr)){
2482 const char *kbuf = TCXSTRPTR(kxstr);
2483 if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
2484 TCLISTPUSH(rv, kbuf, TCXSTRSIZE(kxstr));
2485 TCLISTPUSH(rv, TCXSTRPTR(vxstr), TCXSTRSIZE(vxstr));
2486 max--;
2487 }
2488 tcbdbcurnext(cur);
2489 }
2490 tcxstrdel(vxstr);
2491 tcxstrdel(kxstr);
2492 tcbdbcurdel(cur);
2493 regfree(&rbuf);
2494 } else {
2495 rv = NULL;
2496 }
2497 } else {
2498 rv = NULL;
2499 }
2500 } else if(!strcmp(name, "range")){
2501 rv = tclistnew();
2502 int bksiz = 0;
2503 const char *bkbuf = NULL;
2504 if(argc > 0) TCLISTVAL(bkbuf, args, 0, bksiz);
2505 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2506 if(max < 1) max = INT_MAX;
2507 int eksiz = 0;
2508 const char *ekbuf = NULL;
2509 if(argc > 2) TCLISTVAL(ekbuf, args, 2, eksiz);
2510 TCCMP cmp = tcbdbcmpfunc(adb->bdb);
2511 void *cmpop = tcbdbcmpop(adb->bdb);
2512 BDBCUR *cur = tcbdbcurnew(adb->bdb);
2513 if(bkbuf){
2514 tcbdbcurjump(cur, bkbuf, bksiz);
2515 } else {
2516 tcbdbcurfirst(cur);
2517 }
2518 TCXSTR *kxstr = tcxstrnew();
2519 TCXSTR *vxstr = tcxstrnew();
2520 while(max > 0 && tcbdbcurrec(cur, kxstr, vxstr)){
2521 const char *kbuf = TCXSTRPTR(kxstr);
2522 int ksiz = TCXSTRSIZE(kxstr);
2523 if(ekbuf && cmp(kbuf, ksiz, ekbuf, eksiz, cmpop) >= 0) break;
2524 TCLISTPUSH(rv, kbuf, ksiz);
2525 TCLISTPUSH(rv, TCXSTRPTR(vxstr), TCXSTRSIZE(vxstr));
2526 max--;
2527 tcbdbcurnext(cur);
2528 }
2529 tcxstrdel(vxstr);
2530 tcxstrdel(kxstr);
2531 tcbdbcurdel(cur);
2532 } else {
2533 rv = NULL;
2534 }
2535 break;
2536 case ADBOFDB:
2537 if(!strcmp(name, "put") || !strcmp(name, "putkeep") || !strcmp(name, "putcat")){
2538 if(argc > 1){
2539 rv = tclistnew2(1);
2540 const char *kbuf, *vbuf;
2541 int ksiz, vsiz;
2542 TCLISTVAL(kbuf, args, 0, ksiz);
2543 TCLISTVAL(vbuf, args, 1, vsiz);
2544 bool err = false;
2545 if(!strcmp(name, "put")){
2546 if(!tcfdbput2(adb->fdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2547 } else if(!strcmp(name, "putkeep")){
2548 if(!tcfdbputkeep2(adb->fdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2549 } else if(!strcmp(name, "putcat")){
2550 if(!tcfdbputcat2(adb->fdb, kbuf, ksiz, vbuf, vsiz)) err = true;
2551 }
2552 if(err){
2553 tclistdel(rv);
2554 rv = NULL;
2555 }
2556 } else {
2557 rv = NULL;
2558 }
2559 } else if(!strcmp(name, "out")){
2560 if(argc > 0){
2561 rv = tclistnew2(1);
2562 const char *kbuf;
2563 int ksiz;
2564 TCLISTVAL(kbuf, args, 0, ksiz);
2565 if(!tcfdbout2(adb->fdb, kbuf, ksiz)){
2566 tclistdel(rv);
2567 rv = NULL;
2568 }
2569 } else {
2570 rv = NULL;
2571 }
2572 } else if(!strcmp(name, "get")){
2573 if(argc > 0){
2574 rv = tclistnew2(1);
2575 const char *kbuf;
2576 int ksiz;
2577 TCLISTVAL(kbuf, args, 0, ksiz);
2578 int vsiz;
2579 char *vbuf = tcfdbget2(adb->fdb, kbuf, ksiz, &vsiz);
2580 if(vbuf){
2581 TCLISTPUSH(rv, vbuf, vsiz);
2582 TCFREE(vbuf);
2583 } else {
2584 tclistdel(rv);
2585 rv = NULL;
2586 }
2587 } else {
2588 rv = NULL;
2589 }
2590 } else if(!strcmp(name, "putlist")){
2591 rv = tclistnew2(1);
2592 bool err = false;
2593 argc--;
2594 for(int i = 0; i < argc; i += 2){
2595 const char *kbuf, *vbuf;
2596 int ksiz, vsiz;
2597 TCLISTVAL(kbuf, args, i, ksiz);
2598 TCLISTVAL(vbuf, args, i + 1, vsiz);
2599 if(!tcfdbput2(adb->fdb, kbuf, ksiz, vbuf, vsiz)){
2600 err = true;
2601 break;
2602 }
2603 }
2604 if(err){
2605 tclistdel(rv);
2606 rv = NULL;
2607 }
2608 } else if(!strcmp(name, "outlist")){
2609 rv = tclistnew2(1);
2610 bool err = false;
2611 for(int i = 0; i < argc; i++){
2612 const char *kbuf;
2613 int ksiz;
2614 TCLISTVAL(kbuf, args, i, ksiz);
2615 if(!tcfdbout2(adb->fdb, kbuf, ksiz) && tcfdbecode(adb->fdb) != TCENOREC){
2616 err = true;
2617 break;
2618 }
2619 }
2620 if(err){
2621 tclistdel(rv);
2622 rv = NULL;
2623 }
2624 } else if(!strcmp(name, "getlist")){
2625 rv = tclistnew2(argc * 2);
2626 bool err = false;
2627 for(int i = 0; i < argc; i++){
2628 const char *kbuf;
2629 int ksiz;
2630 TCLISTVAL(kbuf, args, i, ksiz);
2631 int vsiz;
2632 char *vbuf = tcfdbget2(adb->fdb, kbuf, ksiz, &vsiz);
2633 if(vbuf){
2634 TCLISTPUSH(rv, kbuf, ksiz);
2635 TCLISTPUSH(rv, vbuf, vsiz);
2636 TCFREE(vbuf);
2637 } else if(tcfdbecode(adb->fdb) != TCENOREC){
2638 err = true;
2639 }
2640 }
2641 if(err){
2642 tclistdel(rv);
2643 rv = NULL;
2644 }
2645 } else if(!strcmp(name, "getpart")){
2646 if(argc > 0){
2647 const char *kbuf;
2648 int ksiz;
2649 TCLISTVAL(kbuf, args, 0, ksiz);
2650 int off = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2651 if(off < 0) off = 0;
2652 if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
2653 int len = argc > 2 ? tcatoi(TCLISTVALPTR(args, 2)) : -1;
2654 if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
2655 int vsiz;
2656 char *vbuf = tcfdbget2(adb->fdb, kbuf, ksiz, &vsiz);
2657 if(vbuf){
2658 if(off < vsiz){
2659 rv = tclistnew2(1);
2660 vsiz -= off;
2661 if(vsiz > len) vsiz = len;
2662 if(off > 0) memmove(vbuf, vbuf + off, vsiz);
2663 tclistpushmalloc(rv, vbuf, vsiz);
2664 } else {
2665 rv = NULL;
2666 TCFREE(vbuf);
2667 }
2668 } else {
2669 rv = NULL;
2670 }
2671 } else {
2672 rv = NULL;
2673 }
2674 } else if(!strcmp(name, "iterinit")){
2675 rv = tclistnew2(1);
2676 bool err = false;
2677 if(argc > 0){
2678 const char *kbuf;
2679 int ksiz;
2680 TCLISTVAL(kbuf, args, 0, ksiz);
2681 if(!tcfdbiterinit3(adb->fdb, kbuf, ksiz)) err = true;
2682 } else {
2683 if(!tcfdbiterinit(adb->fdb)) err = true;
2684 }
2685 if(err){
2686 tclistdel(rv);
2687 rv = NULL;
2688 }
2689 } else if(!strcmp(name, "iternext")){
2690 rv = tclistnew2(1);
2691 int ksiz;
2692 char *kbuf = tcfdbiternext2(adb->fdb, &ksiz);
2693 if(kbuf){
2694 TCLISTPUSH(rv, kbuf, ksiz);
2695 int vsiz;
2696 char *vbuf = tcfdbget2(adb->fdb, kbuf, ksiz, &vsiz);
2697 if(vbuf){
2698 TCLISTPUSH(rv, vbuf, vsiz);
2699 TCFREE(vbuf);
2700 }
2701 TCFREE(kbuf);
2702 } else {
2703 tclistdel(rv);
2704 rv = NULL;
2705 }
2706 } else if(!strcmp(name, "sync")){
2707 rv = tclistnew2(1);
2708 if(!tcadbsync(adb)){
2709 tclistdel(rv);
2710 rv = NULL;
2711 }
2712 } else if(!strcmp(name, "optimize")){
2713 rv = tclistnew2(1);
2714 const char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
2715 if(!tcadboptimize(adb, params)){
2716 tclistdel(rv);
2717 rv = NULL;
2718 }
2719 } else if(!strcmp(name, "vanish")){
2720 rv = tclistnew2(1);
2721 if(!tcadbvanish(adb)){
2722 tclistdel(rv);
2723 rv = NULL;
2724 }
2725 } else if(!strcmp(name, "error")){
2726 rv = tclistnew2(1);
2727 int ecode = tcfdbecode(adb->fdb);
2728 tclistprintf(rv, "%d: %s", ecode, tcfdberrmsg(ecode));
2729 uint8_t flags = tcfdbflags(adb->fdb);
2730 if(flags & FDBFFATAL) tclistprintf(rv, "fatal");
2731 } else if(!strcmp(name, "regex")){
2732 if(argc > 0){
2733 const char *regex = TCLISTVALPTR(args, 0);
2734 int options = REG_EXTENDED | REG_NOSUB;
2735 if(*regex == '*'){
2736 options |= REG_ICASE;
2737 regex++;
2738 }
2739 regex_t rbuf;
2740 if(regcomp(&rbuf, regex, options) == 0){
2741 rv = tclistnew();
2742 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2743 if(max < 1) max = INT_MAX;
2744 tcfdbiterinit(adb->fdb);
2745 char *kbuf;
2746 int ksiz;
2747 while(max > 0 && (kbuf = tcfdbiternext2(adb->fdb, &ksiz))){
2748 if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
2749 int vsiz;
2750 char *vbuf = tcfdbget2(adb->fdb, kbuf, ksiz, &vsiz);
2751 if(vbuf){
2752 TCLISTPUSH(rv, kbuf, ksiz);
2753 TCLISTPUSH(rv, vbuf, vsiz);
2754 TCFREE(vbuf);
2755 max--;
2756 }
2757 }
2758 TCFREE(kbuf);
2759 }
2760 regfree(&rbuf);
2761 } else {
2762 rv = NULL;
2763 }
2764 } else {
2765 rv = NULL;
2766 }
2767 } else if(!strcmp(name, "range")){
2768 rv = tclistnew();
2769 int bksiz = 0;
2770 const char *bkbuf = NULL;
2771 if(argc > 0) TCLISTVAL(bkbuf, args, 0, bksiz);
2772 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2773 if(max < 1) max = INT_MAX;
2774 int eksiz = 0;
2775 const char *ekbuf = NULL;
2776 if(argc > 2) TCLISTVAL(ekbuf, args, 2, eksiz);
2777 if(bkbuf){
2778 tcfdbiterinit3(adb->fdb, bkbuf, bksiz);
2779 } else {
2780 tcfdbiterinit(adb->fdb);
2781 }
2782 int64_t eid = ekbuf ? tcfdbkeytoid(ekbuf, eksiz) : -1;
2783 char *kbuf;
2784 int ksiz;
2785 while(max > 0 && (kbuf = tcfdbiternext2(adb->fdb, &ksiz)) != NULL){
2786 if(eid > 0 && tcatoi(kbuf) >= eid){
2787 TCFREE(kbuf);
2788 break;
2789 }
2790 int vsiz;
2791 char *vbuf = tcfdbget2(adb->fdb, kbuf, ksiz, &vsiz);
2792 if(vbuf){
2793 TCLISTPUSH(rv, kbuf, ksiz);
2794 TCLISTPUSH(rv, vbuf, vsiz);
2795 TCFREE(vbuf);
2796 max--;
2797 }
2798 TCFREE(kbuf);
2799 }
2800 } else {
2801 rv = NULL;
2802 }
2803 break;
2804 case ADBOTDB:
2805 if(!strcmp(name, "put") || !strcmp(name, "putkeep") || !strcmp(name, "putcat")){
2806 if(argc > 0){
2807 rv = tclistnew2(1);
2808 char *pkbuf;
2809 int pksiz;
2810 TCLISTVAL(pkbuf, args, 0, pksiz);
2811 argc--;
2812 TCMAP *cols = tcmapnew2(argc);
2813 for(int i = 1; i < argc; i += 2){
2814 const char *kbuf, *vbuf;
2815 int ksiz, vsiz;
2816 TCLISTVAL(kbuf, args, i, ksiz);
2817 TCLISTVAL(vbuf, args, i + 1, vsiz);
2818 tcmapput(cols, kbuf, ksiz, vbuf, vsiz);
2819 }
2820 bool err = false;
2821 if(!strcmp(name, "put")){
2822 if(!tctdbput(adb->tdb, pkbuf, pksiz, cols)) err = true;
2823 } else if(!strcmp(name, "putkeep")){
2824 if(!tctdbputkeep(adb->tdb, pkbuf, pksiz, cols)) err = true;
2825 } else if(!strcmp(name, "putcat")){
2826 if(!tctdbputcat(adb->tdb, pkbuf, pksiz, cols)) err = true;
2827 }
2828 tcmapdel(cols);
2829 if(err){
2830 tclistdel(rv);
2831 rv = NULL;
2832 }
2833 } else {
2834 rv = NULL;
2835 }
2836 } else if(!strcmp(name, "out")){
2837 if(argc > 0){
2838 rv = tclistnew2(1);
2839 char *pkbuf;
2840 int pksiz;
2841 TCLISTVAL(pkbuf, args, 0, pksiz);
2842 if(!tctdbout(adb->tdb, pkbuf, pksiz)){
2843 tclistdel(rv);
2844 rv = NULL;
2845 }
2846 } else {
2847 rv = NULL;
2848 }
2849 } else if(!strcmp(name, "get")){
2850 if(argc > 0){
2851 rv = tclistnew2(1);
2852 char *pkbuf;
2853 int pksiz;
2854 TCLISTVAL(pkbuf, args, 0, pksiz);
2855 TCMAP *cols = tctdbget(adb->tdb, pkbuf, pksiz);
2856 if(cols){
2857 tcmapiterinit(cols);
2858 const char *kbuf;
2859 int ksiz;
2860 while((kbuf = tcmapiternext(cols, &ksiz)) != NULL){
2861 int vsiz;
2862 const char *vbuf = tcmapiterval(kbuf, &vsiz);
2863 TCLISTPUSH(rv, kbuf, ksiz);
2864 TCLISTPUSH(rv, vbuf, vsiz);
2865 }
2866 tcmapdel(cols);
2867 } else {
2868 tclistdel(rv);
2869 rv = NULL;
2870 }
2871 } else {
2872 rv = NULL;
2873 }
2874 } else if(!strcmp(name, "putlist")){
2875 rv = tclistnew2(1);
2876 bool err = false;
2877 argc--;
2878 for(int i = 0; i < argc; i += 2){
2879 const char *kbuf, *vbuf;
2880 int ksiz, vsiz;
2881 TCLISTVAL(kbuf, args, i, ksiz);
2882 TCLISTVAL(vbuf, args, i + 1, vsiz);
2883 if(!tctdbput2(adb->tdb, kbuf, ksiz, vbuf, vsiz)){
2884 err = true;
2885 break;
2886 }
2887 }
2888 if(err){
2889 tclistdel(rv);
2890 rv = NULL;
2891 }
2892 } else if(!strcmp(name, "outlist")){
2893 rv = tclistnew2(1);
2894 bool err = false;
2895 for(int i = 0; i < argc; i++){
2896 const char *kbuf;
2897 int ksiz;
2898 TCLISTVAL(kbuf, args, i, ksiz);
2899 if(!tctdbout(adb->tdb, kbuf, ksiz) && tctdbecode(adb->tdb) != TCENOREC){
2900 err = true;
2901 break;
2902 }
2903 }
2904 if(err){
2905 tclistdel(rv);
2906 rv = NULL;
2907 }
2908 } else if(!strcmp(name, "getlist")){
2909 rv = tclistnew2(argc * 2);
2910 bool err = false;
2911 for(int i = 0; i < argc; i++){
2912 const char *kbuf;
2913 int ksiz;
2914 TCLISTVAL(kbuf, args, i, ksiz);
2915 int vsiz;
2916 char *vbuf = tctdbget2(adb->tdb, kbuf, ksiz, &vsiz);
2917 if(vbuf){
2918 TCLISTPUSH(rv, kbuf, ksiz);
2919 TCLISTPUSH(rv, vbuf, vsiz);
2920 TCFREE(vbuf);
2921 } else if(tctdbecode(adb->tdb) != TCENOREC){
2922 err = true;
2923 }
2924 }
2925 if(err){
2926 tclistdel(rv);
2927 rv = NULL;
2928 }
2929 } else if(!strcmp(name, "getpart")){
2930 if(argc > 0){
2931 const char *kbuf;
2932 int ksiz;
2933 TCLISTVAL(kbuf, args, 0, ksiz);
2934 int off = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
2935 if(off < 0) off = 0;
2936 if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
2937 int len = argc > 2 ? tcatoi(TCLISTVALPTR(args, 2)) : -1;
2938 if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
2939 int vsiz;
2940 char *vbuf = tctdbget2(adb->tdb, kbuf, ksiz, &vsiz);
2941 if(vbuf){
2942 if(off < vsiz){
2943 rv = tclistnew2(1);
2944 vsiz -= off;
2945 if(vsiz > len) vsiz = len;
2946 if(off > 0) memmove(vbuf, vbuf + off, vsiz);
2947 tclistpushmalloc(rv, vbuf, vsiz);
2948 } else {
2949 rv = NULL;
2950 TCFREE(vbuf);
2951 }
2952 } else {
2953 rv = NULL;
2954 }
2955 } else {
2956 rv = NULL;
2957 }
2958 } else if(!strcmp(name, "iterinit")){
2959 rv = tclistnew2(1);
2960 bool err = false;
2961 if(argc > 0){
2962 const char *pkbuf;
2963 int pksiz;
2964 TCLISTVAL(pkbuf, args, 0, pksiz);
2965 if(!tctdbiterinit2(adb->tdb, pkbuf, pksiz)) err = true;
2966 } else {
2967 if(!tctdbiterinit(adb->tdb)) err = true;
2968 }
2969 if(err){
2970 tclistdel(rv);
2971 rv = NULL;
2972 }
2973 } else if(!strcmp(name, "iternext")){
2974 rv = tclistnew2(1);
2975 int pksiz;
2976 char *pkbuf = tctdbiternext(adb->tdb, &pksiz);
2977 if(pkbuf){
2978 TCLISTPUSH(rv, pkbuf, pksiz);
2979 int csiz;
2980 char *cbuf = tctdbget2(adb->tdb, pkbuf, pksiz, &csiz);
2981 if(cbuf){
2982 TCLISTPUSH(rv, cbuf, csiz);
2983 TCFREE(cbuf);
2984 }
2985 TCFREE(pkbuf);
2986 } else {
2987 tclistdel(rv);
2988 rv = NULL;
2989 }
2990 } else if(!strcmp(name, "sync")){
2991 rv = tclistnew2(1);
2992 if(!tcadbsync(adb)){
2993 tclistdel(rv);
2994 rv = NULL;
2995 }
2996 } else if(!strcmp(name, "optimize")){
2997 rv = tclistnew2(1);
2998 const char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
2999 if(!tcadboptimize(adb, params)){
3000 tclistdel(rv);
3001 rv = NULL;
3002 }
3003 } else if(!strcmp(name, "vanish")){
3004 rv = tclistnew2(1);
3005 if(!tcadbvanish(adb)){
3006 tclistdel(rv);
3007 rv = NULL;
3008 }
3009 } else if(!strcmp(name, "error")){
3010 rv = tclistnew2(1);
3011 int ecode = tctdbecode(adb->tdb);
3012 tclistprintf(rv, "%d: %s", ecode, tctdberrmsg(ecode));
3013 uint8_t flags = tctdbflags(adb->tdb);
3014 if(flags & TDBFFATAL) tclistprintf(rv, "fatal");
3015 } else if(!strcmp(name, "defrag")){
3016 rv = tclistnew2(1);
3017 int64_t step = argc > 0 ? tcatoi(TCLISTVALPTR(args, 0)) : -1;
3018 if(!tctdbdefrag(adb->tdb, step)){
3019 tclistdel(rv);
3020 rv = NULL;
3021 }
3022 } else if(!strcmp(name, "cacheclear")){
3023 rv = tclistnew2(1);
3024 if(!tctdbcacheclear(adb->tdb)){
3025 tclistdel(rv);
3026 rv = NULL;
3027 }
3028 } else if(!strcmp(name, "regex")){
3029 if(argc > 0){
3030 const char *regex = TCLISTVALPTR(args, 0);
3031 int options = REG_EXTENDED | REG_NOSUB;
3032 if(*regex == '*'){
3033 options |= REG_ICASE;
3034 regex++;
3035 }
3036 regex_t rbuf;
3037 if(regcomp(&rbuf, regex, options) == 0){
3038 rv = tclistnew();
3039 int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
3040 if(max < 1) max = INT_MAX;
3041 tctdbiterinit(adb->tdb);
3042 char *kbuf;
3043 int ksiz;
3044 while(max > 0 && (kbuf = tctdbiternext(adb->tdb, &ksiz))){
3045 if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
3046 int vsiz;
3047 char *vbuf = tctdbget2(adb->tdb, kbuf, ksiz, &vsiz);
3048 if(vbuf){
3049 TCLISTPUSH(rv, kbuf, ksiz);
3050 TCLISTPUSH(rv, vbuf, vsiz);
3051 TCFREE(vbuf);
3052 max--;
3053 }
3054 }
3055 TCFREE(kbuf);
3056 }
3057 regfree(&rbuf);
3058 } else {
3059 rv = NULL;
3060 }
3061 } else {
3062 rv = NULL;
3063 }
3064 } else if(!strcmp(name, "setindex")){
3065 rv = tclistnew2(1);
3066 bool err = false;
3067 argc--;
3068 for(int i = 0; i < argc; i += 2){
3069 const char *kbuf, *vbuf;
3070 kbuf = TCLISTVALPTR(args, i);
3071 vbuf = TCLISTVALPTR(args, i + 1);
3072 int type = tctdbstrtoindextype(vbuf);
3073 if(type >= 0){
3074 if(!tctdbsetindex(adb->tdb, kbuf, type)) err = true;
3075 } else {
3076 err = true;
3077 }
3078 }
3079 if(err){
3080 tclistdel(rv);
3081 rv = NULL;
3082 }
3083 } else if(!strcmp(name, "search") || !strcmp(name, "metasearch")){
3084 bool toout = false;
3085 bool tocnt = false;
3086 bool tohint = false;
3087 TDBQRY *qry = tctdbqrynew(adb->tdb);
3088 TDBQRY **qrys = NULL;
3089 int qnum = 0;
3090 int mstype = TDBMSUNION;
3091 TCLIST *cnames = NULL;
3092 for(int i = 0; i < argc; i++){
3093 const char *arg;
3094 int asiz;
3095 TCLISTVAL(arg, args, i, asiz);
3096 TCLIST *tokens = tcstrsplit2(arg, asiz);
3097 int tnum = TCLISTNUM(tokens);
3098 if(tnum > 0){
3099 const char *cmd = TCLISTVALPTR(tokens, 0);
3100 if((!strcmp(cmd, "addcond") || !strcmp(cmd, "cond")) && tnum > 3){
3101 const char *name = TCLISTVALPTR(tokens, 1);
3102 const char *opstr = TCLISTVALPTR(tokens, 2);
3103 const char *expr = TCLISTVALPTR(tokens, 3);
3104 int op = tctdbqrystrtocondop(opstr);
3105 if(op >= 0) tctdbqryaddcond(qry, name, op, expr);
3106 } else if((!strcmp(cmd, "setorder") || !strcmp(cmd, "order")) && tnum > 2){
3107 const char *name = TCLISTVALPTR(tokens, 1);
3108 const char *typestr = TCLISTVALPTR(tokens, 2);
3109 int type = tctdbqrystrtoordertype(typestr);
3110 if(type >= 0) tctdbqrysetorder(qry, name, type);
3111 } else if((!strcmp(cmd, "setlimit") || !strcmp(cmd, "limit") ||
3112 !strcmp(cmd, "setmax") || !strcmp(cmd, "max") ) && tnum > 1){
3113 const char *maxstr = TCLISTVALPTR(tokens, 1);
3114 int max = tcatoi(maxstr);
3115 int skip = 0;
3116 if(tnum > 2){
3117 maxstr = TCLISTVALPTR(tokens, 2);
3118 skip = tcatoi(maxstr);
3119 }
3120 tctdbqrysetlimit(qry, max, skip);
3121 } else if(!strcmp(cmd, "get") || !strcmp(cmd, "columns")){
3122 if(!cnames) cnames = tclistnew();
3123 for(int j = 1; j < tnum; j++){
3124 const char *token;
3125 int tsiz;
3126 TCLISTVAL(token, tokens, j, tsiz);
3127 TCLISTPUSH(cnames, token, tsiz);
3128 }
3129 } else if(!strcmp(cmd, "next")){
3130 if(qrys){
3131 TCREALLOC(qrys, qrys, sizeof(*qrys) * (qnum + 1));
3132 } else {
3133 TCMALLOC(qrys, sizeof(*qrys) * 2);
3134 qrys[0] = qry;
3135 qnum = 1;
3136 }
3137 qry = tctdbqrynew(adb->tdb);
3138 qrys[qnum++] = qry;
3139 } else if(!strcmp(cmd, "mstype") && tnum > 1){
3140 const char *typestr = TCLISTVALPTR(tokens, 1);
3141 mstype = tctdbstrtometasearcytype(typestr);
3142 if(mstype < 0) mstype = TDBMSUNION;
3143 } else if(!strcmp(cmd, "out") || !strcmp(cmd, "remove")){
3144 toout = true;
3145 } else if(!strcmp(cmd, "count")){
3146 tocnt = true;
3147 } else if(!strcmp(cmd, "hint")){
3148 tohint = true;
3149 }
3150 }
3151 tclistdel(tokens);
3152 }
3153 if(toout){
3154 if(cnames){
3155 rv = tclistnew2(1);
3156 void *opq[2];
3157 opq[0] = rv;
3158 opq[1] = cnames;
3159 if(!tctdbqryproc2(qry, tcadbtdbqrygetout, opq)){
3160 tclistdel(rv);
3161 rv = NULL;
3162 }
3163 } else {
3164 if(tctdbqrysearchout2(qry)){
3165 rv = tclistnew2(1);
3166 } else {
3167 rv = NULL;
3168 }
3169 }
3170 } else {
3171 if(qrys){
3172 rv = tctdbmetasearch(qrys, qnum, mstype);
3173 } else {
3174 rv = tctdbqrysearch(qry);
3175 }
3176 if(cnames){
3177 int cnnum = TCLISTNUM(cnames);
3178 int rnum = TCLISTNUM(rv);
3179 TCLIST *nrv = tclistnew2(rnum);
3180 for(int i = 0; i < rnum; i++){
3181 const char *pkbuf;
3182 int pksiz;
3183 TCLISTVAL(pkbuf, rv, i, pksiz);
3184 TCMAP *cols = tctdbget(adb->tdb, pkbuf, pksiz);
3185 if(cols){
3186 tcmapput(cols, "", 0, pkbuf, pksiz);
3187 tcmapmove(cols, "", 0, true);
3188 if(cnnum > 0){
3189 TCMAP *ncols = tcmapnew2(cnnum + 1);
3190 for(int j = 0; j < cnnum; j++){
3191 const char *cname;
3192 int cnsiz;
3193 TCLISTVAL(cname, cnames, j, cnsiz);
3194 int cvsiz;
3195 const char *cvalue = tcmapget(cols, cname, cnsiz, &cvsiz);
3196 if(cvalue) tcmapput(ncols, cname, cnsiz, cvalue, cvsiz);
3197 }
3198 tcmapdel(cols);
3199 cols = ncols;
3200 }
3201 int csiz;
3202 char *cbuf = tcstrjoin4(cols, &csiz);
3203 tclistpushmalloc(nrv, cbuf, csiz);
3204 tcmapdel(cols);
3205 }
3206 }
3207 tclistdel(rv);
3208 rv = nrv;
3209 }
3210 }
3211 if(tocnt && rv){
3212 tclistclear(rv);
3213 char numbuf[TCNUMBUFSIZ];
3214 int len = sprintf(numbuf, "%d", tctdbqrycount(qry));
3215 TCLISTPUSH(rv, numbuf, len);
3216 }
3217 if(tohint && rv){
3218 TCXSTR *hbuf = tcxstrnew();
3219 TCXSTRCAT(hbuf, "", 1);
3220 TCXSTRCAT(hbuf, "", 1);
3221 TCXSTRCAT(hbuf, "[[HINT]]\n", 9);
3222 const char *hint = tctdbqryhint(qrys ? qrys[0] : qry);
3223 TCXSTRCAT(hbuf, hint, strlen(hint));
3224 TCLISTPUSH(rv, TCXSTRPTR(hbuf), TCXSTRSIZE(hbuf));
3225 tcxstrdel(hbuf);
3226 }
3227 if(cnames) tclistdel(cnames);
3228 if(qrys){
3229 for(int i = 0; i < qnum; i++){
3230 tctdbqrydel(qrys[i]);
3231 }
3232 TCFREE(qrys);
3233 } else {
3234 tctdbqrydel(qry);
3235 }
3236 } else if(!strcmp(name, "genuid")){
3237 rv = tclistnew2(1);
3238 char numbuf[TCNUMBUFSIZ];
3239 int nsiz = sprintf(numbuf, "%lld", (long long)tctdbgenuid(adb->tdb));
3240 TCLISTPUSH(rv, numbuf, nsiz);
3241 } else {
3242 rv = NULL;
3243 }
3244 break;
3245 case ADBOSKEL:
3246 skel = adb->skel;
3247 if(skel->misc){
3248 rv = skel->misc(skel->opq, name, args);
3249 } else {
3250 rv = NULL;
3251 }
3252 break;
3253 default:
3254 rv = NULL;
3255 break;
3256 }
3257 return rv;
3258 }
3259
3260
3261
3262 /*************************************************************************************************
3263 * features for experts
3264 *************************************************************************************************/
3265
3266
3267 /* Set an extra database sleleton to an abstract database object. */
tcadbsetskel(TCADB * adb,ADBSKEL * skel)3268 bool tcadbsetskel(TCADB *adb, ADBSKEL *skel){
3269 assert(skel);
3270 if(adb->omode != ADBOVOID) return false;
3271 if(adb->skel) TCFREE(adb->skel);
3272 adb->skel = tcmemdup(skel, sizeof(*skel));
3273 return true;
3274 }
3275
3276
3277 /* Set the multiple database skeleton to an abstract database object. */
tcadbsetskelmulti(TCADB * adb,int num)3278 bool tcadbsetskelmulti(TCADB *adb, int num){
3279 assert(adb && num >= 0);
3280 if(adb->omode != ADBOVOID) return false;
3281 if(num < 1) return false;
3282 if(num > CHAR_MAX) num = CHAR_MAX;
3283 ADBMUL *mul = tcadbmulnew(num);
3284 ADBSKEL skel;
3285 memset(&skel, 0, sizeof(skel));
3286 skel.opq = mul;
3287 skel.del = (void (*)(void *))tcadbmuldel;
3288 skel.open = (bool (*)(void *, const char *))tcadbmulopen;
3289 skel.close = (bool (*)(void *))tcadbmulclose;
3290 skel.put = (bool (*)(void *, const void *, int, const void *, int))tcadbmulput;
3291 skel.putkeep = (bool (*)(void *, const void *, int, const void *, int))tcadbmulputkeep;
3292 skel.putcat = (bool (*)(void *, const void *, int, const void *, int))tcadbmulputcat;
3293 skel.out = (bool (*)(void *, const void *, int))tcadbmulout;
3294 skel.get = (void *(*)(void *, const void *, int, int *))tcadbmulget;
3295 skel.vsiz = (int (*)(void *, const void *, int))tcadbmulvsiz;
3296 skel.iterinit = (bool (*)(void *))tcadbmuliterinit;
3297 skel.iternext = (void *(*)(void *, int *))tcadbmuliternext;
3298 skel.fwmkeys = (TCLIST *(*)(void *, const void *, int, int))tcadbmulfwmkeys;
3299 skel.addint = (int (*)(void *, const void *, int, int))tcadbmuladdint;
3300 skel.adddouble = (double (*)(void *, const void *, int, double))tcadbmuladddouble;
3301 skel.sync = (bool (*)(void *))tcadbmulsync;
3302 skel.optimize = (bool (*)(void *, const char *))tcadbmuloptimize;
3303 skel.vanish = (bool (*)(void *))tcadbmulvanish;
3304 skel.copy = (bool (*)(void *, const char *))tcadbmulcopy;
3305 skel.tranbegin = (bool (*)(void *))tcadbmultranbegin;
3306 skel.trancommit = (bool (*)(void *))tcadbmultrancommit;
3307 skel.tranabort = (bool (*)(void *))tcadbmultranabort;
3308 skel.path = (const char *(*)(void *))tcadbmulpath;
3309 skel.rnum = (uint64_t (*)(void *))tcadbmulrnum;
3310 skel.size = (uint64_t (*)(void *))tcadbmulsize;
3311 skel.misc = (TCLIST *(*)(void *, const char *, const TCLIST *))tcadbmulmisc;
3312 skel.putproc =
3313 (bool (*)(void *, const void *, int, const void *, int, TCPDPROC, void *))tcadbmulputproc;
3314 skel.foreach = (bool (*)(void *, TCITER, void *))tcadbmulforeach;
3315 if(!tcadbsetskel(adb, &skel)){
3316 tcadbmuldel(mul);
3317 return false;
3318 }
3319 return true;
3320 }
3321
3322
3323 /* Get the open mode of an abstract database object. */
tcadbomode(TCADB * adb)3324 int tcadbomode(TCADB *adb){
3325 assert(adb);
3326 return adb->omode;
3327 }
3328
3329
3330 /* Get the concrete database object of an abstract database object. */
tcadbreveal(TCADB * adb)3331 void *tcadbreveal(TCADB *adb){
3332 assert(adb);
3333 void *rv;
3334 switch(adb->omode){
3335 case ADBOMDB:
3336 rv = adb->mdb;
3337 break;
3338 case ADBONDB:
3339 rv = adb->ndb;
3340 break;
3341 case ADBOHDB:
3342 rv = adb->hdb;
3343 break;
3344 case ADBOBDB:
3345 rv = adb->bdb;
3346 break;
3347 case ADBOFDB:
3348 rv = adb->fdb;
3349 break;
3350 case ADBOTDB:
3351 rv = adb->tdb;
3352 break;
3353 case ADBOSKEL:
3354 rv = adb->skel;
3355 break;
3356 default:
3357 rv = NULL;
3358 break;
3359 }
3360 return rv;
3361 }
3362
3363
3364 /* Store a record into an abstract database object with a duplication handler. */
tcadbputproc(TCADB * adb,const void * kbuf,int ksiz,const void * vbuf,int vsiz,TCPDPROC proc,void * op)3365 bool tcadbputproc(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz,
3366 TCPDPROC proc, void *op){
3367 assert(adb && kbuf && ksiz >= 0 && proc);
3368 bool err = false;
3369 ADBSKEL *skel;
3370 switch(adb->omode){
3371 case ADBOMDB:
3372 if(tcmdbputproc(adb->mdb, kbuf, ksiz, vbuf, vsiz, proc, op)){
3373 if(adb->capnum > 0 || adb->capsiz > 0){
3374 adb->capcnt++;
3375 if((adb->capcnt & 0xff) == 0){
3376 if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
3377 tcmdbcutfront(adb->mdb, 0x100);
3378 if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
3379 tcmdbcutfront(adb->mdb, 0x200);
3380 }
3381 }
3382 } else {
3383 err = true;
3384 }
3385 break;
3386 case ADBONDB:
3387 if(tcndbputproc(adb->ndb, kbuf, ksiz, vbuf, vsiz, proc, op)){
3388 if(adb->capnum > 0 || adb->capsiz > 0){
3389 adb->capcnt++;
3390 if((adb->capcnt & 0xff) == 0){
3391 if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum + 0x100)
3392 tcndbcutfringe(adb->ndb, 0x100);
3393 if(adb->capsiz > 0 && tcndbmsiz(adb->ndb) > adb->capsiz)
3394 tcndbcutfringe(adb->ndb, 0x200);
3395 }
3396 }
3397 } else {
3398 err = true;
3399 }
3400 break;
3401 case ADBOHDB:
3402 if(!tchdbputproc(adb->hdb, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3403 break;
3404 case ADBOBDB:
3405 if(!tcbdbputproc(adb->bdb, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3406 break;
3407 case ADBOFDB:
3408 if(!tcfdbputproc(adb->fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz, proc, op)) err = true;
3409 break;
3410 case ADBOTDB:
3411 if(!tctdbputproc(adb->tdb, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3412 break;
3413 case ADBOSKEL:
3414 skel = adb->skel;
3415 if(skel->putproc){
3416 if(!skel->putproc(skel->opq, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3417 } else {
3418 err = true;
3419 }
3420 break;
3421 default:
3422 err = true;
3423 break;
3424 }
3425 return !err;
3426 }
3427
3428
3429 /* Process each record atomically of an abstract database object. */
tcadbforeach(TCADB * adb,TCITER iter,void * op)3430 bool tcadbforeach(TCADB *adb, TCITER iter, void *op){
3431 assert(adb && iter);
3432 bool err = false;
3433 ADBSKEL *skel;
3434 switch(adb->omode){
3435 case ADBOMDB:
3436 tcmdbforeach(adb->mdb, iter, op);
3437 break;
3438 case ADBONDB:
3439 tcndbforeach(adb->ndb, iter, op);
3440 break;
3441 case ADBOHDB:
3442 if(!tchdbforeach(adb->hdb, iter, op)) err = true;
3443 break;
3444 case ADBOBDB:
3445 if(!tcbdbforeach(adb->bdb, iter, op)) err = true;
3446 break;
3447 case ADBOFDB:
3448 if(!tcfdbforeach(adb->fdb, iter, op)) err = true;
3449 break;
3450 case ADBOTDB:
3451 if(!tctdbforeach(adb->tdb, iter, op)) err = true;
3452 break;
3453 case ADBOSKEL:
3454 skel = adb->skel;
3455 if(skel->foreach){
3456 if(!skel->foreach(skel->opq, iter, op)) err = true;
3457 } else {
3458 err = true;
3459 }
3460 break;
3461 default:
3462 err = true;
3463 break;
3464 }
3465 return !err;
3466 }
3467
3468
3469 /* Map records of an abstract database object into another B+ tree database. */
tcadbmapbdb(TCADB * adb,TCLIST * keys,TCBDB * bdb,ADBMAPPROC proc,void * op,int64_t csiz)3470 bool tcadbmapbdb(TCADB *adb, TCLIST *keys, TCBDB *bdb, ADBMAPPROC proc, void *op, int64_t csiz){
3471 assert(adb && bdb && proc);
3472 if(csiz < 0) csiz = 256LL << 20;
3473 TCLIST *recs = tclistnew2(tclmin(csiz / 64 + 256, INT_MAX / 4));
3474 ADBMAPBDB map;
3475 map.adb = adb;
3476 map.bdb = bdb;
3477 map.recs = recs;
3478 map.proc = proc;
3479 map.op = op;
3480 map.rsiz = 0;
3481 map.csiz = csiz;
3482 bool err = false;
3483 if(keys){
3484 int knum = TCLISTNUM(keys);
3485 for(int i = 0; i < knum && !err; i++){
3486 const char *kbuf;
3487 int ksiz;
3488 TCLISTVAL(kbuf, keys, i, ksiz);
3489 int vsiz;
3490 char *vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
3491 if(vbuf){
3492 if(!tcadbmapbdbiter(kbuf, ksiz, vbuf, vsiz, &map)) err = true;
3493 TCFREE(vbuf);
3494 if(map.rsiz > map.csiz && !tcadbmapbdbdump(&map)) err = true;
3495 }
3496 if(map.rsiz > 0 && !tcadbmapbdbdump(&map)) err = true;
3497 }
3498 } else {
3499 if(!tcadbforeach(adb, tcadbmapbdbiter, &map)) err = true;
3500 }
3501 if(map.rsiz > 0 && !tcadbmapbdbdump(&map)) err = true;
3502 tclistdel(recs);
3503 return !err;
3504 }
3505
3506
3507 /* Emit records generated by the mapping function into the result map. */
tcadbmapbdbemit(void * map,const char * kbuf,int ksiz,const char * vbuf,int vsiz)3508 bool tcadbmapbdbemit(void *map, const char *kbuf, int ksiz, const char *vbuf, int vsiz){
3509 assert(map && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3510 ADBMAPBDB *mymap = map;
3511 int rsiz = sizeof(ksiz) + ksiz + vsiz;
3512 char stack[TCNUMBUFSIZ*8];
3513 char *rbuf;
3514 if(rsiz <= sizeof(stack)){
3515 rbuf = stack;
3516 } else {
3517 TCMALLOC(rbuf, rsiz);
3518 }
3519 bool err = false;
3520 char *wp = rbuf;
3521 memcpy(wp, &ksiz, sizeof(ksiz));
3522 wp += sizeof(ksiz);
3523 memcpy(wp, kbuf, ksiz);
3524 wp += ksiz;
3525 memcpy(wp, vbuf, vsiz);
3526 TCLISTPUSH(mymap->recs, rbuf, rsiz);
3527 mymap->rsiz += rsiz + sizeof(TCLISTDATUM);
3528 if(rbuf != stack) TCFREE(rbuf);
3529 if(mymap->rsiz > mymap->csiz && !tcadbmapbdbdump(map)) err = true;
3530 return !err;
3531 }
3532
3533
3534
3535 /*************************************************************************************************
3536 * private features
3537 *************************************************************************************************/
3538
3539
3540 /* Create a multiple database object.
3541 `num' specifies the number of inner databases.
3542 The return value is the new multiple database object. */
tcadbmulnew(int num)3543 static ADBMUL *tcadbmulnew(int num){
3544 assert(num > 0);
3545 ADBMUL *mul;
3546 TCMALLOC(mul, sizeof(*mul));
3547 mul->adbs = NULL;
3548 mul->num = num;
3549 mul->iter = -1;
3550 mul->path = NULL;
3551 return mul;
3552 }
3553
3554
3555 /* Delete a multiple database object.
3556 `mul' specifies the multiple database object. */
tcadbmuldel(ADBMUL * mul)3557 static void tcadbmuldel(ADBMUL *mul){
3558 assert(mul);
3559 if(mul->adbs) tcadbmulclose(mul);
3560 TCFREE(mul);
3561 }
3562
3563
3564 /* Open a multiple database.
3565 `mul' specifies the multiple database object.
3566 If successful, the return value is true, else, it is false. */
tcadbmulopen(ADBMUL * mul,const char * name)3567 static bool tcadbmulopen(ADBMUL *mul, const char *name){
3568 assert(mul && name);
3569 if(mul->adbs) return false;
3570 mul->iter = -1;
3571 TCLIST *elems = tcstrsplit(name, "#");
3572 char *path = tclistshift2(elems);
3573 if(!path){
3574 tclistdel(elems);
3575 return false;
3576 }
3577 const char *ext = strrchr(path, MYEXTCHR);
3578 if(!ext) ext = "";
3579 const char *params = strchr(name, '#');
3580 if(!params) params = "";
3581 bool owmode = true;
3582 bool ocmode = true;
3583 bool otmode = false;
3584 int ln = TCLISTNUM(elems);
3585 for(int i = 0; i < ln; i++){
3586 const char *elem = TCLISTVALPTR(elems, i);
3587 char *pv = strchr(elem, '=');
3588 if(!pv) continue;
3589 *(pv++) = '\0';
3590 if(!tcstricmp(elem, "mode")){
3591 owmode = strchr(pv, 'w') || strchr(pv, 'W');
3592 ocmode = strchr(pv, 'c') || strchr(pv, 'C');
3593 otmode = strchr(pv, 't') || strchr(pv, 'T');
3594 }
3595 }
3596 tclistdel(elems);
3597 bool err = false;
3598 char *gpat = tcsprintf("%s%c%s*%s", path, MYPATHCHR, ADBMULPREFIX, ext);
3599 TCLIST *cpaths = tcglobpat(gpat);
3600 tclistsort(cpaths);
3601 int cnum = TCLISTNUM(cpaths);
3602 if(owmode){
3603 if(otmode){
3604 for(int i = 0; i < cnum; i++){
3605 const char *cpath = TCLISTVALPTR(cpaths, i);
3606 if(unlink(cpath) != 0) err = true;
3607 }
3608 tclistclear(cpaths);
3609 cnum = 0;
3610 }
3611 if(ocmode && cnum < 1){
3612 if(mkdir(path, ADBDIRMODE) != 0 && errno != EEXIST){
3613 err = true;
3614 } else {
3615 for(int i = 0; i < mul->num; i++){
3616 tclistprintf(cpaths, "%s%c%s%03d%s", path, MYPATHCHR, ADBMULPREFIX, i + 1, ext);
3617 }
3618 cnum = TCLISTNUM(cpaths);
3619 }
3620 }
3621 }
3622 if(!err && cnum > 0){
3623 TCADB **adbs;
3624 TCMALLOC(adbs, sizeof(*adbs) * cnum);
3625 for(int i = 0; i < cnum; i++){
3626 TCADB *adb = tcadbnew();
3627 const char *cpath = TCLISTVALPTR(cpaths, i);
3628 char *cname = tcsprintf("%s%s", cpath, params);
3629 if(!tcadbopen(adb, cname)) err = true;
3630 TCFREE(cname);
3631 adbs[i] = adb;
3632 }
3633 if(err){
3634 for(int i = cnum - 1; i >= 0; i--){
3635 tcadbdel(adbs[i]);
3636 }
3637 TCFREE(adbs);
3638 } else {
3639 mul->adbs = adbs;
3640 mul->num = cnum;
3641 mul->path = path;
3642 path = NULL;
3643 }
3644 }
3645 tclistdel(cpaths);
3646 TCFREE(gpat);
3647 TCFREE(path);
3648 return !err;
3649 }
3650
3651
3652 /* Close a multiple database object.
3653 `mul' specifies the multiple database object.
3654 If successful, the return value is true, else, it is false. */
tcadbmulclose(ADBMUL * mul)3655 static bool tcadbmulclose(ADBMUL *mul){
3656 assert(mul);
3657 if(!mul->adbs) return false;
3658 TCADB **adbs = mul->adbs;
3659 int num = mul->num;
3660 bool err = false;
3661 for(int i = num - 1; i >= 0; i--){
3662 TCADB *adb = adbs[i];
3663 if(!tcadbclose(adb)) err = true;
3664 tcadbdel(adb);
3665 }
3666 TCFREE(mul->path);
3667 TCFREE(adbs);
3668 mul->adbs = NULL;
3669 mul->path = NULL;
3670 return !err;
3671 }
3672
3673
3674 /* Store a record into a multiple database object.
3675 `mul' specifies the multiple database object.
3676 `kbuf' specifies the pointer to the region of the key.
3677 `ksiz' specifies the size of the region of the key.
3678 `vbuf' specifies the pointer to the region of the value.
3679 `vsiz' specifies the size of the region of the value.
3680 If successful, the return value is true, else, it is false. */
tcadbmulput(ADBMUL * mul,const void * kbuf,int ksiz,const void * vbuf,int vsiz)3681 static bool tcadbmulput(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
3682 assert(mul && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3683 if(!mul->adbs) return false;
3684 int idx = tcadbmulidx(mul, kbuf, ksiz);
3685 TCADB *adb = mul->adbs[idx];
3686 return tcadbput(adb, kbuf, ksiz, vbuf, vsiz);
3687 }
3688
3689
3690 /* Store a new record into a multiple database object.
3691 `mul' specifies the multiple database object.
3692 `kbuf' specifies the pointer to the region of the key.
3693 `ksiz' specifies the size of the region of the key.
3694 `vbuf' specifies the pointer to the region of the value.
3695 `vsiz' specifies the size of the region of the value.
3696 If successful, the return value is true, else, it is false. */
tcadbmulputkeep(ADBMUL * mul,const void * kbuf,int ksiz,const void * vbuf,int vsiz)3697 static bool tcadbmulputkeep(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
3698 assert(mul && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3699 if(!mul->adbs) return false;
3700 int idx = tcadbmulidx(mul, kbuf, ksiz);
3701 TCADB *adb = mul->adbs[idx];
3702 return tcadbputkeep(adb, kbuf, ksiz, vbuf, vsiz);
3703 }
3704
3705
3706 /* Concatenate a value at the end of the existing record in a multiple database object.
3707 `mul' specifies the multiple database object.
3708 `kbuf' specifies the pointer to the region of the key.
3709 `ksiz' specifies the size of the region of the key.
3710 `vbuf' specifies the pointer to the region of the value.
3711 `vsiz' specifies the size of the region of the value.
3712 If successful, the return value is true, else, it is false. */
tcadbmulputcat(ADBMUL * mul,const void * kbuf,int ksiz,const void * vbuf,int vsiz)3713 static bool tcadbmulputcat(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
3714 assert(mul && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3715 if(!mul->adbs) return false;
3716 int idx = tcadbmulidx(mul, kbuf, ksiz);
3717 TCADB *adb = mul->adbs[idx];
3718 return tcadbputcat(adb, kbuf, ksiz, vbuf, vsiz);
3719 }
3720
3721
3722 /* Remove a record of a multiple database object.
3723 `mul' specifies the multiple database object.
3724 `kbuf' specifies the pointer to the region of the key.
3725 `ksiz' specifies the size of the region of the key.
3726 If successful, the return value is true, else, it is false. */
tcadbmulout(ADBMUL * mul,const void * kbuf,int ksiz)3727 static bool tcadbmulout(ADBMUL *mul, const void *kbuf, int ksiz){
3728 assert(mul && kbuf && ksiz >= 0);
3729 if(!mul->adbs) return false;
3730 int idx = tcadbmulidx(mul, kbuf, ksiz);
3731 TCADB *adb = mul->adbs[idx];
3732 return tcadbout(adb, kbuf, ksiz);
3733 }
3734
3735
3736 /* Retrieve a record in a multiple database object.
3737 `mul' specifies the multiple database object.
3738 `kbuf' specifies the pointer to the region of the key.
3739 `ksiz' specifies the size of the region of the key.
3740 `sp' specifies the pointer to the variable into which the size of the region of the return
3741 value is assigned.
3742 If successful, the return value is the pointer to the region of the value of the corresponding
3743 record. */
tcadbmulget(ADBMUL * mul,const void * kbuf,int ksiz,int * sp)3744 static void *tcadbmulget(ADBMUL *mul, const void *kbuf, int ksiz, int *sp){
3745 assert(mul && kbuf && ksiz >= 0 && sp);
3746 if(!mul->adbs) return false;
3747 int idx = tcadbmulidx(mul, kbuf, ksiz);
3748 TCADB *adb = mul->adbs[idx];
3749 return tcadbget(adb, kbuf, ksiz, sp);
3750 }
3751
3752
3753 /* Get the size of the value of a record in a multiple database object.
3754 `mul' specifies the multiple database object.
3755 `kbuf' specifies the pointer to the region of the key.
3756 `ksiz' specifies the size of the region of the key.
3757 If successful, the return value is the size of the value of the corresponding record, else,
3758 it is -1. */
tcadbmulvsiz(ADBMUL * mul,const void * kbuf,int ksiz)3759 static int tcadbmulvsiz(ADBMUL *mul, const void *kbuf, int ksiz){
3760 assert(mul && kbuf && ksiz >= 0);
3761 if(!mul->adbs) return false;
3762 int idx = tcadbmulidx(mul, kbuf, ksiz);
3763 TCADB *adb = mul->adbs[idx];
3764 return tcadbvsiz(adb, kbuf, ksiz);
3765 }
3766
3767
3768 /* Initialize the iterator of a multiple database object.
3769 `mul' specifies the multiple database object.
3770 If successful, the return value is true, else, it is false. */
tcadbmuliterinit(ADBMUL * mul)3771 static bool tcadbmuliterinit(ADBMUL *mul){
3772 assert(mul);
3773 if(!mul->adbs) return false;
3774 mul->iter = -1;
3775 TCADB **adbs = mul->adbs;
3776 int num = mul->num;
3777 bool err = false;
3778 for(int i = 0; i < num; i++){
3779 if(!tcadbiterinit(adbs[i])) err = true;
3780 }
3781 if(err) return false;
3782 mul->iter = 0;
3783 return true;
3784 }
3785
3786
3787 /* Get the next key of the iterator of a multiple database object.
3788 `mul' specifies the multiple database object.
3789 `sp' specifies the pointer to the variable into which the size of the region of the return
3790 value is assigned.
3791 If successful, the return value is the pointer to the region of the next key, else, it is
3792 `NULL'. */
tcadbmuliternext(ADBMUL * mul,int * sp)3793 static void *tcadbmuliternext(ADBMUL *mul, int *sp){
3794 assert(mul && sp);
3795 if(!mul->adbs || mul->iter < 0) return false;
3796 while(mul->iter < mul->num){
3797 TCADB *adb = mul->adbs[mul->iter];
3798 char *rv = tcadbiternext(adb, sp);
3799 if(rv) return rv;
3800 mul->iter++;
3801 }
3802 mul->iter = -1;
3803 return NULL;
3804 }
3805
3806
3807 /* Get forward matching keys in a multiple database object.
3808 `mul' specifies the multiple database object.
3809 `pbuf' specifies the pointer to the region of the prefix.
3810 `psiz' specifies the size of the region of the prefix.
3811 `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is
3812 specified.
3813 The return value is a list object of the corresponding keys. */
tcadbmulfwmkeys(ADBMUL * mul,const void * pbuf,int psiz,int max)3814 static TCLIST *tcadbmulfwmkeys(ADBMUL *mul, const void *pbuf, int psiz, int max){
3815 assert(mul && pbuf && psiz >= 0);
3816 if(!mul->adbs) return tclistnew2(1);
3817 if(max < 0) max = INT_MAX;
3818 TCADB **adbs = mul->adbs;
3819 int num = mul->num;
3820 TCLIST *rv = tclistnew();
3821 for(int i = 0; i < num && TCLISTNUM(rv) < max; i++){
3822 TCLIST *res = tcadbfwmkeys(adbs[i], pbuf, psiz, max);
3823 int rnum = TCLISTNUM(res);
3824 for(int j = 0; j < rnum && TCLISTNUM(rv) < max; j++){
3825 const char *vbuf;
3826 int vsiz;
3827 TCLISTVAL(vbuf, res, j, vsiz);
3828 TCLISTPUSH(rv, vbuf, vsiz);
3829 }
3830 tclistdel(res);
3831 }
3832 return rv;
3833 }
3834
3835
3836 /* Add an integer to a record in a multiple database object.
3837 `mul' specifies the multiple database object.
3838 `kbuf' specifies the pointer to the region of the key.
3839 `ksiz' specifies the size of the region of the key.
3840 `num' specifies the additional value.
3841 If successful, the return value is the summation value, else, it is `INT_MIN'. */
tcadbmuladdint(ADBMUL * mul,const void * kbuf,int ksiz,int num)3842 static int tcadbmuladdint(ADBMUL *mul, const void *kbuf, int ksiz, int num){
3843 assert(mul && kbuf && ksiz >= 0);
3844 if(!mul->adbs) return INT_MIN;
3845 int idx = tcadbmulidx(mul, kbuf, ksiz);
3846 TCADB *adb = mul->adbs[idx];
3847 return tcadbaddint(adb, kbuf, ksiz, num);
3848 }
3849
3850
3851 /* Add a real number to a record in a multiple database object.
3852 `mul' specifies the multiple database object.
3853 `kbuf' specifies the pointer to the region of the key.
3854 `ksiz' specifies the size of the region of the key.
3855 `num' specifies the additional value.
3856 If successful, the return value is the summation value, else, it is Not-a-Number. */
tcadbmuladddouble(ADBMUL * mul,const void * kbuf,int ksiz,double num)3857 static double tcadbmuladddouble(ADBMUL *mul, const void *kbuf, int ksiz, double num){
3858 assert(mul && kbuf && ksiz >= 0);
3859 if(!mul->adbs) return nan("");
3860 int idx = tcadbmulidx(mul, kbuf, ksiz);
3861 TCADB *adb = mul->adbs[idx];
3862 return tcadbadddouble(adb, kbuf, ksiz, num);
3863 }
3864
3865
3866 /* Synchronize updated contents of a multiple database object with the file and the device.
3867 `mul' specifies the multiple database object.
3868 If successful, the return value is true, else, it is false. */
tcadbmulsync(ADBMUL * mul)3869 static bool tcadbmulsync(ADBMUL *mul){
3870 assert(mul);
3871 if(!mul->adbs) return false;
3872 TCADB **adbs = mul->adbs;
3873 int num = mul->num;
3874 bool err = false;
3875 for(int i = 0; i < num; i++){
3876 if(!tcadbsync(adbs[i])) err = true;
3877 }
3878 return !err;
3879 }
3880
3881
3882 /* Optimize the storage of a multiple database object.
3883 `mul' specifies the multiple database object.
3884 `params' specifies the string of the tuning parameters, which works as with the tuning
3885 of parameters the function `tcadbmulopen'.
3886 If successful, the return value is true, else, it is false. */
tcadbmuloptimize(ADBMUL * mul,const char * params)3887 static bool tcadbmuloptimize(ADBMUL *mul, const char *params){
3888 assert(mul);
3889 if(!mul->adbs) return false;
3890 mul->iter = -1;
3891 TCADB **adbs = mul->adbs;
3892 int num = mul->num;
3893 bool err = false;
3894 for(int i = 0; i < num; i++){
3895 if(!tcadboptimize(adbs[i], params)) err = true;
3896 }
3897 return !err;
3898 }
3899
3900
3901 /* Remove all records of a multiple database object.
3902 `mul' specifies the multiple database object.
3903 If successful, the return value is true, else, it is false. */
tcadbmulvanish(ADBMUL * mul)3904 static bool tcadbmulvanish(ADBMUL *mul){
3905 assert(mul);
3906 if(!mul->adbs) return false;
3907 mul->iter = -1;
3908 TCADB **adbs = mul->adbs;
3909 int num = mul->num;
3910 bool err = false;
3911 for(int i = 0; i < num; i++){
3912 if(!tcadbvanish(adbs[i])) err = true;
3913 }
3914 return !err;
3915 }
3916
3917
3918 /* Copy the database file of a multiple database object.
3919 `mul' specifies the multiple database object.
3920 `path' specifies the path of the destination file.
3921 If successful, the return value is true, else, it is false. False is returned if the executed
3922 command returns non-zero code. */
tcadbmulcopy(ADBMUL * mul,const char * path)3923 static bool tcadbmulcopy(ADBMUL *mul, const char *path){
3924 assert(mul && path);
3925 TCADB **adbs = mul->adbs;
3926 int num = mul->num;
3927 bool err = false;
3928 if(*path == '@'){
3929 for(int i = 0; i < num; i++){
3930 if(!tcadbcopy(adbs[i], path)) err = true;
3931 }
3932 } else {
3933 if(mkdir(path, ADBDIRMODE) == -1 && errno != EEXIST) return false;
3934 for(int i = 0; i < num; i++){
3935 TCADB *adb = adbs[i];
3936 const char *cpath = tcadbpath(adb);
3937 if(cpath){
3938 const char *cname = strrchr(cpath, MYPATHCHR);
3939 cname = cname ? cname + 1 : cpath;
3940 const char *ext = strrchr(cname, MYEXTCHR);
3941 if(!ext) ext = "";
3942 char *npath = tcsprintf("%s%c%s%03d%s", path, MYPATHCHR, ADBMULPREFIX, i + 1, ext);
3943 if(!tcadbcopy(adb, npath)) err = true;
3944 TCFREE(npath);
3945 } else {
3946 err = true;
3947 }
3948 }
3949 }
3950 return !err;
3951 }
3952
3953
3954 /* Begin the transaction of a multiple database object.
3955 `mul' specifies the multiple database object.
3956 If successful, the return value is true, else, it is false. */
tcadbmultranbegin(ADBMUL * mul)3957 static bool tcadbmultranbegin(ADBMUL *mul){
3958 assert(mul);
3959 if(!mul->adbs) return false;
3960 TCADB **adbs = mul->adbs;
3961 int num = mul->num;
3962 bool err = false;
3963 for(int i = 0; i < num; i++){
3964 if(!tcadbtranbegin(adbs[i])){
3965 while(--i >= 0){
3966 tcadbtranabort(adbs[i]);
3967 }
3968 err = true;
3969 break;
3970 }
3971 }
3972 return !err;
3973 }
3974
3975
3976 /* Commit the transaction of a multiple database object.
3977 `mul' specifies the multiple database object.
3978 If successful, the return value is true, else, it is false. */
tcadbmultrancommit(ADBMUL * mul)3979 static bool tcadbmultrancommit(ADBMUL *mul){
3980 assert(mul);
3981 if(!mul->adbs) return false;
3982 TCADB **adbs = mul->adbs;
3983 int num = mul->num;
3984 bool err = false;
3985 for(int i = num - 1; i >= 0; i--){
3986 if(!tcadbtrancommit(adbs[i])) err = true;
3987 }
3988 return !err;
3989 }
3990
3991
3992 /* Abort the transaction of a multiple database object.
3993 `mul' specifies the multiple database object.
3994 If successful, the return value is true, else, it is false. */
tcadbmultranabort(ADBMUL * mul)3995 static bool tcadbmultranabort(ADBMUL *mul){
3996 assert(mul);
3997 if(!mul->adbs) return false;
3998 TCADB **adbs = mul->adbs;
3999 int num = mul->num;
4000 bool err = false;
4001 for(int i = num - 1; i >= 0; i--){
4002 if(!tcadbtranabort(adbs[i])) err = true;
4003 }
4004 return !err;
4005 }
4006
4007
4008 /* Get the file path of a multiple database object.
4009 `mul' specifies the multiple database object.
4010 The return value is the path of the database file or `NULL' if the object does not connect to
4011 any database. */
tcadbmulpath(ADBMUL * mul)4012 static const char *tcadbmulpath(ADBMUL *mul){
4013 assert(mul);
4014 if(!mul->adbs) return NULL;
4015 return mul->path;
4016 }
4017
4018
4019 /* Get the number of records of a multiple database object.
4020 `mul' specifies the multiple database object.
4021 The return value is the number of records or 0 if the object does not connect to any database
4022 instance. */
tcadbmulrnum(ADBMUL * mul)4023 static uint64_t tcadbmulrnum(ADBMUL *mul){
4024 assert(mul);
4025 if(!mul->adbs) return 0;
4026 TCADB **adbs = mul->adbs;
4027 int num = mul->num;
4028 uint64_t rnum = 0;
4029 for(int i = 0; i < num; i++){
4030 rnum += tcadbrnum(adbs[i]);
4031 }
4032 return rnum;
4033 }
4034
4035
4036 /* Get the size of the database of a multiple database object.
4037 `mul' specifies the multiple database object.
4038 The return value is the size of the database or 0 if the object does not connect to any
4039 database instance. */
tcadbmulsize(ADBMUL * mul)4040 static uint64_t tcadbmulsize(ADBMUL *mul){
4041 assert(mul);
4042 if(!mul->adbs) return 0;
4043 TCADB **adbs = mul->adbs;
4044 int num = mul->num;
4045 uint64_t size = 0;
4046 for(int i = 0; i < num; i++){
4047 size += tcadbsize(adbs[i]);
4048 }
4049 return size;
4050 }
4051
4052
4053 /* Call a versatile function for miscellaneous operations of a multiple database object.
4054 `mul' specifies the multiple database object.
4055 `name' specifies the name of the function.
4056 `args' specifies a list object containing arguments.
4057 If successful, the return value is a list object of the result. */
tcadbmulmisc(ADBMUL * mul,const char * name,const TCLIST * args)4058 static TCLIST *tcadbmulmisc(ADBMUL *mul, const char *name, const TCLIST *args){
4059 assert(mul && name);
4060 if(!mul->adbs) return NULL;
4061 TCADB **adbs = mul->adbs;
4062 int num = mul->num;
4063 TCLIST *rv = tclistnew();
4064 if(*name == '@'){
4065 name++;
4066 int anum = TCLISTNUM(args) - 1;
4067 TCLIST *targs = tclistnew2(2);
4068 for(int i = 0; i < anum; i++){
4069 const char *kbuf;
4070 int ksiz;
4071 TCLISTVAL(kbuf, args, i, ksiz);
4072 tclistclear(targs);
4073 TCLISTPUSH(targs, kbuf, ksiz);
4074 int idx = tcadbmulidx(mul, kbuf, ksiz);
4075 TCADB *adb = mul->adbs[idx];
4076 TCLIST *res = tcadbmisc(adb, name, targs);
4077 if(res){
4078 int rnum = TCLISTNUM(res);
4079 for(int j = 0; j < rnum; j++){
4080 const char *vbuf;
4081 int vsiz;
4082 TCLISTVAL(vbuf, res, j, vsiz);
4083 TCLISTPUSH(rv, vbuf, vsiz);
4084 }
4085 tclistdel(res);
4086 }
4087 }
4088 tclistdel(targs);
4089 } else if(*name == '%'){
4090 name++;
4091 int anum = TCLISTNUM(args) - 1;
4092 TCLIST *targs = tclistnew2(2);
4093 for(int i = 0; i < anum; i += 2){
4094 const char *kbuf, *vbuf;
4095 int ksiz, vsiz;
4096 TCLISTVAL(kbuf, args, i, ksiz);
4097 TCLISTVAL(vbuf, args, i + 1, vsiz);
4098 tclistclear(targs);
4099 TCLISTPUSH(targs, kbuf, ksiz);
4100 TCLISTPUSH(targs, vbuf, vsiz);
4101 int idx = tcadbmulidx(mul, kbuf, ksiz);
4102 TCADB *adb = mul->adbs[idx];
4103 TCLIST *res = tcadbmisc(adb, name, targs);
4104 if(res){
4105 int rnum = TCLISTNUM(res);
4106 for(int j = 0; j < rnum; j++){
4107 TCLISTVAL(vbuf, res, j, vsiz);
4108 TCLISTPUSH(rv, vbuf, vsiz);
4109 }
4110 tclistdel(res);
4111 }
4112 }
4113 tclistdel(targs);
4114 } else {
4115 for(int i = 0; i < num; i++){
4116 TCLIST *res = tcadbmisc(adbs[i], name, args);
4117 if(res){
4118 int rnum = TCLISTNUM(res);
4119 for(int j = 0; j < rnum; j++){
4120 const char *vbuf;
4121 int vsiz;
4122 TCLISTVAL(vbuf, res, j, vsiz);
4123 TCLISTPUSH(rv, vbuf, vsiz);
4124 }
4125 tclistdel(res);
4126 } else {
4127 tclistdel(rv);
4128 rv = NULL;
4129 break;
4130 }
4131 }
4132 }
4133 return rv;
4134 }
4135
4136
4137 /* Store a record into a multiple database object with a duplication handler.
4138 `mul' specifies the multiple database object.
4139 `kbuf' specifies the pointer to the region of the key.
4140 `ksiz' specifies the size of the region of the key.
4141 `vbuf' specifies the pointer to the region of the value.
4142 `vsiz' specifies the size of the region of the value.
4143 `proc' specifies the pointer to the callback function to process duplication.
4144 `op' specifies an arbitrary pointer to be given as a parameter of the callback function.
4145 If successful, the return value is true, else, it is false. */
tcadbmulputproc(ADBMUL * mul,const void * kbuf,int ksiz,const void * vbuf,int vsiz,TCPDPROC proc,void * op)4146 static bool tcadbmulputproc(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz,
4147 TCPDPROC proc, void *op){
4148 assert(mul && kbuf && ksiz >= 0 && proc);
4149 if(!mul->adbs) return false;
4150 int idx = tcadbmulidx(mul, kbuf, ksiz);
4151 TCADB *adb = mul->adbs[idx];
4152 return tcadbputproc(adb, kbuf, ksiz, vbuf, vsiz, proc, op);
4153 }
4154
4155
4156 /* Process each record atomically of a multiple database object.
4157 `mul' specifies the multiple database object.
4158 `iter' specifies the pointer to the iterator function called for each record.
4159 `op' specifies an arbitrary pointer to be given as a parameter of the iterator function.
4160 If successful, the return value is true, else, it is false. */
tcadbmulforeach(ADBMUL * mul,TCITER iter,void * op)4161 static bool tcadbmulforeach(ADBMUL *mul, TCITER iter, void *op){
4162 assert(mul && iter);
4163 if(!mul->adbs) return false;
4164 TCADB **adbs = mul->adbs;
4165 int num = mul->num;
4166 bool err = false;
4167 for(int i = 0; i < num; i++){
4168 if(!tcadbforeach(adbs[i], iter, op)){
4169 err = true;
4170 break;
4171 }
4172 }
4173 return !err;
4174 }
4175
4176
4177 /* Get the database index of a multiple database object.
4178 `mul' specifies the multiple database object.
4179 `kbuf' specifies the pointer to the region of the key.
4180 `ksiz' specifies the size of the region of the key.
4181 The return value is the bucket index. */
tcadbmulidx(ADBMUL * mul,const void * kbuf,int ksiz)4182 static int tcadbmulidx(ADBMUL *mul, const void *kbuf, int ksiz){
4183 assert(mul && kbuf && ksiz >= 0);
4184 uint32_t hash = 20090810;
4185 const char *rp = (char *)kbuf + ksiz;
4186 while(ksiz--){
4187 hash = (hash * 29) ^ *(uint8_t *)--rp;
4188 }
4189 return hash % mul->num;
4190 }
4191
4192
4193 /* Call the mapping function for every record of a multiple database object.
4194 `kbuf' specifies the pointer to the region of the key.
4195 `ksiz' specifies the size of the region of the key.
4196 `vbuf' specifies the pointer to the region of the value.
4197 `vsiz' specifies the size of the region of the value.
4198 `op' specifies the pointer to the optional opaque object.
4199 The return value is true to continue iteration or false to stop iteration. */
tcadbmapbdbiter(const void * kbuf,int ksiz,const void * vbuf,int vsiz,void * op)4200 static bool tcadbmapbdbiter(const void *kbuf, int ksiz, const void *vbuf, int vsiz, void *op){
4201 assert(kbuf && ksiz >= 0 && vbuf && vsiz >= 0 && op);
4202 ADBMAPBDB *map = op;
4203 bool err = false;
4204 if(!map->proc(map, kbuf, ksiz, vbuf, vsiz, map->op)) err = true;
4205 return !err;
4206 }
4207
4208
4209 /* Dump all cached records into the B+ tree database.
4210 `map' specifies the mapper object for the B+ tree database.
4211 The return value is true if successful, else, it is false. */
tcadbmapbdbdump(ADBMAPBDB * map)4212 static bool tcadbmapbdbdump(ADBMAPBDB *map){
4213 assert(map);
4214 TCBDB *bdb = map->bdb;
4215 TCLIST *recs = map->recs;
4216 int rnum = TCLISTNUM(recs);
4217 TCCMP cmp = tcbdbcmpfunc(bdb);
4218 if(cmp == tccmplexical){
4219 tclistsortex(recs, tcadbmapreccmplexical);
4220 } else if(cmp == tccmpdecimal){
4221 tclistsortex(recs, tcadbmapreccmpdecimal);
4222 } else if(cmp == tccmpint32){
4223 tclistsortex(recs, tcadbmapreccmpint32);
4224 } else if(cmp == tccmpint64){
4225 tclistsortex(recs, tcadbmapreccmpint64);
4226 }
4227 bool err = false;
4228 for(int i = 0; i < rnum; i++){
4229 const char *rbuf;
4230 int rsiz;
4231 TCLISTVAL(rbuf, recs, i, rsiz);
4232 int ksiz;
4233 memcpy(&ksiz, rbuf, sizeof(ksiz));
4234 const char *kbuf = rbuf + sizeof(ksiz);
4235 if(!tcbdbputdup(bdb, kbuf, ksiz, kbuf + ksiz, rsiz - sizeof(ksiz) - ksiz)){
4236 err = true;
4237 break;
4238 }
4239 }
4240 tclistclear(recs);
4241 map->rsiz = 0;
4242 return !err;
4243 }
4244
4245
4246 /* Compare two list elements by lexical order for mapping.
4247 `a' specifies the pointer to one element.
4248 `b' specifies the pointer to the other element.
4249 The return value is positive if the former is big, negative if the latter is big, 0 if both
4250 are equivalent. */
tcadbmapreccmplexical(const TCLISTDATUM * a,const TCLISTDATUM * b)4251 static int tcadbmapreccmplexical(const TCLISTDATUM *a, const TCLISTDATUM *b){
4252 assert(a && b);
4253 unsigned char *ao = (unsigned char *)((TCLISTDATUM *)a)->ptr;
4254 unsigned char *bo = (unsigned char *)((TCLISTDATUM *)b)->ptr;
4255 int size = (((TCLISTDATUM *)a)->size < ((TCLISTDATUM *)b)->size) ?
4256 ((TCLISTDATUM *)a)->size : ((TCLISTDATUM *)b)->size;
4257 for(int i = sizeof(int); i < size; i++){
4258 if(ao[i] > bo[i]) return 1;
4259 if(ao[i] < bo[i]) return -1;
4260 }
4261 return ((TCLISTDATUM *)a)->size - ((TCLISTDATUM *)b)->size;
4262 }
4263
4264
4265 /* Compare two keys as decimal strings of real numbers for mapping.
4266 `a' specifies the pointer to one element.
4267 `b' specifies the pointer to the other element.
4268 The return value is positive if the former is big, negative if the latter is big, 0 if both
4269 are equivalent. */
tcadbmapreccmpdecimal(const TCLISTDATUM * a,const TCLISTDATUM * b)4270 static int tcadbmapreccmpdecimal(const TCLISTDATUM *a, const TCLISTDATUM *b){
4271 assert(a && b);
4272 return tccmpdecimal(((TCLISTDATUM *)a)->ptr + sizeof(int), a->size - sizeof(int),
4273 ((TCLISTDATUM *)b)->ptr + sizeof(int), b->size - sizeof(int), NULL);
4274 }
4275
4276
4277 /* Compare two list elements as 32-bit integers in the native byte order for mapping.
4278 `a' specifies the pointer to one element.
4279 `b' specifies the pointer to the other element.
4280 The return value is positive if the former is big, negative if the latter is big, 0 if both
4281 are equivalent. */
tcadbmapreccmpint32(const TCLISTDATUM * a,const TCLISTDATUM * b)4282 static int tcadbmapreccmpint32(const TCLISTDATUM *a, const TCLISTDATUM *b){
4283 assert(a && b);
4284 return tccmpint32(((TCLISTDATUM *)a)->ptr + sizeof(int), a->size - sizeof(int),
4285 ((TCLISTDATUM *)b)->ptr + sizeof(int), b->size - sizeof(int), NULL);
4286 }
4287
4288
4289 /* Compare two list elements as 64-bit integers in the native byte order for mapping.
4290 `a' specifies the pointer to one element.
4291 `b' specifies the pointer to the other element.
4292 The return value is positive if the former is big, negative if the latter is big, 0 if both
4293 are equivalent. */
tcadbmapreccmpint64(const TCLISTDATUM * a,const TCLISTDATUM * b)4294 static int tcadbmapreccmpint64(const TCLISTDATUM *a, const TCLISTDATUM *b){
4295 assert(a && b);
4296 return tccmpint64(((TCLISTDATUM *)a)->ptr + sizeof(int), a->size - sizeof(int),
4297 ((TCLISTDATUM *)b)->ptr + sizeof(int), b->size - sizeof(int), NULL);
4298 }
4299
4300
4301 /* Retrieve and remove each record corresponding to a query object.
4302 `pkbuf' specifies the pointer to the region of the primary key.
4303 `pksiz' specifies the size of the region of the primary key.
4304 `cols' specifies a map object containing columns.
4305 `op' specifies the pointer to the optional opaque object.
4306 The return value is flags of the post treatment by bitwise-or.
4307 If successful, the return value is true, else, it is false. */
tcadbtdbqrygetout(const void * pkbuf,int pksiz,TCMAP * cols,void * op)4308 static int tcadbtdbqrygetout(const void *pkbuf, int pksiz, TCMAP *cols, void *op){
4309 TCLIST *rv = ((void **)op)[0];
4310 TCLIST *cnames = ((void **)op)[1];
4311 int cnnum = TCLISTNUM(cnames);
4312 tcmapput(cols, "", 0, pkbuf, pksiz);
4313 tcmapmove(cols, "", 0, true);
4314 if(cnnum > 0){
4315 TCMAP *ncols = tcmapnew2(cnnum + 1);
4316 for(int j = 0; j < cnnum; j++){
4317 const char *cname;
4318 int cnsiz;
4319 TCLISTVAL(cname, cnames, j, cnsiz);
4320 int cvsiz;
4321 const char *cvalue = tcmapget(cols, cname, cnsiz, &cvsiz);
4322 if(cvalue) tcmapput(ncols, cname, cnsiz, cvalue, cvsiz);
4323 }
4324 int csiz;
4325 char *cbuf = tcstrjoin4(ncols, &csiz);
4326 tclistpushmalloc(rv, cbuf, csiz);
4327 tcmapdel(ncols);
4328 } else {
4329 int csiz;
4330 char *cbuf = tcstrjoin4(cols, &csiz);
4331 tclistpushmalloc(rv, cbuf, csiz);
4332 }
4333 return TDBQPOUT;
4334 }
4335
4336
4337
4338 // END OF FILE
4339