tokyomessenger 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/COPYING +504 -0
  2. data/README.rdoc +224 -0
  3. data/Rakefile +72 -0
  4. data/benchmarks/balancer.rb +101 -0
  5. data/benchmarks/bulk_db.rb +92 -0
  6. data/benchmarks/bulk_table.rb +104 -0
  7. data/benchmarks/db.rb +131 -0
  8. data/benchmarks/table.rb +186 -0
  9. data/ext/a.h +496 -0
  10. data/ext/extconf.rb +27 -0
  11. data/ext/md5.c +381 -0
  12. data/ext/md5.h +101 -0
  13. data/ext/tc_myconf.c +493 -0
  14. data/ext/tc_myconf.h +543 -0
  15. data/ext/tcadb.c +4339 -0
  16. data/ext/tcadb.h +533 -0
  17. data/ext/tcbdb.c +4180 -0
  18. data/ext/tcbdb.h +1086 -0
  19. data/ext/tcfdb.c +2746 -0
  20. data/ext/tcfdb.h +842 -0
  21. data/ext/tchdb.c +5153 -0
  22. data/ext/tchdb.h +856 -0
  23. data/ext/tcrdb.c +2637 -0
  24. data/ext/tcrdb.h +785 -0
  25. data/ext/tctdb.c +6199 -0
  26. data/ext/tctdb.h +1070 -0
  27. data/ext/tcutil.c +10528 -0
  28. data/ext/tcutil.h +4166 -0
  29. data/ext/tokyo_messenger.c +147 -0
  30. data/ext/tokyo_messenger.h +49 -0
  31. data/ext/tokyo_messenger_db.c +227 -0
  32. data/ext/tokyo_messenger_db.h +8 -0
  33. data/ext/tokyo_messenger_module.c +453 -0
  34. data/ext/tokyo_messenger_module.h +10 -0
  35. data/ext/tokyo_messenger_query.c +226 -0
  36. data/ext/tokyo_messenger_query.h +9 -0
  37. data/ext/tokyo_messenger_table.c +319 -0
  38. data/ext/tokyo_messenger_table.h +8 -0
  39. data/ext/tt_myconf.c +169 -0
  40. data/ext/tt_myconf.h +408 -0
  41. data/ext/ttutil.c +1509 -0
  42. data/ext/ttutil.h +480 -0
  43. data/lib/tokyo_messenger/balancer.rb +188 -0
  44. data/spec/ext.lua +4 -0
  45. data/spec/plu_db.rb +538 -0
  46. data/spec/spec.rb +1 -0
  47. data/spec/spec_base.rb +17 -0
  48. data/spec/start_tyrants.sh +36 -0
  49. data/spec/stop_tyrants.sh +9 -0
  50. data/spec/tokyo_tyrant_balancer_db_spec.rb +160 -0
  51. data/spec/tokyo_tyrant_balancer_table_spec.rb +177 -0
  52. data/spec/tokyo_tyrant_query_spec.rb +159 -0
  53. data/spec/tokyo_tyrant_spec.rb +254 -0
  54. data/spec/tokyo_tyrant_table_spec.rb +301 -0
  55. metadata +117 -0
@@ -0,0 +1,4339 @@
1
+ /*************************************************************************************************
2
+ * The abstract database API of Tokyo Cabinet
3
+ * Copyright (C) 2006-2009 Mikio Hirabayashi
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 "tc_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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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. */
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
+ int ksiz, vsiz;
3071
+ TCLISTVAL(kbuf, args, i, ksiz);
3072
+ TCLISTVAL(vbuf, args, i + 1, vsiz);
3073
+ int type = tctdbstrtoindextype(vbuf);
3074
+ if(type >= 0){
3075
+ if(!tctdbsetindex(adb->tdb, kbuf, type)) err = true;
3076
+ } else {
3077
+ err = true;
3078
+ }
3079
+ }
3080
+ if(err){
3081
+ tclistdel(rv);
3082
+ rv = NULL;
3083
+ }
3084
+ } else if(!strcmp(name, "search") || !strcmp(name, "metasearch")){
3085
+ bool toout = false;
3086
+ bool tocnt = false;
3087
+ bool tohint = false;
3088
+ TDBQRY *qry = tctdbqrynew(adb->tdb);
3089
+ TDBQRY **qrys = NULL;
3090
+ int qnum = 0;
3091
+ int mstype = TDBMSUNION;
3092
+ TCLIST *cnames = NULL;
3093
+ for(int i = 0; i < argc; i++){
3094
+ const char *arg;
3095
+ int asiz;
3096
+ TCLISTVAL(arg, args, i, asiz);
3097
+ TCLIST *tokens = tcstrsplit2(arg, asiz);
3098
+ int tnum = TCLISTNUM(tokens);
3099
+ if(tnum > 0){
3100
+ const char *cmd = TCLISTVALPTR(tokens, 0);
3101
+ if((!strcmp(cmd, "addcond") || !strcmp(cmd, "cond")) && tnum > 3){
3102
+ const char *name = TCLISTVALPTR(tokens, 1);
3103
+ const char *opstr = TCLISTVALPTR(tokens, 2);
3104
+ const char *expr = TCLISTVALPTR(tokens, 3);
3105
+ int op = tctdbqrystrtocondop(opstr);
3106
+ if(op >= 0) tctdbqryaddcond(qry, name, op, expr);
3107
+ } else if((!strcmp(cmd, "setorder") || !strcmp(cmd, "order")) && tnum > 2){
3108
+ const char *name = TCLISTVALPTR(tokens, 1);
3109
+ const char *typestr = TCLISTVALPTR(tokens, 2);
3110
+ int type = tctdbqrystrtoordertype(typestr);
3111
+ if(type >= 0) tctdbqrysetorder(qry, name, type);
3112
+ } else if((!strcmp(cmd, "setlimit") || !strcmp(cmd, "limit") ||
3113
+ !strcmp(cmd, "setmax") || !strcmp(cmd, "max") ) && tnum > 1){
3114
+ const char *maxstr = TCLISTVALPTR(tokens, 1);
3115
+ int max = tcatoi(maxstr);
3116
+ int skip = 0;
3117
+ if(tnum > 2){
3118
+ maxstr = TCLISTVALPTR(tokens, 2);
3119
+ skip = tcatoi(maxstr);
3120
+ }
3121
+ tctdbqrysetlimit(qry, max, skip);
3122
+ } else if(!strcmp(cmd, "get") || !strcmp(cmd, "columns")){
3123
+ if(!cnames) cnames = tclistnew();
3124
+ for(int j = 1; j < tnum; j++){
3125
+ const char *token;
3126
+ int tsiz;
3127
+ TCLISTVAL(token, tokens, j, tsiz);
3128
+ TCLISTPUSH(cnames, token, tsiz);
3129
+ }
3130
+ } else if(!strcmp(cmd, "next")){
3131
+ if(qrys){
3132
+ TCREALLOC(qrys, qrys, sizeof(*qrys) * (qnum + 1));
3133
+ } else {
3134
+ TCMALLOC(qrys, sizeof(*qrys) * 2);
3135
+ qrys[0] = qry;
3136
+ qnum = 1;
3137
+ }
3138
+ qry = tctdbqrynew(adb->tdb);
3139
+ qrys[qnum++] = qry;
3140
+ } else if(!strcmp(cmd, "mstype") && tnum > 1){
3141
+ const char *typestr = TCLISTVALPTR(tokens, 1);
3142
+ mstype = tctdbstrtometasearcytype(typestr);
3143
+ if(mstype < 0) mstype = TDBMSUNION;
3144
+ } else if(!strcmp(cmd, "out") || !strcmp(cmd, "remove")){
3145
+ toout = true;
3146
+ } else if(!strcmp(cmd, "count")){
3147
+ tocnt = true;
3148
+ } else if(!strcmp(cmd, "hint")){
3149
+ tohint = true;
3150
+ }
3151
+ }
3152
+ tclistdel(tokens);
3153
+ }
3154
+ if(toout){
3155
+ if(cnames){
3156
+ rv = tclistnew2(1);
3157
+ void *opq[2];
3158
+ opq[0] = rv;
3159
+ opq[1] = cnames;
3160
+ if(!tctdbqryproc2(qry, tcadbtdbqrygetout, opq)){
3161
+ tclistdel(rv);
3162
+ rv = NULL;
3163
+ }
3164
+ } else {
3165
+ if(tctdbqrysearchout2(qry)){
3166
+ rv = tclistnew2(1);
3167
+ } else {
3168
+ rv = NULL;
3169
+ }
3170
+ }
3171
+ } else {
3172
+ if(qrys){
3173
+ rv = tctdbmetasearch(qrys, qnum, mstype);
3174
+ } else {
3175
+ rv = tctdbqrysearch(qry);
3176
+ }
3177
+ if(cnames){
3178
+ int cnnum = TCLISTNUM(cnames);
3179
+ int rnum = TCLISTNUM(rv);
3180
+ TCLIST *nrv = tclistnew2(rnum);
3181
+ for(int i = 0; i < rnum; i++){
3182
+ const char *pkbuf;
3183
+ int pksiz;
3184
+ TCLISTVAL(pkbuf, rv, i, pksiz);
3185
+ TCMAP *cols = tctdbget(adb->tdb, pkbuf, pksiz);
3186
+ if(cols){
3187
+ tcmapput(cols, "", 0, pkbuf, pksiz);
3188
+ tcmapmove(cols, "", 0, true);
3189
+ if(cnnum > 0){
3190
+ TCMAP *ncols = tcmapnew2(cnnum + 1);
3191
+ for(int j = 0; j < cnnum; j++){
3192
+ const char *cname;
3193
+ int cnsiz;
3194
+ TCLISTVAL(cname, cnames, j, cnsiz);
3195
+ int cvsiz;
3196
+ const char *cvalue = tcmapget(cols, cname, cnsiz, &cvsiz);
3197
+ if(cvalue) tcmapput(ncols, cname, cnsiz, cvalue, cvsiz);
3198
+ }
3199
+ tcmapdel(cols);
3200
+ cols = ncols;
3201
+ }
3202
+ int csiz;
3203
+ char *cbuf = tcstrjoin4(cols, &csiz);
3204
+ tclistpushmalloc(nrv, cbuf, csiz);
3205
+ tcmapdel(cols);
3206
+ }
3207
+ }
3208
+ tclistdel(rv);
3209
+ rv = nrv;
3210
+ }
3211
+ }
3212
+ if(tocnt && rv){
3213
+ tclistclear(rv);
3214
+ char numbuf[TCNUMBUFSIZ];
3215
+ int len = sprintf(numbuf, "%d", tctdbqrycount(qry));
3216
+ TCLISTPUSH(rv, numbuf, len);
3217
+ }
3218
+ if(tohint && rv){
3219
+ TCXSTR *hbuf = tcxstrnew();
3220
+ TCXSTRCAT(hbuf, "", 1);
3221
+ TCXSTRCAT(hbuf, "", 1);
3222
+ TCXSTRCAT(hbuf, "[[HINT]]\n", 9);
3223
+ const char *hint = tctdbqryhint(qrys ? qrys[0] : qry);
3224
+ TCXSTRCAT(hbuf, hint, strlen(hint));
3225
+ TCLISTPUSH(rv, TCXSTRPTR(hbuf), TCXSTRSIZE(hbuf));
3226
+ tcxstrdel(hbuf);
3227
+ }
3228
+ if(cnames) tclistdel(cnames);
3229
+ if(qrys){
3230
+ for(int i = 0; i < qnum; i++){
3231
+ tctdbqrydel(qrys[i]);
3232
+ }
3233
+ TCFREE(qrys);
3234
+ } else {
3235
+ tctdbqrydel(qry);
3236
+ }
3237
+ } else if(!strcmp(name, "genuid")){
3238
+ rv = tclistnew2(1);
3239
+ char numbuf[TCNUMBUFSIZ];
3240
+ int nsiz = sprintf(numbuf, "%lld", (long long)tctdbgenuid(adb->tdb));
3241
+ TCLISTPUSH(rv, numbuf, nsiz);
3242
+ } else {
3243
+ rv = NULL;
3244
+ }
3245
+ break;
3246
+ case ADBOSKEL:
3247
+ skel = adb->skel;
3248
+ if(skel->misc){
3249
+ rv = skel->misc(skel->opq, name, args);
3250
+ } else {
3251
+ rv = NULL;
3252
+ }
3253
+ break;
3254
+ default:
3255
+ rv = NULL;
3256
+ break;
3257
+ }
3258
+ return rv;
3259
+ }
3260
+
3261
+
3262
+
3263
+ /*************************************************************************************************
3264
+ * features for experts
3265
+ *************************************************************************************************/
3266
+
3267
+
3268
+ /* Set an extra database sleleton to an abstract database object. */
3269
+ bool tcadbsetskel(TCADB *adb, ADBSKEL *skel){
3270
+ assert(skel);
3271
+ if(adb->omode != ADBOVOID) return false;
3272
+ if(adb->skel) TCFREE(adb->skel);
3273
+ adb->skel = tcmemdup(skel, sizeof(*skel));
3274
+ return true;
3275
+ }
3276
+
3277
+
3278
+ /* Set the multiple database skeleton to an abstract database object. */
3279
+ bool tcadbsetskelmulti(TCADB *adb, int num){
3280
+ assert(adb && num >= 0);
3281
+ if(adb->omode != ADBOVOID) return false;
3282
+ if(num < 1) return false;
3283
+ if(num > CHAR_MAX) num = CHAR_MAX;
3284
+ ADBMUL *mul = tcadbmulnew(num);
3285
+ ADBSKEL skel;
3286
+ memset(&skel, 0, sizeof(skel));
3287
+ skel.opq = mul;
3288
+ skel.del = (void (*)(void *))tcadbmuldel;
3289
+ skel.open = (bool (*)(void *, const char *))tcadbmulopen;
3290
+ skel.close = (bool (*)(void *))tcadbmulclose;
3291
+ skel.put = (bool (*)(void *, const void *, int, const void *, int))tcadbmulput;
3292
+ skel.putkeep = (bool (*)(void *, const void *, int, const void *, int))tcadbmulputkeep;
3293
+ skel.putcat = (bool (*)(void *, const void *, int, const void *, int))tcadbmulputcat;
3294
+ skel.out = (bool (*)(void *, const void *, int))tcadbmulout;
3295
+ skel.get = (void *(*)(void *, const void *, int, int *))tcadbmulget;
3296
+ skel.vsiz = (int (*)(void *, const void *, int))tcadbmulvsiz;
3297
+ skel.iterinit = (bool (*)(void *))tcadbmuliterinit;
3298
+ skel.iternext = (void *(*)(void *, int *))tcadbmuliternext;
3299
+ skel.fwmkeys = (TCLIST *(*)(void *, const void *, int, int))tcadbmulfwmkeys;
3300
+ skel.addint = (int (*)(void *, const void *, int, int))tcadbmuladdint;
3301
+ skel.adddouble = (double (*)(void *, const void *, int, double))tcadbmuladddouble;
3302
+ skel.sync = (bool (*)(void *))tcadbmulsync;
3303
+ skel.optimize = (bool (*)(void *, const char *))tcadbmuloptimize;
3304
+ skel.vanish = (bool (*)(void *))tcadbmulvanish;
3305
+ skel.copy = (bool (*)(void *, const char *))tcadbmulcopy;
3306
+ skel.tranbegin = (bool (*)(void *))tcadbmultranbegin;
3307
+ skel.trancommit = (bool (*)(void *))tcadbmultrancommit;
3308
+ skel.tranabort = (bool (*)(void *))tcadbmultranabort;
3309
+ skel.path = (const char *(*)(void *))tcadbmulpath;
3310
+ skel.rnum = (uint64_t (*)(void *))tcadbmulrnum;
3311
+ skel.size = (uint64_t (*)(void *))tcadbmulsize;
3312
+ skel.misc = (TCLIST *(*)(void *, const char *, const TCLIST *))tcadbmulmisc;
3313
+ skel.putproc =
3314
+ (bool (*)(void *, const void *, int, const void *, int, TCPDPROC, void *))tcadbmulputproc;
3315
+ skel.foreach = (bool (*)(void *, TCITER, void *))tcadbmulforeach;
3316
+ if(!tcadbsetskel(adb, &skel)){
3317
+ tcadbmuldel(mul);
3318
+ return false;
3319
+ }
3320
+ return true;
3321
+ }
3322
+
3323
+
3324
+ /* Get the open mode of an abstract database object. */
3325
+ int tcadbomode(TCADB *adb){
3326
+ assert(adb);
3327
+ return adb->omode;
3328
+ }
3329
+
3330
+
3331
+ /* Get the concrete database object of an abstract database object. */
3332
+ void *tcadbreveal(TCADB *adb){
3333
+ assert(adb);
3334
+ void *rv;
3335
+ switch(adb->omode){
3336
+ case ADBOMDB:
3337
+ rv = adb->mdb;
3338
+ break;
3339
+ case ADBONDB:
3340
+ rv = adb->ndb;
3341
+ break;
3342
+ case ADBOHDB:
3343
+ rv = adb->hdb;
3344
+ break;
3345
+ case ADBOBDB:
3346
+ rv = adb->bdb;
3347
+ break;
3348
+ case ADBOFDB:
3349
+ rv = adb->fdb;
3350
+ break;
3351
+ case ADBOTDB:
3352
+ rv = adb->tdb;
3353
+ break;
3354
+ case ADBOSKEL:
3355
+ rv = adb->skel;
3356
+ break;
3357
+ default:
3358
+ rv = NULL;
3359
+ break;
3360
+ }
3361
+ return rv;
3362
+ }
3363
+
3364
+
3365
+ /* Store a record into an abstract database object with a duplication handler. */
3366
+ bool tcadbputproc(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz,
3367
+ TCPDPROC proc, void *op){
3368
+ assert(adb && kbuf && ksiz >= 0 && proc);
3369
+ bool err = false;
3370
+ ADBSKEL *skel;
3371
+ switch(adb->omode){
3372
+ case ADBOMDB:
3373
+ if(tcmdbputproc(adb->mdb, kbuf, ksiz, vbuf, vsiz, proc, op)){
3374
+ if(adb->capnum > 0 || adb->capsiz > 0){
3375
+ adb->capcnt++;
3376
+ if((adb->capcnt & 0xff) == 0){
3377
+ if(adb->capnum > 0 && tcmdbrnum(adb->mdb) > adb->capnum + 0x100)
3378
+ tcmdbcutfront(adb->mdb, 0x100);
3379
+ if(adb->capsiz > 0 && tcmdbmsiz(adb->mdb) > adb->capsiz)
3380
+ tcmdbcutfront(adb->mdb, 0x200);
3381
+ }
3382
+ }
3383
+ } else {
3384
+ err = true;
3385
+ }
3386
+ break;
3387
+ case ADBONDB:
3388
+ if(tcndbputproc(adb->ndb, kbuf, ksiz, vbuf, vsiz, proc, op)){
3389
+ if(adb->capnum > 0 || adb->capsiz > 0){
3390
+ adb->capcnt++;
3391
+ if((adb->capcnt & 0xff) == 0){
3392
+ if(adb->capnum > 0 && tcndbrnum(adb->ndb) > adb->capnum + 0x100)
3393
+ tcndbcutfringe(adb->ndb, 0x100);
3394
+ if(adb->capsiz > 0 && tcndbmsiz(adb->ndb) > adb->capsiz)
3395
+ tcndbcutfringe(adb->ndb, 0x200);
3396
+ }
3397
+ }
3398
+ } else {
3399
+ err = true;
3400
+ }
3401
+ break;
3402
+ case ADBOHDB:
3403
+ if(!tchdbputproc(adb->hdb, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3404
+ break;
3405
+ case ADBOBDB:
3406
+ if(!tcbdbputproc(adb->bdb, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3407
+ break;
3408
+ case ADBOFDB:
3409
+ if(!tcfdbputproc(adb->fdb, tcfdbkeytoid(kbuf, ksiz), vbuf, vsiz, proc, op)) err = true;
3410
+ break;
3411
+ case ADBOTDB:
3412
+ if(!tctdbputproc(adb->tdb, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3413
+ break;
3414
+ case ADBOSKEL:
3415
+ skel = adb->skel;
3416
+ if(skel->putproc){
3417
+ if(!skel->putproc(skel->opq, kbuf, ksiz, vbuf, vsiz, proc, op)) err = true;
3418
+ } else {
3419
+ err = true;
3420
+ }
3421
+ break;
3422
+ default:
3423
+ err = true;
3424
+ break;
3425
+ }
3426
+ return !err;
3427
+ }
3428
+
3429
+
3430
+ /* Process each record atomically of an abstract database object. */
3431
+ bool tcadbforeach(TCADB *adb, TCITER iter, void *op){
3432
+ assert(adb && iter);
3433
+ bool err = false;
3434
+ ADBSKEL *skel;
3435
+ switch(adb->omode){
3436
+ case ADBOMDB:
3437
+ tcmdbforeach(adb->mdb, iter, op);
3438
+ break;
3439
+ case ADBONDB:
3440
+ tcndbforeach(adb->ndb, iter, op);
3441
+ break;
3442
+ case ADBOHDB:
3443
+ if(!tchdbforeach(adb->hdb, iter, op)) err = true;
3444
+ break;
3445
+ case ADBOBDB:
3446
+ if(!tcbdbforeach(adb->bdb, iter, op)) err = true;
3447
+ break;
3448
+ case ADBOFDB:
3449
+ if(!tcfdbforeach(adb->fdb, iter, op)) err = true;
3450
+ break;
3451
+ case ADBOTDB:
3452
+ if(!tctdbforeach(adb->tdb, iter, op)) err = true;
3453
+ break;
3454
+ case ADBOSKEL:
3455
+ skel = adb->skel;
3456
+ if(skel->foreach){
3457
+ if(!skel->foreach(skel->opq, iter, op)) err = true;
3458
+ } else {
3459
+ err = true;
3460
+ }
3461
+ break;
3462
+ default:
3463
+ err = true;
3464
+ break;
3465
+ }
3466
+ return !err;
3467
+ }
3468
+
3469
+
3470
+ /* Map records of an abstract database object into another B+ tree database. */
3471
+ bool tcadbmapbdb(TCADB *adb, TCLIST *keys, TCBDB *bdb, ADBMAPPROC proc, void *op, int64_t csiz){
3472
+ assert(adb && bdb && proc);
3473
+ if(csiz < 0) csiz = 256LL << 20;
3474
+ TCLIST *recs = tclistnew2(tclmin(csiz / 64 + 256, INT_MAX / 4));
3475
+ ADBMAPBDB map;
3476
+ map.adb = adb;
3477
+ map.bdb = bdb;
3478
+ map.recs = recs;
3479
+ map.proc = proc;
3480
+ map.op = op;
3481
+ map.rsiz = 0;
3482
+ map.csiz = csiz;
3483
+ bool err = false;
3484
+ if(keys){
3485
+ int knum = TCLISTNUM(keys);
3486
+ for(int i = 0; i < knum && !err; i++){
3487
+ const char *kbuf;
3488
+ int ksiz;
3489
+ TCLISTVAL(kbuf, keys, i, ksiz);
3490
+ int vsiz;
3491
+ char *vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
3492
+ if(vbuf){
3493
+ if(!tcadbmapbdbiter(kbuf, ksiz, vbuf, vsiz, &map)) err = true;
3494
+ TCFREE(vbuf);
3495
+ if(map.rsiz > map.csiz && !tcadbmapbdbdump(&map)) err = true;
3496
+ }
3497
+ if(map.rsiz > 0 && !tcadbmapbdbdump(&map)) err = true;
3498
+ }
3499
+ } else {
3500
+ if(!tcadbforeach(adb, tcadbmapbdbiter, &map)) err = true;
3501
+ }
3502
+ if(map.rsiz > 0 && !tcadbmapbdbdump(&map)) err = true;
3503
+ tclistdel(recs);
3504
+ return !err;
3505
+ }
3506
+
3507
+
3508
+ /* Emit records generated by the mapping function into the result map. */
3509
+ bool tcadbmapbdbemit(void *map, const char *kbuf, int ksiz, const char *vbuf, int vsiz){
3510
+ assert(map && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3511
+ ADBMAPBDB *mymap = map;
3512
+ int rsiz = sizeof(ksiz) + ksiz + vsiz;
3513
+ char stack[TCNUMBUFSIZ*8];
3514
+ char *rbuf;
3515
+ if(rsiz <= sizeof(stack)){
3516
+ rbuf = stack;
3517
+ } else {
3518
+ TCMALLOC(rbuf, rsiz);
3519
+ }
3520
+ bool err = false;
3521
+ char *wp = rbuf;
3522
+ memcpy(wp, &ksiz, sizeof(ksiz));
3523
+ wp += sizeof(ksiz);
3524
+ memcpy(wp, kbuf, ksiz);
3525
+ wp += ksiz;
3526
+ memcpy(wp, vbuf, vsiz);
3527
+ TCLISTPUSH(mymap->recs, rbuf, rsiz);
3528
+ mymap->rsiz += rsiz + sizeof(TCLISTDATUM);
3529
+ if(rbuf != stack) TCFREE(rbuf);
3530
+ if(mymap->rsiz > mymap->csiz && !tcadbmapbdbdump(map)) err = true;
3531
+ return !err;
3532
+ }
3533
+
3534
+
3535
+
3536
+ /*************************************************************************************************
3537
+ * private features
3538
+ *************************************************************************************************/
3539
+
3540
+
3541
+ /* Create a multiple database object.
3542
+ `num' specifies the number of inner databases.
3543
+ The return value is the new multiple database object. */
3544
+ static ADBMUL *tcadbmulnew(int num){
3545
+ assert(num > 0);
3546
+ ADBMUL *mul;
3547
+ TCMALLOC(mul, sizeof(*mul));
3548
+ mul->adbs = NULL;
3549
+ mul->num = num;
3550
+ mul->iter = -1;
3551
+ mul->path = NULL;
3552
+ return mul;
3553
+ }
3554
+
3555
+
3556
+ /* Delete a multiple database object.
3557
+ `mul' specifies the multiple database object. */
3558
+ static void tcadbmuldel(ADBMUL *mul){
3559
+ assert(mul);
3560
+ if(mul->adbs) tcadbmulclose(mul);
3561
+ TCFREE(mul);
3562
+ }
3563
+
3564
+
3565
+ /* Open a multiple database.
3566
+ `mul' specifies the multiple database object.
3567
+ If successful, the return value is true, else, it is false. */
3568
+ static bool tcadbmulopen(ADBMUL *mul, const char *name){
3569
+ assert(mul && name);
3570
+ if(mul->adbs) return false;
3571
+ mul->iter = -1;
3572
+ TCLIST *elems = tcstrsplit(name, "#");
3573
+ char *path = tclistshift2(elems);
3574
+ if(!path){
3575
+ tclistdel(elems);
3576
+ return false;
3577
+ }
3578
+ const char *ext = strrchr(path, MYEXTCHR);
3579
+ if(!ext) ext = "";
3580
+ const char *params = strchr(name, '#');
3581
+ if(!params) params = "";
3582
+ bool owmode = true;
3583
+ bool ocmode = true;
3584
+ bool otmode = false;
3585
+ int ln = TCLISTNUM(elems);
3586
+ for(int i = 0; i < ln; i++){
3587
+ const char *elem = TCLISTVALPTR(elems, i);
3588
+ char *pv = strchr(elem, '=');
3589
+ if(!pv) continue;
3590
+ *(pv++) = '\0';
3591
+ if(!tcstricmp(elem, "mode")){
3592
+ owmode = strchr(pv, 'w') || strchr(pv, 'W');
3593
+ ocmode = strchr(pv, 'c') || strchr(pv, 'C');
3594
+ otmode = strchr(pv, 't') || strchr(pv, 'T');
3595
+ }
3596
+ }
3597
+ tclistdel(elems);
3598
+ bool err = false;
3599
+ char *gpat = tcsprintf("%s%c%s*", path, MYPATHCHR, ADBMULPREFIX);
3600
+ TCLIST *cpaths = tcglobpat(gpat);
3601
+ tclistsort(cpaths);
3602
+ int cnum = TCLISTNUM(cpaths);
3603
+ if(owmode){
3604
+ if(otmode){
3605
+ for(int i = 0; i < cnum; i++){
3606
+ const char *cpath = TCLISTVALPTR(cpaths, i);
3607
+ if(unlink(cpath) != 0) err = true;
3608
+ }
3609
+ tclistclear(cpaths);
3610
+ cnum = 0;
3611
+ }
3612
+ if(ocmode && cnum < 1){
3613
+ if(mkdir(path, ADBDIRMODE) != 0 && errno != EEXIST){
3614
+ err = true;
3615
+ } else {
3616
+ for(int i = 0; i < mul->num; i++){
3617
+ tclistprintf(cpaths, "%s%c%s%03d%s", path, MYPATHCHR, ADBMULPREFIX, i + 1, ext);
3618
+ }
3619
+ cnum = TCLISTNUM(cpaths);
3620
+ }
3621
+ }
3622
+ }
3623
+ if(!err && cnum > 0){
3624
+ TCADB **adbs;
3625
+ TCMALLOC(adbs, sizeof(*adbs) * cnum);
3626
+ for(int i = 0; i < cnum; i++){
3627
+ TCADB *adb = tcadbnew();
3628
+ const char *cpath = TCLISTVALPTR(cpaths, i);
3629
+ char *cname = tcsprintf("%s%s", cpath, params);
3630
+ if(!tcadbopen(adb, cname)) err = true;
3631
+ TCFREE(cname);
3632
+ adbs[i] = adb;
3633
+ }
3634
+ if(err){
3635
+ for(int i = cnum - 1; i >= 0; i--){
3636
+ tcadbdel(adbs[i]);
3637
+ }
3638
+ TCFREE(adbs);
3639
+ } else {
3640
+ mul->adbs = adbs;
3641
+ mul->num = cnum;
3642
+ mul->path = path;
3643
+ path = NULL;
3644
+ }
3645
+ }
3646
+ tclistdel(cpaths);
3647
+ TCFREE(gpat);
3648
+ TCFREE(path);
3649
+ return !err;
3650
+ }
3651
+
3652
+
3653
+ /* Close a multiple database object.
3654
+ `mul' specifies the multiple database object.
3655
+ If successful, the return value is true, else, it is false. */
3656
+ static bool tcadbmulclose(ADBMUL *mul){
3657
+ assert(mul);
3658
+ if(!mul->adbs) return false;
3659
+ TCADB **adbs = mul->adbs;
3660
+ int num = mul->num;
3661
+ bool err = false;
3662
+ for(int i = num - 1; i >= 0; i--){
3663
+ TCADB *adb = adbs[i];
3664
+ if(!tcadbclose(adb)) err = true;
3665
+ tcadbdel(adb);
3666
+ }
3667
+ TCFREE(mul->path);
3668
+ TCFREE(adbs);
3669
+ mul->adbs = NULL;
3670
+ mul->path = NULL;
3671
+ return !err;
3672
+ }
3673
+
3674
+
3675
+ /* Store a record into a multiple database object.
3676
+ `mul' specifies the multiple database object.
3677
+ `kbuf' specifies the pointer to the region of the key.
3678
+ `ksiz' specifies the size of the region of the key.
3679
+ `vbuf' specifies the pointer to the region of the value.
3680
+ `vsiz' specifies the size of the region of the value.
3681
+ If successful, the return value is true, else, it is false. */
3682
+ static bool tcadbmulput(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
3683
+ assert(mul && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3684
+ if(!mul->adbs) return false;
3685
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3686
+ TCADB *adb = mul->adbs[idx];
3687
+ return tcadbput(adb, kbuf, ksiz, vbuf, vsiz);
3688
+ }
3689
+
3690
+
3691
+ /* Store a new record into a multiple database object.
3692
+ `mul' specifies the multiple database object.
3693
+ `kbuf' specifies the pointer to the region of the key.
3694
+ `ksiz' specifies the size of the region of the key.
3695
+ `vbuf' specifies the pointer to the region of the value.
3696
+ `vsiz' specifies the size of the region of the value.
3697
+ If successful, the return value is true, else, it is false. */
3698
+ static bool tcadbmulputkeep(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
3699
+ assert(mul && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3700
+ if(!mul->adbs) return false;
3701
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3702
+ TCADB *adb = mul->adbs[idx];
3703
+ return tcadbputkeep(adb, kbuf, ksiz, vbuf, vsiz);
3704
+ }
3705
+
3706
+
3707
+ /* Concatenate a value at the end of the existing record in a multiple database object.
3708
+ `mul' specifies the multiple database object.
3709
+ `kbuf' specifies the pointer to the region of the key.
3710
+ `ksiz' specifies the size of the region of the key.
3711
+ `vbuf' specifies the pointer to the region of the value.
3712
+ `vsiz' specifies the size of the region of the value.
3713
+ If successful, the return value is true, else, it is false. */
3714
+ static bool tcadbmulputcat(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
3715
+ assert(mul && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
3716
+ if(!mul->adbs) return false;
3717
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3718
+ TCADB *adb = mul->adbs[idx];
3719
+ return tcadbputcat(adb, kbuf, ksiz, vbuf, vsiz);
3720
+ }
3721
+
3722
+
3723
+ /* Remove a record of a multiple database object.
3724
+ `mul' specifies the multiple database object.
3725
+ `kbuf' specifies the pointer to the region of the key.
3726
+ `ksiz' specifies the size of the region of the key.
3727
+ If successful, the return value is true, else, it is false. */
3728
+ static bool tcadbmulout(ADBMUL *mul, const void *kbuf, int ksiz){
3729
+ assert(mul && kbuf && ksiz >= 0);
3730
+ if(!mul->adbs) return false;
3731
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3732
+ TCADB *adb = mul->adbs[idx];
3733
+ return tcadbout(adb, kbuf, ksiz);
3734
+ }
3735
+
3736
+
3737
+ /* Retrieve a record in a multiple database object.
3738
+ `mul' specifies the multiple database object.
3739
+ `kbuf' specifies the pointer to the region of the key.
3740
+ `ksiz' specifies the size of the region of the key.
3741
+ `sp' specifies the pointer to the variable into which the size of the region of the return
3742
+ value is assigned.
3743
+ If successful, the return value is the pointer to the region of the value of the corresponding
3744
+ record. */
3745
+ static void *tcadbmulget(ADBMUL *mul, const void *kbuf, int ksiz, int *sp){
3746
+ assert(mul && kbuf && ksiz >= 0 && sp);
3747
+ if(!mul->adbs) return false;
3748
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3749
+ TCADB *adb = mul->adbs[idx];
3750
+ return tcadbget(adb, kbuf, ksiz, sp);
3751
+ }
3752
+
3753
+
3754
+ /* Get the size of the value of a record in a multiple database object.
3755
+ `mul' specifies the multiple database object.
3756
+ `kbuf' specifies the pointer to the region of the key.
3757
+ `ksiz' specifies the size of the region of the key.
3758
+ If successful, the return value is the size of the value of the corresponding record, else,
3759
+ it is -1. */
3760
+ static int tcadbmulvsiz(ADBMUL *mul, const void *kbuf, int ksiz){
3761
+ assert(mul && kbuf && ksiz >= 0);
3762
+ if(!mul->adbs) return false;
3763
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3764
+ TCADB *adb = mul->adbs[idx];
3765
+ return tcadbvsiz(adb, kbuf, ksiz);
3766
+ }
3767
+
3768
+
3769
+ /* Initialize the iterator of a multiple database object.
3770
+ `mul' specifies the multiple database object.
3771
+ If successful, the return value is true, else, it is false. */
3772
+ static bool tcadbmuliterinit(ADBMUL *mul){
3773
+ assert(mul);
3774
+ if(!mul->adbs) return false;
3775
+ mul->iter = -1;
3776
+ TCADB **adbs = mul->adbs;
3777
+ int num = mul->num;
3778
+ bool err = false;
3779
+ for(int i = 0; i < num; i++){
3780
+ if(!tcadbiterinit(adbs[i])) err = true;
3781
+ }
3782
+ if(err) return false;
3783
+ mul->iter = 0;
3784
+ return true;
3785
+ }
3786
+
3787
+
3788
+ /* Get the next key of the iterator of a multiple database object.
3789
+ `mul' specifies the multiple database object.
3790
+ `sp' specifies the pointer to the variable into which the size of the region of the return
3791
+ value is assigned.
3792
+ If successful, the return value is the pointer to the region of the next key, else, it is
3793
+ `NULL'. */
3794
+ static void *tcadbmuliternext(ADBMUL *mul, int *sp){
3795
+ assert(mul && sp);
3796
+ if(!mul->adbs || mul->iter < 0) return false;
3797
+ while(mul->iter < mul->num){
3798
+ TCADB *adb = mul->adbs[mul->iter];
3799
+ char *rv = tcadbiternext(adb, sp);
3800
+ if(rv) return rv;
3801
+ mul->iter++;
3802
+ }
3803
+ mul->iter = -1;
3804
+ return NULL;
3805
+ }
3806
+
3807
+
3808
+ /* Get forward matching keys in a multiple database object.
3809
+ `mul' specifies the multiple database object.
3810
+ `pbuf' specifies the pointer to the region of the prefix.
3811
+ `psiz' specifies the size of the region of the prefix.
3812
+ `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is
3813
+ specified.
3814
+ The return value is a list object of the corresponding keys. */
3815
+ static TCLIST *tcadbmulfwmkeys(ADBMUL *mul, const void *pbuf, int psiz, int max){
3816
+ assert(mul && pbuf && psiz >= 0);
3817
+ if(!mul->adbs) return tclistnew2(1);
3818
+ if(max < 0) max = INT_MAX;
3819
+ TCADB **adbs = mul->adbs;
3820
+ int num = mul->num;
3821
+ TCLIST *rv = tclistnew();
3822
+ for(int i = 0; i < num && TCLISTNUM(rv) < max; i++){
3823
+ TCLIST *res = tcadbfwmkeys(adbs[i], pbuf, psiz, max);
3824
+ int rnum = TCLISTNUM(res);
3825
+ for(int j = 0; j < rnum && TCLISTNUM(rv) < max; j++){
3826
+ const char *vbuf;
3827
+ int vsiz;
3828
+ TCLISTVAL(vbuf, res, j, vsiz);
3829
+ TCLISTPUSH(rv, vbuf, vsiz);
3830
+ }
3831
+ tclistdel(res);
3832
+ }
3833
+ return rv;
3834
+ }
3835
+
3836
+
3837
+ /* Add an integer to a record in a multiple database object.
3838
+ `mul' specifies the multiple database object.
3839
+ `kbuf' specifies the pointer to the region of the key.
3840
+ `ksiz' specifies the size of the region of the key.
3841
+ `num' specifies the additional value.
3842
+ If successful, the return value is the summation value, else, it is `INT_MIN'. */
3843
+ static int tcadbmuladdint(ADBMUL *mul, const void *kbuf, int ksiz, int num){
3844
+ assert(mul && kbuf && ksiz >= 0);
3845
+ if(!mul->adbs) return INT_MIN;
3846
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3847
+ TCADB *adb = mul->adbs[idx];
3848
+ return tcadbaddint(adb, kbuf, ksiz, num);
3849
+ }
3850
+
3851
+
3852
+ /* Add a real number to a record in a multiple database object.
3853
+ `mul' specifies the multiple database object.
3854
+ `kbuf' specifies the pointer to the region of the key.
3855
+ `ksiz' specifies the size of the region of the key.
3856
+ `num' specifies the additional value.
3857
+ If successful, the return value is the summation value, else, it is Not-a-Number. */
3858
+ static double tcadbmuladddouble(ADBMUL *mul, const void *kbuf, int ksiz, double num){
3859
+ assert(mul && kbuf && ksiz >= 0);
3860
+ if(!mul->adbs) return nan("");
3861
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
3862
+ TCADB *adb = mul->adbs[idx];
3863
+ return tcadbadddouble(adb, kbuf, ksiz, num);
3864
+ }
3865
+
3866
+
3867
+ /* Synchronize updated contents of a multiple database object with the file and the device.
3868
+ `mul' specifies the multiple database object.
3869
+ If successful, the return value is true, else, it is false. */
3870
+ static bool tcadbmulsync(ADBMUL *mul){
3871
+ assert(mul);
3872
+ if(!mul->adbs) return false;
3873
+ TCADB **adbs = mul->adbs;
3874
+ int num = mul->num;
3875
+ bool err = false;
3876
+ for(int i = 0; i < num; i++){
3877
+ if(!tcadbsync(adbs[i])) err = true;
3878
+ }
3879
+ return !err;
3880
+ }
3881
+
3882
+
3883
+ /* Optimize the storage of a multiple database object.
3884
+ `mul' specifies the multiple database object.
3885
+ `params' specifies the string of the tuning parameters, which works as with the tuning
3886
+ of parameters the function `tcadbmulopen'.
3887
+ If successful, the return value is true, else, it is false. */
3888
+ static bool tcadbmuloptimize(ADBMUL *mul, const char *params){
3889
+ assert(mul);
3890
+ if(!mul->adbs) return false;
3891
+ mul->iter = -1;
3892
+ TCADB **adbs = mul->adbs;
3893
+ int num = mul->num;
3894
+ bool err = false;
3895
+ for(int i = 0; i < num; i++){
3896
+ if(!tcadboptimize(adbs[i], params)) err = true;
3897
+ }
3898
+ return !err;
3899
+ }
3900
+
3901
+
3902
+ /* Remove all records of a multiple database object.
3903
+ `mul' specifies the multiple database object.
3904
+ If successful, the return value is true, else, it is false. */
3905
+ static bool tcadbmulvanish(ADBMUL *mul){
3906
+ assert(mul);
3907
+ if(!mul->adbs) return false;
3908
+ mul->iter = -1;
3909
+ TCADB **adbs = mul->adbs;
3910
+ int num = mul->num;
3911
+ bool err = false;
3912
+ for(int i = 0; i < num; i++){
3913
+ if(!tcadbvanish(adbs[i])) err = true;
3914
+ }
3915
+ return !err;
3916
+ }
3917
+
3918
+
3919
+ /* Copy the database file of a multiple database object.
3920
+ `mul' specifies the multiple database object.
3921
+ `path' specifies the path of the destination file.
3922
+ If successful, the return value is true, else, it is false. False is returned if the executed
3923
+ command returns non-zero code. */
3924
+ static bool tcadbmulcopy(ADBMUL *mul, const char *path){
3925
+ assert(mul && path);
3926
+ TCADB **adbs = mul->adbs;
3927
+ int num = mul->num;
3928
+ bool err = false;
3929
+ if(*path == '@'){
3930
+ for(int i = 0; i < num; i++){
3931
+ if(!tcadbcopy(adbs[i], path)) err = true;
3932
+ }
3933
+ } else {
3934
+ if(mkdir(path, ADBDIRMODE) == -1 && errno != EEXIST) return false;
3935
+ for(int i = 0; i < num; i++){
3936
+ TCADB *adb = adbs[i];
3937
+ const char *cpath = tcadbpath(adb);
3938
+ if(cpath){
3939
+ const char *cname = strrchr(cpath, MYPATHCHR);
3940
+ cname = cname ? cname + 1 : cpath;
3941
+ const char *ext = strrchr(cname, MYEXTCHR);
3942
+ if(!ext) ext = "";
3943
+ char *npath = tcsprintf("%s%c%s%03d%s", path, MYPATHCHR, ADBMULPREFIX, i + 1, ext);
3944
+ if(!tcadbcopy(adb, npath)) err = true;
3945
+ TCFREE(npath);
3946
+ } else {
3947
+ err = true;
3948
+ }
3949
+ }
3950
+ }
3951
+ return !err;
3952
+ }
3953
+
3954
+
3955
+ /* Begin the transaction of a multiple database object.
3956
+ `mul' specifies the multiple database object.
3957
+ If successful, the return value is true, else, it is false. */
3958
+ static bool tcadbmultranbegin(ADBMUL *mul){
3959
+ assert(mul);
3960
+ if(!mul->adbs) return false;
3961
+ TCADB **adbs = mul->adbs;
3962
+ int num = mul->num;
3963
+ bool err = false;
3964
+ for(int i = 0; i < num; i++){
3965
+ if(!tcadbtranbegin(adbs[i])){
3966
+ while(--i >= 0){
3967
+ tcadbtranabort(adbs[i]);
3968
+ }
3969
+ err = true;
3970
+ break;
3971
+ }
3972
+ }
3973
+ return !err;
3974
+ }
3975
+
3976
+
3977
+ /* Commit the transaction of a multiple database object.
3978
+ `mul' specifies the multiple database object.
3979
+ If successful, the return value is true, else, it is false. */
3980
+ static bool tcadbmultrancommit(ADBMUL *mul){
3981
+ assert(mul);
3982
+ if(!mul->adbs) return false;
3983
+ TCADB **adbs = mul->adbs;
3984
+ int num = mul->num;
3985
+ bool err = false;
3986
+ for(int i = num - 1; i >= 0; i--){
3987
+ if(!tcadbtrancommit(adbs[i])) err = true;
3988
+ }
3989
+ return !err;
3990
+ }
3991
+
3992
+
3993
+ /* Abort the transaction of a multiple database object.
3994
+ `mul' specifies the multiple database object.
3995
+ If successful, the return value is true, else, it is false. */
3996
+ static bool tcadbmultranabort(ADBMUL *mul){
3997
+ assert(mul);
3998
+ if(!mul->adbs) return false;
3999
+ TCADB **adbs = mul->adbs;
4000
+ int num = mul->num;
4001
+ bool err = false;
4002
+ for(int i = num - 1; i >= 0; i--){
4003
+ if(!tcadbtranabort(adbs[i])) err = true;
4004
+ }
4005
+ return !err;
4006
+ }
4007
+
4008
+
4009
+ /* Get the file path of a multiple database object.
4010
+ `mul' specifies the multiple database object.
4011
+ The return value is the path of the database file or `NULL' if the object does not connect to
4012
+ any database. */
4013
+ static const char *tcadbmulpath(ADBMUL *mul){
4014
+ assert(mul);
4015
+ if(!mul->adbs) return NULL;
4016
+ return mul->path;
4017
+ }
4018
+
4019
+
4020
+ /* Get the number of records of a multiple database object.
4021
+ `mul' specifies the multiple database object.
4022
+ The return value is the number of records or 0 if the object does not connect to any database
4023
+ instance. */
4024
+ static uint64_t tcadbmulrnum(ADBMUL *mul){
4025
+ assert(mul);
4026
+ if(!mul->adbs) return 0;
4027
+ TCADB **adbs = mul->adbs;
4028
+ int num = mul->num;
4029
+ uint64_t rnum = 0;
4030
+ for(int i = 0; i < num; i++){
4031
+ rnum += tcadbrnum(adbs[i]);
4032
+ }
4033
+ return rnum;
4034
+ }
4035
+
4036
+
4037
+ /* Get the size of the database of a multiple database object.
4038
+ `mul' specifies the multiple database object.
4039
+ The return value is the size of the database or 0 if the object does not connect to any
4040
+ database instance. */
4041
+ static uint64_t tcadbmulsize(ADBMUL *mul){
4042
+ assert(mul);
4043
+ if(!mul->adbs) return 0;
4044
+ TCADB **adbs = mul->adbs;
4045
+ int num = mul->num;
4046
+ uint64_t size = 0;
4047
+ for(int i = 0; i < num; i++){
4048
+ size += tcadbsize(adbs[i]);
4049
+ }
4050
+ return size;
4051
+ }
4052
+
4053
+
4054
+ /* Call a versatile function for miscellaneous operations of a multiple database object.
4055
+ `mul' specifies the multiple database object.
4056
+ `name' specifies the name of the function.
4057
+ `args' specifies a list object containing arguments.
4058
+ If successful, the return value is a list object of the result. */
4059
+ static TCLIST *tcadbmulmisc(ADBMUL *mul, const char *name, const TCLIST *args){
4060
+ assert(mul && name);
4061
+ if(!mul->adbs) return NULL;
4062
+ TCADB **adbs = mul->adbs;
4063
+ int num = mul->num;
4064
+ TCLIST *rv = tclistnew();
4065
+ if(*name == '@'){
4066
+ name++;
4067
+ int anum = TCLISTNUM(args) - 1;
4068
+ TCLIST *targs = tclistnew2(2);
4069
+ for(int i = 0; i < anum; i++){
4070
+ const char *kbuf;
4071
+ int ksiz;
4072
+ TCLISTVAL(kbuf, args, i, ksiz);
4073
+ tclistclear(targs);
4074
+ TCLISTPUSH(targs, kbuf, ksiz);
4075
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
4076
+ TCADB *adb = mul->adbs[idx];
4077
+ TCLIST *res = tcadbmisc(adb, name, targs);
4078
+ if(res){
4079
+ int rnum = TCLISTNUM(res);
4080
+ for(int j = 0; j < rnum; j++){
4081
+ const char *vbuf;
4082
+ int vsiz;
4083
+ TCLISTVAL(vbuf, res, j, vsiz);
4084
+ TCLISTPUSH(rv, vbuf, vsiz);
4085
+ }
4086
+ tclistdel(res);
4087
+ }
4088
+ }
4089
+ tclistdel(targs);
4090
+ } else if(*name == '%'){
4091
+ name++;
4092
+ int anum = TCLISTNUM(args) - 1;
4093
+ TCLIST *targs = tclistnew2(2);
4094
+ for(int i = 0; i < anum; i += 2){
4095
+ const char *kbuf, *vbuf;
4096
+ int ksiz, vsiz;
4097
+ TCLISTVAL(kbuf, args, i, ksiz);
4098
+ TCLISTVAL(vbuf, args, i + 1, vsiz);
4099
+ tclistclear(targs);
4100
+ TCLISTPUSH(targs, kbuf, ksiz);
4101
+ TCLISTPUSH(targs, vbuf, vsiz);
4102
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
4103
+ TCADB *adb = mul->adbs[idx];
4104
+ TCLIST *res = tcadbmisc(adb, name, targs);
4105
+ if(res){
4106
+ int rnum = TCLISTNUM(res);
4107
+ for(int j = 0; j < rnum; j++){
4108
+ TCLISTVAL(vbuf, res, j, vsiz);
4109
+ TCLISTPUSH(rv, vbuf, vsiz);
4110
+ }
4111
+ tclistdel(res);
4112
+ }
4113
+ }
4114
+ tclistdel(targs);
4115
+ } else {
4116
+ for(int i = 0; i < num; i++){
4117
+ TCLIST *res = tcadbmisc(adbs[i], name, args);
4118
+ if(res){
4119
+ int rnum = TCLISTNUM(res);
4120
+ for(int j = 0; j < rnum; j++){
4121
+ const char *vbuf;
4122
+ int vsiz;
4123
+ TCLISTVAL(vbuf, res, j, vsiz);
4124
+ TCLISTPUSH(rv, vbuf, vsiz);
4125
+ }
4126
+ tclistdel(res);
4127
+ } else {
4128
+ tclistdel(rv);
4129
+ rv = NULL;
4130
+ break;
4131
+ }
4132
+ }
4133
+ }
4134
+ return rv;
4135
+ }
4136
+
4137
+
4138
+ /* Store a record into a multiple database object with a duplication handler.
4139
+ `mul' specifies the multiple database object.
4140
+ `kbuf' specifies the pointer to the region of the key.
4141
+ `ksiz' specifies the size of the region of the key.
4142
+ `vbuf' specifies the pointer to the region of the value.
4143
+ `vsiz' specifies the size of the region of the value.
4144
+ `proc' specifies the pointer to the callback function to process duplication.
4145
+ `op' specifies an arbitrary pointer to be given as a parameter of the callback function.
4146
+ If successful, the return value is true, else, it is false. */
4147
+ static bool tcadbmulputproc(ADBMUL *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz,
4148
+ TCPDPROC proc, void *op){
4149
+ assert(mul && kbuf && ksiz >= 0 && proc);
4150
+ if(!mul->adbs) return false;
4151
+ int idx = tcadbmulidx(mul, kbuf, ksiz);
4152
+ TCADB *adb = mul->adbs[idx];
4153
+ return tcadbputproc(adb, kbuf, ksiz, vbuf, vsiz, proc, op);
4154
+ }
4155
+
4156
+
4157
+ /* Process each record atomically of a multiple database object.
4158
+ `mul' specifies the multiple database object.
4159
+ `iter' specifies the pointer to the iterator function called for each record.
4160
+ `op' specifies an arbitrary pointer to be given as a parameter of the iterator function.
4161
+ If successful, the return value is true, else, it is false. */
4162
+ static bool tcadbmulforeach(ADBMUL *mul, TCITER iter, void *op){
4163
+ assert(mul && iter);
4164
+ if(!mul->adbs) return false;
4165
+ TCADB **adbs = mul->adbs;
4166
+ int num = mul->num;
4167
+ bool err = false;
4168
+ for(int i = 0; i < num; i++){
4169
+ if(!tcadbforeach(adbs[i], iter, op)){
4170
+ err = true;
4171
+ break;
4172
+ }
4173
+ }
4174
+ return !err;
4175
+ }
4176
+
4177
+
4178
+ /* Get the database index of a multiple database object.
4179
+ `mul' specifies the multiple database object.
4180
+ `kbuf' specifies the pointer to the region of the key.
4181
+ `ksiz' specifies the size of the region of the key.
4182
+ The return value is the bucket index. */
4183
+ static int tcadbmulidx(ADBMUL *mul, const void *kbuf, int ksiz){
4184
+ assert(mul && kbuf && ksiz >= 0);
4185
+ uint32_t hash = 20090810;
4186
+ const char *rp = (char *)kbuf + ksiz;
4187
+ while(ksiz--){
4188
+ hash = (hash * 29) ^ *(uint8_t *)--rp;
4189
+ }
4190
+ return hash % mul->num;
4191
+ }
4192
+
4193
+
4194
+ /* Call the mapping function for every record of a multiple database object.
4195
+ `kbuf' specifies the pointer to the region of the key.
4196
+ `ksiz' specifies the size of the region of the key.
4197
+ `vbuf' specifies the pointer to the region of the value.
4198
+ `vsiz' specifies the size of the region of the value.
4199
+ `op' specifies the pointer to the optional opaque object.
4200
+ The return value is true to continue iteration or false to stop iteration. */
4201
+ static bool tcadbmapbdbiter(const void *kbuf, int ksiz, const void *vbuf, int vsiz, void *op){
4202
+ assert(kbuf && ksiz >= 0 && vbuf && vsiz >= 0 && op);
4203
+ ADBMAPBDB *map = op;
4204
+ bool err = false;
4205
+ if(!map->proc(map, kbuf, ksiz, vbuf, vsiz, map->op)) err = true;
4206
+ return !err;
4207
+ }
4208
+
4209
+
4210
+ /* Dump all cached records into the B+ tree database.
4211
+ `map' specifies the mapper object for the B+ tree database.
4212
+ The return value is true if successful, else, it is false. */
4213
+ static bool tcadbmapbdbdump(ADBMAPBDB *map){
4214
+ assert(map);
4215
+ TCBDB *bdb = map->bdb;
4216
+ TCLIST *recs = map->recs;
4217
+ int rnum = TCLISTNUM(recs);
4218
+ TCCMP cmp = tcbdbcmpfunc(bdb);
4219
+ if(cmp == tccmplexical){
4220
+ tclistsortex(recs, tcadbmapreccmplexical);
4221
+ } else if(cmp == tccmpdecimal){
4222
+ tclistsortex(recs, tcadbmapreccmpdecimal);
4223
+ } else if(cmp == tccmpint32){
4224
+ tclistsortex(recs, tcadbmapreccmpint32);
4225
+ } else if(cmp == tccmpint64){
4226
+ tclistsortex(recs, tcadbmapreccmpint64);
4227
+ }
4228
+ bool err = false;
4229
+ for(int i = 0; i < rnum; i++){
4230
+ const char *rbuf;
4231
+ int rsiz;
4232
+ TCLISTVAL(rbuf, recs, i, rsiz);
4233
+ int ksiz;
4234
+ memcpy(&ksiz, rbuf, sizeof(ksiz));
4235
+ const char *kbuf = rbuf + sizeof(ksiz);
4236
+ if(!tcbdbputdup(bdb, kbuf, ksiz, kbuf + ksiz, rsiz - sizeof(ksiz) - ksiz)){
4237
+ err = true;
4238
+ break;
4239
+ }
4240
+ }
4241
+ tclistclear(recs);
4242
+ map->rsiz = 0;
4243
+ return !err;
4244
+ }
4245
+
4246
+
4247
+ /* Compare two list elements by lexical order for mapping.
4248
+ `a' specifies the pointer to one element.
4249
+ `b' specifies the pointer to the other element.
4250
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
4251
+ are equivalent. */
4252
+ static int tcadbmapreccmplexical(const TCLISTDATUM *a, const TCLISTDATUM *b){
4253
+ assert(a && b);
4254
+ unsigned char *ao = (unsigned char *)((TCLISTDATUM *)a)->ptr;
4255
+ unsigned char *bo = (unsigned char *)((TCLISTDATUM *)b)->ptr;
4256
+ int size = (((TCLISTDATUM *)a)->size < ((TCLISTDATUM *)b)->size) ?
4257
+ ((TCLISTDATUM *)a)->size : ((TCLISTDATUM *)b)->size;
4258
+ for(int i = sizeof(int); i < size; i++){
4259
+ if(ao[i] > bo[i]) return 1;
4260
+ if(ao[i] < bo[i]) return -1;
4261
+ }
4262
+ return ((TCLISTDATUM *)a)->size - ((TCLISTDATUM *)b)->size;
4263
+ }
4264
+
4265
+
4266
+ /* Compare two keys as decimal strings of real numbers for mapping.
4267
+ `a' specifies the pointer to one element.
4268
+ `b' specifies the pointer to the other element.
4269
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
4270
+ are equivalent. */
4271
+ static int tcadbmapreccmpdecimal(const TCLISTDATUM *a, const TCLISTDATUM *b){
4272
+ assert(a && b);
4273
+ return tccmpdecimal(((TCLISTDATUM *)a)->ptr + sizeof(int), a->size - sizeof(int),
4274
+ ((TCLISTDATUM *)b)->ptr + sizeof(int), b->size - sizeof(int), NULL);
4275
+ }
4276
+
4277
+
4278
+ /* Compare two list elements as 32-bit integers in the native byte order for mapping.
4279
+ `a' specifies the pointer to one element.
4280
+ `b' specifies the pointer to the other element.
4281
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
4282
+ are equivalent. */
4283
+ static int tcadbmapreccmpint32(const TCLISTDATUM *a, const TCLISTDATUM *b){
4284
+ assert(a && b);
4285
+ return tccmpint32(((TCLISTDATUM *)a)->ptr + sizeof(int), a->size - sizeof(int),
4286
+ ((TCLISTDATUM *)b)->ptr + sizeof(int), b->size - sizeof(int), NULL);
4287
+ }
4288
+
4289
+
4290
+ /* Compare two list elements as 64-bit integers in the native byte order for mapping.
4291
+ `a' specifies the pointer to one element.
4292
+ `b' specifies the pointer to the other element.
4293
+ The return value is positive if the former is big, negative if the latter is big, 0 if both
4294
+ are equivalent. */
4295
+ static int tcadbmapreccmpint64(const TCLISTDATUM *a, const TCLISTDATUM *b){
4296
+ assert(a && b);
4297
+ return tccmpint64(((TCLISTDATUM *)a)->ptr + sizeof(int), a->size - sizeof(int),
4298
+ ((TCLISTDATUM *)b)->ptr + sizeof(int), b->size - sizeof(int), NULL);
4299
+ }
4300
+
4301
+
4302
+ /* Retrieve and remove each record corresponding to a query object.
4303
+ `pkbuf' specifies the pointer to the region of the primary key.
4304
+ `pksiz' specifies the size of the region of the primary key.
4305
+ `cols' specifies a map object containing columns.
4306
+ `op' specifies the pointer to the optional opaque object.
4307
+ The return value is flags of the post treatment by bitwise-or.
4308
+ If successful, the return value is true, else, it is false. */
4309
+ static int tcadbtdbqrygetout(const void *pkbuf, int pksiz, TCMAP *cols, void *op){
4310
+ TCLIST *rv = ((void **)op)[0];
4311
+ TCLIST *cnames = ((void **)op)[1];
4312
+ int cnnum = TCLISTNUM(cnames);
4313
+ tcmapput(cols, "", 0, pkbuf, pksiz);
4314
+ tcmapmove(cols, "", 0, true);
4315
+ if(cnnum > 0){
4316
+ TCMAP *ncols = tcmapnew2(cnnum + 1);
4317
+ for(int j = 0; j < cnnum; j++){
4318
+ const char *cname;
4319
+ int cnsiz;
4320
+ TCLISTVAL(cname, cnames, j, cnsiz);
4321
+ int cvsiz;
4322
+ const char *cvalue = tcmapget(cols, cname, cnsiz, &cvsiz);
4323
+ if(cvalue) tcmapput(ncols, cname, cnsiz, cvalue, cvsiz);
4324
+ }
4325
+ int csiz;
4326
+ char *cbuf = tcstrjoin4(ncols, &csiz);
4327
+ tclistpushmalloc(rv, cbuf, csiz);
4328
+ tcmapdel(ncols);
4329
+ } else {
4330
+ int csiz;
4331
+ char *cbuf = tcstrjoin4(cols, &csiz);
4332
+ tclistpushmalloc(rv, cbuf, csiz);
4333
+ }
4334
+ return TDBQPOUT;
4335
+ }
4336
+
4337
+
4338
+
4339
+ // END OF FILE