00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <tcl.h>
00018 #endif
00019
00020 #include "db_int.h"
00021 #include "dbinc/db_page.h"
00022 #include "dbinc/db_am.h"
00023 #include "dbinc/tcl_db.h"
00024
00025
00026
00027
00028 static int tcl_DbAssociate __P((Tcl_Interp *,
00029 int, Tcl_Obj * CONST*, DB *));
00030 static int tcl_DbClose __P((Tcl_Interp *,
00031 int, Tcl_Obj * CONST*, DB *, DBTCL_INFO *));
00032 static int tcl_DbDelete __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00033 static int tcl_DbGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *, int));
00034 #ifdef CONFIG_TEST
00035 static int tcl_DbKeyRange __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00036 #endif
00037 static int tcl_DbPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00038 static int tcl_DbStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00039 static int tcl_DbTruncate __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00040 #ifdef CONFIG_TEST
00041 static int tcl_DbCompact __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00042 static int tcl_DbCompactStat __P((Tcl_Interp *,
00043 int, Tcl_Obj * CONST*, DB *));
00044 #endif
00045 static int tcl_DbCursor __P((Tcl_Interp *,
00046 int, Tcl_Obj * CONST*, DB *, DBC **));
00047 static int tcl_DbJoin __P((Tcl_Interp *,
00048 int, Tcl_Obj * CONST*, DB *, DBC **));
00049 static int tcl_DbGetFlags __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00050 static int tcl_DbGetOpenFlags __P((Tcl_Interp *,
00051 int, Tcl_Obj * CONST*, DB *));
00052 static int tcl_DbGetjoin __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00053 static int tcl_DbCount __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB *));
00054 static int tcl_second_call __P((DB *, const DBT *, const DBT *, DBT *));
00055
00056
00057
00058
00059
00060
00061 void
00062 _DbInfoDelete(interp, dbip)
00063 Tcl_Interp *interp;
00064 DBTCL_INFO *dbip;
00065 {
00066 DBTCL_INFO *nextp, *p;
00067
00068
00069
00070
00071 for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
00072 nextp = LIST_NEXT(p, entries);
00073
00074
00075
00076
00077
00078 if (p->i_parent == dbip && p->i_type == I_DBC) {
00079 (void)Tcl_DeleteCommand(interp, p->i_name);
00080 _DeleteInfo(p);
00081 }
00082 }
00083 (void)Tcl_DeleteCommand(interp, dbip->i_name);
00084 _DeleteInfo(dbip);
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094 int
00095 db_Cmd(clientData, interp, objc, objv)
00096 ClientData clientData;
00097 Tcl_Interp *interp;
00098 int objc;
00099 Tcl_Obj *CONST objv[];
00100 {
00101 static const char *dbcmds[] = {
00102 #ifdef CONFIG_TEST
00103 "keyrange",
00104 "pget",
00105 "rpcid",
00106 "test",
00107 "compact",
00108 "compact_stat",
00109 #endif
00110 "associate",
00111 "close",
00112 "count",
00113 "cursor",
00114 "del",
00115 "get",
00116 "get_bt_minkey",
00117 "get_cachesize",
00118 "get_dbname",
00119 "get_encrypt_flags",
00120 "get_env",
00121 "get_errpfx",
00122 "get_flags",
00123 "get_h_ffactor",
00124 "get_h_nelem",
00125 "get_join",
00126 "get_lorder",
00127 "get_open_flags",
00128 "get_pagesize",
00129 "get_q_extentsize",
00130 "get_re_delim",
00131 "get_re_len",
00132 "get_re_pad",
00133 "get_re_source",
00134 "get_type",
00135 "is_byteswapped",
00136 "join",
00137 "put",
00138 "stat",
00139 "sync",
00140 "truncate",
00141 NULL
00142 };
00143 enum dbcmds {
00144 #ifdef CONFIG_TEST
00145 DBKEYRANGE,
00146 DBPGET,
00147 DBRPCID,
00148 DBTEST,
00149 DBCOMPACT,
00150 DBCOMPACT_STAT,
00151 #endif
00152 DBASSOCIATE,
00153 DBCLOSE,
00154 DBCOUNT,
00155 DBCURSOR,
00156 DBDELETE,
00157 DBGET,
00158 DBGETBTMINKEY,
00159 DBGETCACHESIZE,
00160 DBGETDBNAME,
00161 DBGETENCRYPTFLAGS,
00162 DBGETENV,
00163 DBGETERRPFX,
00164 DBGETFLAGS,
00165 DBGETHFFACTOR,
00166 DBGETHNELEM,
00167 DBGETJOIN,
00168 DBGETLORDER,
00169 DBGETOPENFLAGS,
00170 DBGETPAGESIZE,
00171 DBGETQEXTENTSIZE,
00172 DBGETREDELIM,
00173 DBGETRELEN,
00174 DBGETREPAD,
00175 DBGETRESOURCE,
00176 DBGETTYPE,
00177 DBSWAPPED,
00178 DBJOIN,
00179 DBPUT,
00180 DBSTAT,
00181 DBSYNC,
00182 DBTRUNCATE
00183 };
00184 DB *dbp;
00185 DB_ENV *dbenv;
00186 DBC *dbc;
00187 DBTCL_INFO *dbip, *ip;
00188 DBTYPE type;
00189 Tcl_Obj *res, *myobjv[3];
00190 int cmdindex, intval, ncache, result, ret;
00191 char newname[MSG_SIZE];
00192 u_int32_t bytes, gbytes, value;
00193 const char *strval, *filename, *dbname, *envid;
00194
00195 Tcl_ResetResult(interp);
00196 dbp = (DB *)clientData;
00197 dbip = _PtrToInfo((void *)dbp);
00198 memset(newname, 0, MSG_SIZE);
00199 result = TCL_OK;
00200 if (objc <= 1) {
00201 Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
00202 return (TCL_ERROR);
00203 }
00204 if (dbp == NULL) {
00205 Tcl_SetResult(interp, "NULL db pointer", TCL_STATIC);
00206 return (TCL_ERROR);
00207 }
00208 if (dbip == NULL) {
00209 Tcl_SetResult(interp, "NULL db info pointer", TCL_STATIC);
00210 return (TCL_ERROR);
00211 }
00212
00213
00214
00215
00216
00217 if (Tcl_GetIndexFromObj(interp,
00218 objv[1], dbcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
00219 return (IS_HELP(objv[1]));
00220
00221 res = NULL;
00222 switch ((enum dbcmds)cmdindex) {
00223 #ifdef CONFIG_TEST
00224 case DBKEYRANGE:
00225 result = tcl_DbKeyRange(interp, objc, objv, dbp);
00226 break;
00227 case DBPGET:
00228 result = tcl_DbGet(interp, objc, objv, dbp, 1);
00229 break;
00230 case DBRPCID:
00231
00232
00233
00234 if (objc > 2) {
00235 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00236 return (TCL_ERROR);
00237 }
00238
00239
00240
00241
00242 res = Tcl_NewLongObj((long)dbp->cl_id);
00243 break;
00244 case DBTEST:
00245 result = tcl_EnvTest(interp, objc, objv, dbp->dbenv);
00246 break;
00247
00248 case DBCOMPACT:
00249 result = tcl_DbCompact(interp, objc, objv, dbp);
00250 break;
00251
00252 case DBCOMPACT_STAT:
00253 result = tcl_DbCompactStat(interp, objc, objv, dbp);
00254 break;
00255
00256 #endif
00257 case DBASSOCIATE:
00258 result = tcl_DbAssociate(interp, objc, objv, dbp);
00259 break;
00260 case DBCLOSE:
00261 result = tcl_DbClose(interp, objc, objv, dbp, dbip);
00262 break;
00263 case DBDELETE:
00264 result = tcl_DbDelete(interp, objc, objv, dbp);
00265 break;
00266 case DBGET:
00267 result = tcl_DbGet(interp, objc, objv, dbp, 0);
00268 break;
00269 case DBPUT:
00270 result = tcl_DbPut(interp, objc, objv, dbp);
00271 break;
00272 case DBCOUNT:
00273 result = tcl_DbCount(interp, objc, objv, dbp);
00274 break;
00275 case DBSWAPPED:
00276
00277
00278
00279 if (objc > 2) {
00280 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00281 return (TCL_ERROR);
00282 }
00283 _debug_check();
00284 ret = dbp->get_byteswapped(dbp, &intval);
00285 res = Tcl_NewIntObj(intval);
00286 break;
00287 case DBGETTYPE:
00288
00289
00290
00291 if (objc > 2) {
00292 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00293 return (TCL_ERROR);
00294 }
00295 _debug_check();
00296 ret = dbp->get_type(dbp, &type);
00297 if (type == DB_BTREE)
00298 res = NewStringObj("btree", strlen("btree"));
00299 else if (type == DB_HASH)
00300 res = NewStringObj("hash", strlen("hash"));
00301 else if (type == DB_RECNO)
00302 res = NewStringObj("recno", strlen("recno"));
00303 else if (type == DB_QUEUE)
00304 res = NewStringObj("queue", strlen("queue"));
00305 else {
00306 Tcl_SetResult(interp,
00307 "db gettype: Returned unknown type\n", TCL_STATIC);
00308 result = TCL_ERROR;
00309 }
00310 break;
00311 case DBSTAT:
00312 result = tcl_DbStat(interp, objc, objv, dbp);
00313 break;
00314 case DBSYNC:
00315
00316
00317
00318 if (objc > 2) {
00319 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00320 return (TCL_ERROR);
00321 }
00322 _debug_check();
00323 ret = dbp->sync(dbp, 0);
00324 res = Tcl_NewIntObj(ret);
00325 if (ret != 0) {
00326 Tcl_SetObjResult(interp, res);
00327 result = TCL_ERROR;
00328 }
00329 break;
00330 case DBCURSOR:
00331 snprintf(newname, sizeof(newname),
00332 "%s.c%d", dbip->i_name, dbip->i_dbdbcid);
00333 ip = _NewInfo(interp, NULL, newname, I_DBC);
00334 if (ip != NULL) {
00335 result = tcl_DbCursor(interp, objc, objv, dbp, &dbc);
00336 if (result == TCL_OK) {
00337 dbip->i_dbdbcid++;
00338 ip->i_parent = dbip;
00339 (void)Tcl_CreateObjCommand(interp, newname,
00340 (Tcl_ObjCmdProc *)dbc_Cmd,
00341 (ClientData)dbc, NULL);
00342 res = NewStringObj(newname, strlen(newname));
00343 _SetInfoData(ip, dbc);
00344 } else
00345 _DeleteInfo(ip);
00346 } else {
00347 Tcl_SetResult(interp,
00348 "Could not set up info", TCL_STATIC);
00349 result = TCL_ERROR;
00350 }
00351 break;
00352 case DBJOIN:
00353 snprintf(newname, sizeof(newname),
00354 "%s.c%d", dbip->i_name, dbip->i_dbdbcid);
00355 ip = _NewInfo(interp, NULL, newname, I_DBC);
00356 if (ip != NULL) {
00357 result = tcl_DbJoin(interp, objc, objv, dbp, &dbc);
00358 if (result == TCL_OK) {
00359 dbip->i_dbdbcid++;
00360 ip->i_parent = dbip;
00361 (void)Tcl_CreateObjCommand(interp, newname,
00362 (Tcl_ObjCmdProc *)dbc_Cmd,
00363 (ClientData)dbc, NULL);
00364 res = NewStringObj(newname, strlen(newname));
00365 _SetInfoData(ip, dbc);
00366 } else
00367 _DeleteInfo(ip);
00368 } else {
00369 Tcl_SetResult(interp,
00370 "Could not set up info", TCL_STATIC);
00371 result = TCL_ERROR;
00372 }
00373 break;
00374 case DBGETBTMINKEY:
00375 if (objc != 2) {
00376 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00377 return (TCL_ERROR);
00378 }
00379 ret = dbp->get_bt_minkey(dbp, &value);
00380 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00381 "db get_bt_minkey")) == TCL_OK)
00382 res = Tcl_NewIntObj((int)value);
00383 break;
00384 case DBGETCACHESIZE:
00385 if (objc != 2) {
00386 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00387 return (TCL_ERROR);
00388 }
00389 ret = dbp->get_cachesize(dbp, &gbytes, &bytes, &ncache);
00390 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00391 "db get_cachesize")) == TCL_OK) {
00392 myobjv[0] = Tcl_NewIntObj((int)gbytes);
00393 myobjv[1] = Tcl_NewIntObj((int)bytes);
00394 myobjv[2] = Tcl_NewIntObj((int)ncache);
00395 res = Tcl_NewListObj(3, myobjv);
00396 }
00397 break;
00398 case DBGETDBNAME:
00399 if (objc != 2) {
00400 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00401 return (TCL_ERROR);
00402 }
00403 ret = dbp->get_dbname(dbp, &filename, &dbname);
00404 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00405 "db get_dbname")) == TCL_OK) {
00406 myobjv[0] = NewStringObj(filename, strlen(filename));
00407 myobjv[1] = NewStringObj(dbname, strlen(dbname));
00408 res = Tcl_NewListObj(2, myobjv);
00409 }
00410 break;
00411 case DBGETENCRYPTFLAGS:
00412 result = tcl_EnvGetEncryptFlags(interp, objc, objv, dbp->dbenv);
00413 break;
00414 case DBGETENV:
00415 if (objc != 2) {
00416 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00417 return (TCL_ERROR);
00418 }
00419 dbenv = dbp->get_env(dbp);
00420 if (dbenv != NULL && (ip = _PtrToInfo(dbenv)) != NULL) {
00421 envid = ip->i_name;
00422 res = NewStringObj(envid, strlen(envid));
00423 } else
00424 Tcl_ResetResult(interp);
00425 break;
00426 case DBGETERRPFX:
00427 if (objc != 2) {
00428 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00429 return (TCL_ERROR);
00430 }
00431 dbp->get_errpfx(dbp, &strval);
00432 res = NewStringObj(strval, strlen(strval));
00433 break;
00434 case DBGETFLAGS:
00435 result = tcl_DbGetFlags(interp, objc, objv, dbp);
00436 break;
00437 case DBGETHFFACTOR:
00438 if (objc != 2) {
00439 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00440 return (TCL_ERROR);
00441 }
00442 ret = dbp->get_h_ffactor(dbp, &value);
00443 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00444 "db get_h_ffactor")) == TCL_OK)
00445 res = Tcl_NewIntObj((int)value);
00446 break;
00447 case DBGETHNELEM:
00448 if (objc != 2) {
00449 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00450 return (TCL_ERROR);
00451 }
00452 ret = dbp->get_h_nelem(dbp, &value);
00453 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00454 "db get_h_nelem")) == TCL_OK)
00455 res = Tcl_NewIntObj((int)value);
00456 break;
00457 case DBGETJOIN:
00458 result = tcl_DbGetjoin(interp, objc, objv, dbp);
00459 break;
00460 case DBGETLORDER:
00461
00462
00463
00464 if (objc > 2) {
00465 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00466 return (TCL_ERROR);
00467 }
00468 _debug_check();
00469 ret = dbp->get_lorder(dbp, &intval);
00470 res = Tcl_NewIntObj(intval);
00471 break;
00472 case DBGETOPENFLAGS:
00473 result = tcl_DbGetOpenFlags(interp, objc, objv, dbp);
00474 break;
00475 case DBGETPAGESIZE:
00476 if (objc != 2) {
00477 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00478 return (TCL_ERROR);
00479 }
00480 ret = dbp->get_pagesize(dbp, &value);
00481 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00482 "db get_pagesize")) == TCL_OK)
00483 res = Tcl_NewIntObj((int)value);
00484 break;
00485 case DBGETQEXTENTSIZE:
00486 if (objc != 2) {
00487 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00488 return (TCL_ERROR);
00489 }
00490 ret = dbp->get_q_extentsize(dbp, &value);
00491 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00492 "db get_q_extentsize")) == TCL_OK)
00493 res = Tcl_NewIntObj((int)value);
00494 break;
00495 case DBGETREDELIM:
00496 if (objc != 2) {
00497 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00498 return (TCL_ERROR);
00499 }
00500 ret = dbp->get_re_delim(dbp, &intval);
00501 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00502 "db get_re_delim")) == TCL_OK)
00503 res = Tcl_NewIntObj(intval);
00504 break;
00505 case DBGETRELEN:
00506 if (objc != 2) {
00507 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00508 return (TCL_ERROR);
00509 }
00510 ret = dbp->get_re_len(dbp, &value);
00511 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00512 "db get_re_len")) == TCL_OK)
00513 res = Tcl_NewIntObj((int)value);
00514 break;
00515 case DBGETREPAD:
00516 if (objc != 2) {
00517 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00518 return (TCL_ERROR);
00519 }
00520 ret = dbp->get_re_pad(dbp, &intval);
00521 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00522 "db get_re_pad")) == TCL_OK)
00523 res = Tcl_NewIntObj((int)intval);
00524 break;
00525 case DBGETRESOURCE:
00526 if (objc != 2) {
00527 Tcl_WrongNumArgs(interp, 1, objv, NULL);
00528 return (TCL_ERROR);
00529 }
00530 ret = dbp->get_re_source(dbp, &strval);
00531 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00532 "db get_re_source")) == TCL_OK)
00533 res = NewStringObj(strval, strlen(strval));
00534 break;
00535 case DBTRUNCATE:
00536 result = tcl_DbTruncate(interp, objc, objv, dbp);
00537 break;
00538 }
00539
00540
00541
00542
00543 if (result == TCL_OK && res)
00544 Tcl_SetObjResult(interp, res);
00545 return (result);
00546 }
00547
00548
00549
00550
00551 static int
00552 tcl_DbStat(interp, objc, objv, dbp)
00553 Tcl_Interp *interp;
00554 int objc;
00555 Tcl_Obj *CONST objv[];
00556 DB *dbp;
00557 {
00558 static const char *dbstatopts[] = {
00559 #ifdef CONFIG_TEST
00560 "-read_committed",
00561 "-read_uncommitted",
00562 #endif
00563 "-faststat",
00564 "-txn",
00565 NULL
00566 };
00567 enum dbstatopts {
00568 #ifdef CONFIG_TEST
00569 DBCUR_READ_COMMITTED,
00570 DBCUR_READ_UNCOMMITTED,
00571 #endif
00572 DBCUR_FASTSTAT,
00573 DBCUR_TXN
00574 };
00575 DBTYPE type;
00576 DB_BTREE_STAT *bsp;
00577 DB_HASH_STAT *hsp;
00578 DB_QUEUE_STAT *qsp;
00579 DB_TXN *txn;
00580 Tcl_Obj *res, *flaglist, *myobjv[2];
00581 u_int32_t flag;
00582 int i, optindex, result, ret;
00583 char *arg, msg[MSG_SIZE];
00584 void *sp;
00585
00586 result = TCL_OK;
00587 flag = 0;
00588 txn = NULL;
00589 sp = NULL;
00590 i = 2;
00591 while (i < objc) {
00592 if (Tcl_GetIndexFromObj(interp, objv[i], dbstatopts, "option",
00593 TCL_EXACT, &optindex) != TCL_OK) {
00594 result = IS_HELP(objv[i]);
00595 goto error;
00596 }
00597 i++;
00598 switch ((enum dbstatopts)optindex) {
00599 #ifdef CONFIG_TEST
00600 case DBCUR_READ_COMMITTED:
00601 flag |= DB_READ_COMMITTED;
00602 break;
00603 case DBCUR_READ_UNCOMMITTED:
00604 flag |= DB_READ_UNCOMMITTED;
00605 break;
00606 #endif
00607 case DBCUR_FASTSTAT:
00608 flag |= DB_FAST_STAT;
00609 break;
00610 case DBCUR_TXN:
00611 if (i == objc) {
00612 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
00613 result = TCL_ERROR;
00614 break;
00615 }
00616 arg = Tcl_GetStringFromObj(objv[i++], NULL);
00617 txn = NAME_TO_TXN(arg);
00618 if (txn == NULL) {
00619 snprintf(msg, MSG_SIZE,
00620 "Stat: Invalid txn: %s\n", arg);
00621 Tcl_SetResult(interp, msg, TCL_VOLATILE);
00622 result = TCL_ERROR;
00623 }
00624 break;
00625 }
00626 if (result != TCL_OK)
00627 break;
00628 }
00629 if (result != TCL_OK)
00630 goto error;
00631
00632 _debug_check();
00633 ret = dbp->stat(dbp, txn, &sp, flag);
00634 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db stat");
00635 if (result == TCL_ERROR)
00636 return (result);
00637
00638 (void)dbp->get_type(dbp, &type);
00639
00640
00641
00642
00643 res = Tcl_NewObj();
00644
00645
00646
00647
00648 if (type == DB_HASH) {
00649 hsp = (DB_HASH_STAT *)sp;
00650 MAKE_STAT_LIST("Magic", hsp->hash_magic);
00651 MAKE_STAT_LIST("Version", hsp->hash_version);
00652 MAKE_STAT_LIST("Page size", hsp->hash_pagesize);
00653 MAKE_STAT_LIST("Number of keys", hsp->hash_nkeys);
00654 MAKE_STAT_LIST("Number of records", hsp->hash_ndata);
00655 MAKE_STAT_LIST("Fill factor", hsp->hash_ffactor);
00656 MAKE_STAT_LIST("Buckets", hsp->hash_buckets);
00657 if (flag != DB_FAST_STAT) {
00658 MAKE_STAT_LIST("Free pages", hsp->hash_free);
00659 MAKE_STAT_LIST("Bytes free", hsp->hash_bfree);
00660 MAKE_STAT_LIST("Number of big pages",
00661 hsp->hash_bigpages);
00662 MAKE_STAT_LIST("Big pages bytes free",
00663 hsp->hash_big_bfree);
00664 MAKE_STAT_LIST("Overflow pages", hsp->hash_overflows);
00665 MAKE_STAT_LIST("Overflow bytes free",
00666 hsp->hash_ovfl_free);
00667 MAKE_STAT_LIST("Duplicate pages", hsp->hash_dup);
00668 MAKE_STAT_LIST("Duplicate pages bytes free",
00669 hsp->hash_dup_free);
00670 }
00671 } else if (type == DB_QUEUE) {
00672 qsp = (DB_QUEUE_STAT *)sp;
00673 MAKE_STAT_LIST("Magic", qsp->qs_magic);
00674 MAKE_STAT_LIST("Version", qsp->qs_version);
00675 MAKE_STAT_LIST("Page size", qsp->qs_pagesize);
00676 MAKE_STAT_LIST("Extent size", qsp->qs_extentsize);
00677 MAKE_STAT_LIST("Number of records", qsp->qs_nkeys);
00678 MAKE_STAT_LIST("Record length", qsp->qs_re_len);
00679 MAKE_STAT_LIST("Record pad", qsp->qs_re_pad);
00680 MAKE_STAT_LIST("First record number", qsp->qs_first_recno);
00681 MAKE_STAT_LIST("Last record number", qsp->qs_cur_recno);
00682 if (flag != DB_FAST_STAT) {
00683 MAKE_STAT_LIST("Number of pages", qsp->qs_pages);
00684 MAKE_STAT_LIST("Bytes free", qsp->qs_pgfree);
00685 }
00686 } else {
00687 bsp = (DB_BTREE_STAT *)sp;
00688 MAKE_STAT_LIST("Magic", bsp->bt_magic);
00689 MAKE_STAT_LIST("Version", bsp->bt_version);
00690 MAKE_STAT_LIST("Number of keys", bsp->bt_nkeys);
00691 MAKE_STAT_LIST("Number of records", bsp->bt_ndata);
00692 MAKE_STAT_LIST("Minimum keys per page", bsp->bt_minkey);
00693 MAKE_STAT_LIST("Fixed record length", bsp->bt_re_len);
00694 MAKE_STAT_LIST("Record pad", bsp->bt_re_pad);
00695 MAKE_STAT_LIST("Page size", bsp->bt_pagesize);
00696 if (flag != DB_FAST_STAT) {
00697 MAKE_STAT_LIST("Levels", bsp->bt_levels);
00698 MAKE_STAT_LIST("Internal pages", bsp->bt_int_pg);
00699 MAKE_STAT_LIST("Leaf pages", bsp->bt_leaf_pg);
00700 MAKE_STAT_LIST("Duplicate pages", bsp->bt_dup_pg);
00701 MAKE_STAT_LIST("Overflow pages", bsp->bt_over_pg);
00702 MAKE_STAT_LIST("Empty pages", bsp->bt_empty_pg);
00703 MAKE_STAT_LIST("Pages on freelist", bsp->bt_free);
00704 MAKE_STAT_LIST("Internal pages bytes free",
00705 bsp->bt_int_pgfree);
00706 MAKE_STAT_LIST("Leaf pages bytes free",
00707 bsp->bt_leaf_pgfree);
00708 MAKE_STAT_LIST("Duplicate pages bytes free",
00709 bsp->bt_dup_pgfree);
00710 MAKE_STAT_LIST("Bytes free in overflow pages",
00711 bsp->bt_over_pgfree);
00712 }
00713 }
00714
00715
00716
00717
00718
00719
00720
00721 myobjv[0] = NewStringObj("Flags", strlen("Flags"));
00722 myobjv[1] = _GetFlagsList(interp, dbp->flags, __db_get_flags_fn());
00723 flaglist = Tcl_NewListObj(2, myobjv);
00724 if (flaglist == NULL) {
00725 result = TCL_ERROR;
00726 goto error;
00727 }
00728 if ((result =
00729 Tcl_ListObjAppendElement(interp, res, flaglist)) != TCL_OK)
00730 goto error;
00731
00732 Tcl_SetObjResult(interp, res);
00733 error:
00734 if (sp != NULL)
00735 __os_ufree(dbp->dbenv, sp);
00736 return (result);
00737 }
00738
00739
00740
00741
00742 static int
00743 tcl_DbClose(interp, objc, objv, dbp, dbip)
00744 Tcl_Interp *interp;
00745 int objc;
00746 Tcl_Obj *CONST objv[];
00747 DB *dbp;
00748 DBTCL_INFO *dbip;
00749 {
00750 static const char *dbclose[] = {
00751 "-nosync", "--", NULL
00752 };
00753 enum dbclose {
00754 TCL_DBCLOSE_NOSYNC,
00755 TCL_DBCLOSE_ENDARG
00756 };
00757 u_int32_t flag;
00758 int endarg, i, optindex, result, ret;
00759 char *arg;
00760
00761 result = TCL_OK;
00762 endarg = 0;
00763 flag = 0;
00764 if (objc > 4) {
00765 Tcl_WrongNumArgs(interp, 2, objv, "?-nosync?");
00766 return (TCL_ERROR);
00767 }
00768
00769 for (i = 2; i < objc; ++i) {
00770 if (Tcl_GetIndexFromObj(interp, objv[i], dbclose,
00771 "option", TCL_EXACT, &optindex) != TCL_OK) {
00772 arg = Tcl_GetStringFromObj(objv[i], NULL);
00773 if (arg[0] == '-')
00774 return (IS_HELP(objv[i]));
00775 else
00776 Tcl_ResetResult(interp);
00777 break;
00778 }
00779 switch ((enum dbclose)optindex) {
00780 case TCL_DBCLOSE_NOSYNC:
00781 flag = DB_NOSYNC;
00782 break;
00783 case TCL_DBCLOSE_ENDARG:
00784 endarg = 1;
00785 break;
00786 }
00787
00788
00789
00790
00791 if (result != TCL_OK)
00792 return (result);
00793 if (endarg)
00794 break;
00795 }
00796 if (dbip->i_cdata != NULL)
00797 __os_free(dbp->dbenv, dbip->i_cdata);
00798 _DbInfoDelete(interp, dbip);
00799 _debug_check();
00800
00801
00802 dbp->api_internal = NULL;
00803
00804 ret = (dbp)->close(dbp, flag);
00805 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db close");
00806 return (result);
00807 }
00808
00809
00810
00811
00812 static int
00813 tcl_DbPut(interp, objc, objv, dbp)
00814 Tcl_Interp *interp;
00815 int objc;
00816 Tcl_Obj *CONST objv[];
00817 DB *dbp;
00818 {
00819 static const char *dbputopts[] = {
00820 #ifdef CONFIG_TEST
00821 "-nodupdata",
00822 #endif
00823 "-append",
00824 "-nooverwrite",
00825 "-partial",
00826 "-txn",
00827 NULL
00828 };
00829 enum dbputopts {
00830 #ifdef CONFIG_TEST
00831 DBGET_NODUPDATA,
00832 #endif
00833 DBPUT_APPEND,
00834 DBPUT_NOOVER,
00835 DBPUT_PART,
00836 DBPUT_TXN
00837 };
00838 static const char *dbputapp[] = {
00839 "-append", NULL
00840 };
00841 enum dbputapp { DBPUT_APPEND0 };
00842 DBT key, data;
00843 DBTYPE type;
00844 DB_TXN *txn;
00845 Tcl_Obj **elemv, *res;
00846 void *dtmp, *ktmp;
00847 db_recno_t recno;
00848 u_int32_t flag;
00849 int elemc, end, freekey, freedata;
00850 int i, optindex, result, ret;
00851 char *arg, msg[MSG_SIZE];
00852
00853 txn = NULL;
00854 result = TCL_OK;
00855 flag = 0;
00856 if (objc <= 3) {
00857 Tcl_WrongNumArgs(interp, 2, objv, "?-args? key data");
00858 return (TCL_ERROR);
00859 }
00860
00861 dtmp = ktmp = NULL;
00862 freekey = freedata = 0;
00863 memset(&key, 0, sizeof(key));
00864 memset(&data, 0, sizeof(data));
00865
00866
00867
00868
00869
00870
00871 (void)dbp->get_type(dbp, &type);
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 end = objc - 2;
00882 if (type == DB_QUEUE || type == DB_RECNO) {
00883 i = 2;
00884 while (i < objc - 1) {
00885 if (Tcl_GetIndexFromObj(interp, objv[i++], dbputapp,
00886 "option", TCL_EXACT, &optindex) != TCL_OK)
00887 continue;
00888 switch ((enum dbputapp)optindex) {
00889 case DBPUT_APPEND0:
00890 end = objc - 1;
00891 break;
00892 }
00893 }
00894 }
00895 Tcl_ResetResult(interp);
00896
00897
00898
00899
00900
00901 i = 2;
00902 while (i < end) {
00903 if (Tcl_GetIndexFromObj(interp, objv[i],
00904 dbputopts, "option", TCL_EXACT, &optindex) != TCL_OK)
00905 return (IS_HELP(objv[i]));
00906 i++;
00907 switch ((enum dbputopts)optindex) {
00908 #ifdef CONFIG_TEST
00909 case DBGET_NODUPDATA:
00910 FLAG_CHECK(flag);
00911 flag = DB_NODUPDATA;
00912 break;
00913 #endif
00914 case DBPUT_TXN:
00915 if (i > (end - 1)) {
00916 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
00917 result = TCL_ERROR;
00918 break;
00919 }
00920 arg = Tcl_GetStringFromObj(objv[i++], NULL);
00921 txn = NAME_TO_TXN(arg);
00922 if (txn == NULL) {
00923 snprintf(msg, MSG_SIZE,
00924 "Put: Invalid txn: %s\n", arg);
00925 Tcl_SetResult(interp, msg, TCL_VOLATILE);
00926 result = TCL_ERROR;
00927 }
00928 break;
00929 case DBPUT_APPEND:
00930 FLAG_CHECK(flag);
00931 flag = DB_APPEND;
00932 break;
00933 case DBPUT_NOOVER:
00934 FLAG_CHECK(flag);
00935 flag = DB_NOOVERWRITE;
00936 break;
00937 case DBPUT_PART:
00938 if (i > (end - 1)) {
00939 Tcl_WrongNumArgs(interp, 2, objv,
00940 "?-partial {offset length}?");
00941 result = TCL_ERROR;
00942 break;
00943 }
00944
00945
00946
00947 result = Tcl_ListObjGetElements(interp, objv[i++],
00948 &elemc, &elemv);
00949 if (elemc != 2) {
00950 Tcl_SetResult(interp,
00951 "List must be {offset length}", TCL_STATIC);
00952 result = TCL_ERROR;
00953 break;
00954 }
00955 data.flags = DB_DBT_PARTIAL;
00956 result = _GetUInt32(interp, elemv[0], &data.doff);
00957 if (result != TCL_OK)
00958 break;
00959 result = _GetUInt32(interp, elemv[1], &data.dlen);
00960
00961
00962
00963
00964
00965
00966
00967 break;
00968 }
00969 if (result != TCL_OK)
00970 break;
00971 }
00972
00973 if (result == TCL_ERROR)
00974 return (result);
00975
00976
00977
00978
00979
00980 if (type == DB_QUEUE || type == DB_RECNO) {
00981 key.data = &recno;
00982 key.ulen = key.size = sizeof(db_recno_t);
00983 key.flags = DB_DBT_USERMEM;
00984 if (flag == DB_APPEND)
00985 recno = 0;
00986 else {
00987 result = _GetUInt32(interp, objv[objc-2], &recno);
00988 if (result != TCL_OK)
00989 return (result);
00990 }
00991 } else {
00992 COMPQUIET(recno, 0);
00993
00994 ret = _CopyObjBytes(interp, objv[objc-2], &ktmp,
00995 &key.size, &freekey);
00996 if (ret != 0) {
00997 result = _ReturnSetup(interp, ret,
00998 DB_RETOK_DBPUT(ret), "db put");
00999 return (result);
01000 }
01001 key.data = ktmp;
01002 }
01003 ret = _CopyObjBytes(interp, objv[objc-1], &dtmp, &data.size, &freedata);
01004 if (ret != 0) {
01005 result = _ReturnSetup(interp, ret,
01006 DB_RETOK_DBPUT(ret), "db put");
01007 goto out;
01008 }
01009 data.data = dtmp;
01010 _debug_check();
01011 ret = dbp->put(dbp, txn, &key, &data, flag);
01012 result = _ReturnSetup(interp, ret, DB_RETOK_DBPUT(ret), "db put");
01013
01014
01015 if (ret == 0 &&
01016 (type == DB_QUEUE || type == DB_RECNO) && flag == DB_APPEND) {
01017 res = Tcl_NewWideIntObj((Tcl_WideInt)recno);
01018 Tcl_SetObjResult(interp, res);
01019 }
01020
01021 out: if (dtmp != NULL && freedata)
01022 __os_free(dbp->dbenv, dtmp);
01023 if (ktmp != NULL && freekey)
01024 __os_free(dbp->dbenv, ktmp);
01025 return (result);
01026 }
01027
01028
01029
01030
01031 static int
01032 tcl_DbGet(interp, objc, objv, dbp, ispget)
01033 Tcl_Interp *interp;
01034 int objc;
01035 Tcl_Obj *CONST objv[];
01036 DB *dbp;
01037 int ispget;
01038 {
01039 static const char *dbgetopts[] = {
01040 #ifdef CONFIG_TEST
01041 "-multi",
01042 "-read_committed",
01043 "-read_uncommitted",
01044 #endif
01045 "-consume",
01046 "-consume_wait",
01047 "-get_both",
01048 "-glob",
01049 "-partial",
01050 "-recno",
01051 "-rmw",
01052 "-txn",
01053 "--",
01054 NULL
01055 };
01056 enum dbgetopts {
01057 #ifdef CONFIG_TEST
01058 DBGET_MULTI,
01059 DBGET_READ_COMMITTED,
01060 DBGET_READ_UNCOMMITTED,
01061 #endif
01062 DBGET_CONSUME,
01063 DBGET_CONSUME_WAIT,
01064 DBGET_BOTH,
01065 DBGET_GLOB,
01066 DBGET_PART,
01067 DBGET_RECNO,
01068 DBGET_RMW,
01069 DBGET_TXN,
01070 DBGET_ENDARG
01071 };
01072 DBC *dbc;
01073 DBT key, pkey, data, save;
01074 DBTYPE ptype, type;
01075 DB_TXN *txn;
01076 Tcl_Obj **elemv, *retlist;
01077 db_recno_t precno, recno;
01078 u_int32_t flag, cflag, isdup, mflag, rmw;
01079 int elemc, end, endarg, freekey, freedata, i;
01080 int optindex, result, ret, useglob, useprecno, userecno;
01081 char *arg, *pattern, *prefix, msg[MSG_SIZE];
01082 void *dtmp, *ktmp;
01083 #ifdef CONFIG_TEST
01084 int bufsize;
01085 #endif
01086
01087 result = TCL_OK;
01088 freekey = freedata = 0;
01089 cflag = endarg = flag = mflag = rmw = 0;
01090 useglob = userecno = 0;
01091 txn = NULL;
01092 pattern = prefix = NULL;
01093 dtmp = ktmp = NULL;
01094 #ifdef CONFIG_TEST
01095 COMPQUIET(bufsize, 0);
01096 #endif
01097
01098 if (objc < 3) {
01099 Tcl_WrongNumArgs(interp, 2, objv, "?-args? key");
01100 return (TCL_ERROR);
01101 }
01102
01103 memset(&key, 0, sizeof(key));
01104 memset(&data, 0, sizeof(data));
01105 memset(&save, 0, sizeof(save));
01106
01107
01108 memset(&pkey, 0, sizeof(pkey));
01109
01110
01111
01112
01113
01114 i = 2;
01115 (void)dbp->get_type(dbp, &type);
01116 end = objc;
01117 while (i < end) {
01118 if (Tcl_GetIndexFromObj(interp, objv[i], dbgetopts, "option",
01119 TCL_EXACT, &optindex) != TCL_OK) {
01120 arg = Tcl_GetStringFromObj(objv[i], NULL);
01121 if (arg[0] == '-') {
01122 result = IS_HELP(objv[i]);
01123 goto out;
01124 } else
01125 Tcl_ResetResult(interp);
01126 break;
01127 }
01128 i++;
01129 switch ((enum dbgetopts)optindex) {
01130 #ifdef CONFIG_TEST
01131 case DBGET_MULTI:
01132 mflag |= DB_MULTIPLE;
01133 result = Tcl_GetIntFromObj(interp, objv[i], &bufsize);
01134 if (result != TCL_OK)
01135 goto out;
01136 i++;
01137 break;
01138 case DBGET_READ_COMMITTED:
01139 rmw |= DB_READ_COMMITTED;
01140 break;
01141 case DBGET_READ_UNCOMMITTED:
01142 rmw |= DB_READ_UNCOMMITTED;
01143 break;
01144 #endif
01145 case DBGET_BOTH:
01146
01147
01148
01149
01150 if (i > objc - 2) {
01151 Tcl_WrongNumArgs(interp, 2, objv,
01152 "?-get_both key data?");
01153 result = TCL_ERROR;
01154 break;
01155 }
01156 end = objc - 2;
01157 FLAG_CHECK(flag);
01158 flag = DB_GET_BOTH;
01159 break;
01160 case DBGET_TXN:
01161 if (i >= end) {
01162 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
01163 result = TCL_ERROR;
01164 break;
01165 }
01166 arg = Tcl_GetStringFromObj(objv[i++], NULL);
01167 txn = NAME_TO_TXN(arg);
01168 if (txn == NULL) {
01169 snprintf(msg, MSG_SIZE,
01170 "Get: Invalid txn: %s\n", arg);
01171 Tcl_SetResult(interp, msg, TCL_VOLATILE);
01172 result = TCL_ERROR;
01173 }
01174 break;
01175 case DBGET_GLOB:
01176 useglob = 1;
01177 end = objc - 1;
01178 break;
01179 case DBGET_CONSUME:
01180 FLAG_CHECK(flag);
01181 flag = DB_CONSUME;
01182 break;
01183 case DBGET_CONSUME_WAIT:
01184 FLAG_CHECK(flag);
01185 flag = DB_CONSUME_WAIT;
01186 break;
01187 case DBGET_RECNO:
01188 end = objc - 1;
01189 userecno = 1;
01190 if (type != DB_RECNO && type != DB_QUEUE) {
01191 FLAG_CHECK(flag);
01192 flag = DB_SET_RECNO;
01193 key.flags |= DB_DBT_MALLOC;
01194 }
01195 break;
01196 case DBGET_RMW:
01197 rmw |= DB_RMW;
01198 break;
01199 case DBGET_PART:
01200 end = objc - 1;
01201 if (i == end) {
01202 Tcl_WrongNumArgs(interp, 2, objv,
01203 "?-partial {offset length}?");
01204 result = TCL_ERROR;
01205 break;
01206 }
01207
01208
01209
01210 result = Tcl_ListObjGetElements(interp, objv[i++],
01211 &elemc, &elemv);
01212 if (elemc != 2) {
01213 Tcl_SetResult(interp,
01214 "List must be {offset length}", TCL_STATIC);
01215 result = TCL_ERROR;
01216 break;
01217 }
01218 save.flags = DB_DBT_PARTIAL;
01219 result = _GetUInt32(interp, elemv[0], &save.doff);
01220 if (result != TCL_OK)
01221 break;
01222 result = _GetUInt32(interp, elemv[1], &save.dlen);
01223
01224
01225
01226
01227
01228
01229
01230 break;
01231 case DBGET_ENDARG:
01232 endarg = 1;
01233 break;
01234 }
01235 if (result != TCL_OK)
01236 break;
01237 if (endarg)
01238 break;
01239 }
01240 if (result != TCL_OK)
01241 goto out;
01242
01243 if (type == DB_RECNO || type == DB_QUEUE)
01244 userecno = 1;
01245
01246
01247
01248
01249
01250
01251
01252 if (((flag == DB_CONSUME || flag == DB_CONSUME_WAIT) && i != objc) ||
01253 (flag == DB_GET_BOTH && i != objc - 2)) {
01254 Tcl_SetResult(interp,
01255 "Wrong number of key/data given based on flags specified\n",
01256 TCL_STATIC);
01257 result = TCL_ERROR;
01258 goto out;
01259 } else if (flag == 0 && i != objc - 1) {
01260 Tcl_SetResult(interp,
01261 "Wrong number of key/data given\n", TCL_STATIC);
01262 result = TCL_ERROR;
01263 goto out;
01264 }
01265
01266
01267
01268
01269 if (ispget && dbp->s_primary != NULL) {
01270 (void)dbp->s_primary->get_type(dbp->s_primary, &ptype);
01271 useprecno = ptype == DB_RECNO || ptype == DB_QUEUE;
01272 } else
01273 useprecno = 0;
01274
01275
01276
01277
01278 if (useglob && (userecno || flag == DB_SET_RECNO ||
01279 type == DB_RECNO || type == DB_QUEUE)) {
01280 Tcl_SetResult(interp,
01281 "Cannot use -glob and record numbers.\n",
01282 TCL_STATIC);
01283 result = TCL_ERROR;
01284 goto out;
01285 }
01286 if (useglob && flag == DB_GET_BOTH) {
01287 Tcl_SetResult(interp,
01288 "Only one of -glob or -get_both can be specified.\n",
01289 TCL_STATIC);
01290 result = TCL_ERROR;
01291 goto out;
01292 }
01293
01294 if (useglob)
01295 pattern = Tcl_GetStringFromObj(objv[objc - 1], NULL);
01296
01297
01298
01299
01300 retlist = Tcl_NewListObj(0, NULL);
01301 save.flags |= DB_DBT_MALLOC;
01302
01303
01304
01305
01306
01307 if ((ret = dbp->get_flags(dbp, &isdup)) != 0) {
01308 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db get");
01309 goto out;
01310 }
01311 isdup &= DB_DUP;
01312
01313
01314
01315
01316
01317
01318 if (pattern == NULL && (isdup == 0 || mflag != 0 ||
01319 flag == DB_SET_RECNO || flag == DB_GET_BOTH ||
01320 flag == DB_CONSUME || flag == DB_CONSUME_WAIT)) {
01321 if (flag == DB_GET_BOTH) {
01322 if (userecno) {
01323 result = _GetUInt32(interp,
01324 objv[(objc - 2)], &recno);
01325 if (result == TCL_OK) {
01326 key.data = &recno;
01327 key.size = sizeof(db_recno_t);
01328 } else
01329 goto out;
01330 } else {
01331
01332
01333
01334
01335
01336 ret = _CopyObjBytes(interp, objv[objc-2],
01337 &ktmp, &key.size, &freekey);
01338 if (ret != 0) {
01339 result = _ReturnSetup(interp, ret,
01340 DB_RETOK_DBGET(ret), "db get");
01341 goto out;
01342 }
01343 key.data = ktmp;
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354 if (useprecno) {
01355 result = _GetUInt32(interp,
01356 objv[objc - 1], &precno);
01357 if (result == TCL_OK) {
01358 save.data = &precno;
01359 save.size = sizeof(db_recno_t);
01360 } else
01361 goto out;
01362 } else {
01363 ret = _CopyObjBytes(interp, objv[objc-1],
01364 &dtmp, &save.size, &freedata);
01365 if (ret != 0) {
01366 result = _ReturnSetup(interp, ret,
01367 DB_RETOK_DBGET(ret), "db get");
01368 goto out;
01369 }
01370 save.data = dtmp;
01371 }
01372 } else if (flag != DB_CONSUME && flag != DB_CONSUME_WAIT) {
01373 if (userecno) {
01374 result = _GetUInt32(
01375 interp, objv[(objc - 1)], &recno);
01376 if (result == TCL_OK) {
01377 key.data = &recno;
01378 key.size = sizeof(db_recno_t);
01379 } else
01380 goto out;
01381 } else {
01382
01383
01384
01385
01386
01387 ret = _CopyObjBytes(interp, objv[objc-1],
01388 &ktmp, &key.size, &freekey);
01389 if (ret != 0) {
01390 result = _ReturnSetup(interp, ret,
01391 DB_RETOK_DBGET(ret), "db get");
01392 goto out;
01393 }
01394 key.data = ktmp;
01395 }
01396 #ifdef CONFIG_TEST
01397 if (mflag & DB_MULTIPLE) {
01398 if ((ret = __os_malloc(dbp->dbenv,
01399 (size_t)bufsize, &save.data)) != 0) {
01400 Tcl_SetResult(interp,
01401 db_strerror(ret), TCL_STATIC);
01402 goto out;
01403 }
01404 save.ulen = (u_int32_t)bufsize;
01405 F_CLR(&save, DB_DBT_MALLOC);
01406 F_SET(&save, DB_DBT_USERMEM);
01407 }
01408 #endif
01409 }
01410
01411 data = save;
01412
01413 if (ispget) {
01414 if (flag == DB_GET_BOTH) {
01415 pkey.data = save.data;
01416 pkey.size = save.size;
01417 data.data = NULL;
01418 data.size = 0;
01419 }
01420 F_SET(&pkey, DB_DBT_MALLOC);
01421 _debug_check();
01422 ret = dbp->pget(dbp,
01423 txn, &key, &pkey, &data, flag | rmw);
01424 } else {
01425 _debug_check();
01426 ret = dbp->get(dbp,
01427 txn, &key, &data, flag | rmw | mflag);
01428 }
01429 result = _ReturnSetup(interp, ret, DB_RETOK_DBGET(ret),
01430 "db get");
01431 if (ret == 0) {
01432
01433
01434
01435
01436
01437 if (mflag & DB_MULTIPLE)
01438 result = _SetMultiList(interp,
01439 retlist, &key, &data, type, flag);
01440 else if (type == DB_RECNO || type == DB_QUEUE)
01441 if (ispget)
01442 result = _Set3DBTList(interp,
01443 retlist, &key, 1, &pkey,
01444 useprecno, &data);
01445 else
01446 result = _SetListRecnoElem(interp,
01447 retlist, *(db_recno_t *)key.data,
01448 data.data, data.size);
01449 else {
01450 if (ispget)
01451 result = _Set3DBTList(interp,
01452 retlist, &key, 0, &pkey,
01453 useprecno, &data);
01454 else
01455 result = _SetListElem(interp, retlist,
01456 key.data, key.size,
01457 data.data, data.size);
01458 }
01459 }
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469 if (F_ISSET(&key, DB_DBT_MALLOC) && ret == 0 &&
01470 key.data != ktmp)
01471 __os_ufree(dbp->dbenv, key.data);
01472 if (F_ISSET(&data, DB_DBT_MALLOC) && ret == 0 &&
01473 data.data != dtmp)
01474 __os_ufree(dbp->dbenv, data.data);
01475 else if (!F_ISSET(&data, DB_DBT_MALLOC))
01476 __os_free(dbp->dbenv, data.data);
01477 if (ispget && ret == 0 && pkey.data != save.data)
01478 __os_ufree(dbp->dbenv, pkey.data);
01479 if (result == TCL_OK)
01480 Tcl_SetObjResult(interp, retlist);
01481 goto out;
01482 }
01483
01484 if (userecno) {
01485 result = _GetUInt32(interp, objv[(objc - 1)], &recno);
01486 if (result == TCL_OK) {
01487 key.data = &recno;
01488 key.size = sizeof(db_recno_t);
01489 } else
01490 goto out;
01491 } else {
01492
01493
01494
01495
01496
01497 ret = _CopyObjBytes(interp, objv[objc-1], &ktmp,
01498 &key.size, &freekey);
01499 if (ret != 0) {
01500 result = _ReturnSetup(interp, ret,
01501 DB_RETOK_DBGET(ret), "db get");
01502 return (result);
01503 }
01504 key.data = ktmp;
01505 }
01506 ret = dbp->cursor(dbp, txn, &dbc, 0);
01507 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db cursor");
01508 if (result == TCL_ERROR)
01509 goto out;
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519 memset(&data, 0, sizeof(data));
01520
01521
01522
01523 data = save;
01524 if (pattern) {
01525
01526
01527
01528 ret = _GetGlobPrefix(pattern, &prefix);
01529 if (ret) {
01530 result = TCL_ERROR;
01531 Tcl_SetResult(interp,
01532 "Unable to allocate pattern space", TCL_STATIC);
01533 goto out1;
01534 }
01535 key.data = prefix;
01536 key.size = strlen(prefix);
01537
01538
01539
01540
01541 if (strlen(prefix) == 0)
01542 cflag = DB_FIRST;
01543 else
01544 cflag = DB_SET_RANGE;
01545 } else
01546 cflag = DB_SET;
01547 if (ispget) {
01548 _debug_check();
01549 F_SET(&pkey, DB_DBT_MALLOC);
01550 ret = dbc->c_pget(dbc, &key, &pkey, &data, cflag | rmw);
01551 } else {
01552 _debug_check();
01553 ret = dbc->c_get(dbc, &key, &data, cflag | rmw);
01554 }
01555 result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret),
01556 "db get (cursor)");
01557 if (result == TCL_ERROR)
01558 goto out1;
01559 if (pattern) {
01560 if (ret == 0 && prefix != NULL &&
01561 memcmp(key.data, prefix, strlen(prefix)) != 0) {
01562
01563
01564
01565 __os_ufree(dbp->dbenv, data.data);
01566 goto out1;
01567 }
01568 cflag = DB_NEXT;
01569 } else
01570 cflag = DB_NEXT_DUP;
01571
01572 while (ret == 0 && result == TCL_OK) {
01573
01574
01575
01576 if (ispget)
01577 result = _Set3DBTList(interp, retlist, &key, 0,
01578 &pkey, useprecno, &data);
01579 else
01580 result = _SetListElem(interp, retlist,
01581 key.data, key.size, data.data, data.size);
01582
01583
01584
01585 if (ispget)
01586 __os_ufree(dbp->dbenv, pkey.data);
01587 __os_ufree(dbp->dbenv, data.data);
01588 if (result != TCL_OK)
01589 break;
01590
01591
01592
01593 memset(&key, 0, sizeof(key));
01594 memset(&pkey, 0, sizeof(pkey));
01595 memset(&data, 0, sizeof(data));
01596
01597
01598
01599 data = save;
01600 if (ispget) {
01601 F_SET(&pkey, DB_DBT_MALLOC);
01602 ret = dbc->c_pget(dbc, &key, &pkey, &data, cflag | rmw);
01603 } else
01604 ret = dbc->c_get(dbc, &key, &data, cflag | rmw);
01605 if (ret == 0 && prefix != NULL &&
01606 memcmp(key.data, prefix, strlen(prefix)) != 0) {
01607
01608
01609
01610 __os_ufree(dbp->dbenv, data.data);
01611 break;
01612 }
01613 }
01614 out1:
01615 (void)dbc->c_close(dbc);
01616 if (result == TCL_OK)
01617 Tcl_SetObjResult(interp, retlist);
01618 out:
01619
01620
01621
01622
01623
01624 if (prefix != NULL)
01625 __os_free(dbp->dbenv, prefix);
01626 if (dtmp != NULL && freedata)
01627 __os_free(dbp->dbenv, dtmp);
01628 if (ktmp != NULL && freekey)
01629 __os_free(dbp->dbenv, ktmp);
01630 return (result);
01631 }
01632
01633
01634
01635
01636 static int
01637 tcl_DbDelete(interp, objc, objv, dbp)
01638 Tcl_Interp *interp;
01639 int objc;
01640 Tcl_Obj *CONST objv[];
01641 DB *dbp;
01642 {
01643 static const char *dbdelopts[] = {
01644 "-glob",
01645 "-txn",
01646 NULL
01647 };
01648 enum dbdelopts {
01649 DBDEL_GLOB,
01650 DBDEL_TXN
01651 };
01652 DBC *dbc;
01653 DBT key, data;
01654 DBTYPE type;
01655 DB_TXN *txn;
01656 void *ktmp;
01657 db_recno_t recno;
01658 int freekey, i, optindex, result, ret;
01659 u_int32_t flag;
01660 char *arg, *pattern, *prefix, msg[MSG_SIZE];
01661
01662 result = TCL_OK;
01663 freekey = 0;
01664 pattern = prefix = NULL;
01665 txn = NULL;
01666 if (objc < 3) {
01667 Tcl_WrongNumArgs(interp, 2, objv, "?-args? key");
01668 return (TCL_ERROR);
01669 }
01670
01671 ktmp = NULL;
01672 memset(&key, 0, sizeof(key));
01673
01674
01675
01676 i = 2;
01677 while (i < objc) {
01678 if (Tcl_GetIndexFromObj(interp, objv[i], dbdelopts, "option",
01679 TCL_EXACT, &optindex) != TCL_OK) {
01680
01681
01682
01683
01684
01685
01686 if (IS_HELP(objv[i]) == TCL_OK)
01687 return (TCL_OK);
01688 Tcl_ResetResult(interp);
01689 break;
01690 }
01691 i++;
01692 switch ((enum dbdelopts)optindex) {
01693 case DBDEL_TXN:
01694 if (i == objc) {
01695
01696
01697
01698
01699 i--;
01700 break;
01701 }
01702 arg = Tcl_GetStringFromObj(objv[i++], NULL);
01703 txn = NAME_TO_TXN(arg);
01704 if (txn == NULL) {
01705 snprintf(msg, MSG_SIZE,
01706 "Delete: Invalid txn: %s\n", arg);
01707 Tcl_SetResult(interp, msg, TCL_VOLATILE);
01708 result = TCL_ERROR;
01709 }
01710 break;
01711 case DBDEL_GLOB:
01712
01713
01714
01715
01716 if (i == objc) {
01717
01718
01719
01720
01721 i--;
01722 break;
01723 }
01724 pattern = Tcl_GetStringFromObj(objv[i++], NULL);
01725 break;
01726 }
01727 if (result != TCL_OK)
01728 break;
01729 }
01730
01731 if (result != TCL_OK)
01732 goto out;
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746 if (pattern == NULL) {
01747 if (i != (objc - 1)) {
01748 Tcl_WrongNumArgs(
01749 interp, 2, objv, "?args? -glob pattern | key");
01750 result = TCL_ERROR;
01751 goto out;
01752 }
01753 } else {
01754 if (i != objc) {
01755 Tcl_WrongNumArgs(
01756 interp, 2, objv, "?args? -glob pattern | key");
01757 result = TCL_ERROR;
01758 goto out;
01759 }
01760 }
01761
01762
01763
01764
01765
01766
01767
01768
01769 (void)dbp->get_type(dbp, &type);
01770 ret = 0;
01771 while (i < objc && ret == 0) {
01772 memset(&key, 0, sizeof(key));
01773 if (type == DB_RECNO || type == DB_QUEUE) {
01774 result = _GetUInt32(interp, objv[i++], &recno);
01775 if (result == TCL_OK) {
01776 key.data = &recno;
01777 key.size = sizeof(db_recno_t);
01778 } else
01779 return (result);
01780 } else {
01781 ret = _CopyObjBytes(interp, objv[i++], &ktmp,
01782 &key.size, &freekey);
01783 if (ret != 0) {
01784 result = _ReturnSetup(interp, ret,
01785 DB_RETOK_DBDEL(ret), "db del");
01786 return (result);
01787 }
01788 key.data = ktmp;
01789 }
01790 _debug_check();
01791 ret = dbp->del(dbp, txn, &key, 0);
01792
01793
01794
01795
01796 if (ktmp != NULL && freekey)
01797 __os_free(dbp->dbenv, ktmp);
01798 if (ret != 0)
01799 break;
01800 }
01801 result = _ReturnSetup(interp, ret, DB_RETOK_DBDEL(ret), "db del");
01802
01803
01804
01805
01806
01807
01808 if (pattern) {
01809 ret = dbp->cursor(dbp, txn, &dbc, 0);
01810 if (ret != 0) {
01811 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
01812 "db cursor");
01813 goto out;
01814 }
01815
01816
01817
01818 memset(&key, 0, sizeof(key));
01819 memset(&data, 0, sizeof(data));
01820 ret = _GetGlobPrefix(pattern, &prefix);
01821 if (ret) {
01822 result = TCL_ERROR;
01823 Tcl_SetResult(interp,
01824 "Unable to allocate pattern space", TCL_STATIC);
01825 goto out;
01826 }
01827 key.data = prefix;
01828 key.size = strlen(prefix);
01829 if (strlen(prefix) == 0)
01830 flag = DB_FIRST;
01831 else
01832 flag = DB_SET_RANGE;
01833 ret = dbc->c_get(dbc, &key, &data, flag);
01834 while (ret == 0 &&
01835 memcmp(key.data, prefix, strlen(prefix)) == 0) {
01836
01837
01838
01839
01840
01841 _debug_check();
01842 ret = dbc->c_del(dbc, 0);
01843 if (ret != 0) {
01844 result = _ReturnSetup(interp, ret,
01845 DB_RETOK_DBCDEL(ret), "db c_del");
01846 break;
01847 }
01848
01849
01850
01851
01852 memset(&key, 0, sizeof(key));
01853 memset(&data, 0, sizeof(data));
01854 ret = dbc->c_get(dbc, &key, &data, DB_NEXT);
01855 }
01856 if (ret == DB_NOTFOUND)
01857 ret = 0;
01858
01859
01860
01861
01862
01863 __os_free(dbp->dbenv, prefix);
01864 (void)dbc->c_close(dbc);
01865 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db del");
01866 }
01867 out:
01868 return (result);
01869 }
01870
01871
01872
01873
01874 static int
01875 tcl_DbCursor(interp, objc, objv, dbp, dbcp)
01876 Tcl_Interp *interp;
01877 int objc;
01878 Tcl_Obj *CONST objv[];
01879 DB *dbp;
01880 DBC **dbcp;
01881 {
01882 static const char *dbcuropts[] = {
01883 #ifdef CONFIG_TEST
01884 "-read_committed",
01885 "-read_uncommitted",
01886 "-update",
01887 #endif
01888 "-txn",
01889 NULL
01890 };
01891 enum dbcuropts {
01892 #ifdef CONFIG_TEST
01893 DBCUR_READ_COMMITTED,
01894 DBCUR_READ_UNCOMMITTED,
01895 DBCUR_UPDATE,
01896 #endif
01897 DBCUR_TXN
01898 };
01899 DB_TXN *txn;
01900 u_int32_t flag;
01901 int i, optindex, result, ret;
01902 char *arg, msg[MSG_SIZE];
01903
01904 result = TCL_OK;
01905 flag = 0;
01906 txn = NULL;
01907 i = 2;
01908 while (i < objc) {
01909 if (Tcl_GetIndexFromObj(interp, objv[i], dbcuropts, "option",
01910 TCL_EXACT, &optindex) != TCL_OK) {
01911 result = IS_HELP(objv[i]);
01912 goto out;
01913 }
01914 i++;
01915 switch ((enum dbcuropts)optindex) {
01916 #ifdef CONFIG_TEST
01917 case DBCUR_READ_COMMITTED:
01918 flag |= DB_READ_COMMITTED;
01919 break;
01920 case DBCUR_READ_UNCOMMITTED:
01921 flag |= DB_READ_UNCOMMITTED;
01922 break;
01923 case DBCUR_UPDATE:
01924 flag |= DB_WRITECURSOR;
01925 break;
01926 #endif
01927 case DBCUR_TXN:
01928 if (i == objc) {
01929 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
01930 result = TCL_ERROR;
01931 break;
01932 }
01933 arg = Tcl_GetStringFromObj(objv[i++], NULL);
01934 txn = NAME_TO_TXN(arg);
01935 if (txn == NULL) {
01936 snprintf(msg, MSG_SIZE,
01937 "Cursor: Invalid txn: %s\n", arg);
01938 Tcl_SetResult(interp, msg, TCL_VOLATILE);
01939 result = TCL_ERROR;
01940 }
01941 break;
01942 }
01943 if (result != TCL_OK)
01944 break;
01945 }
01946 if (result != TCL_OK)
01947 goto out;
01948
01949 _debug_check();
01950 ret = dbp->cursor(dbp, txn, dbcp, flag);
01951 if (ret != 0)
01952 result = _ErrorSetup(interp, ret, "db cursor");
01953 out:
01954 return (result);
01955 }
01956
01957
01958
01959
01960
01961 static int
01962 tcl_DbAssociate(interp, objc, objv, dbp)
01963 Tcl_Interp *interp;
01964 int objc;
01965 Tcl_Obj *CONST objv[];
01966 DB *dbp;
01967 {
01968 static const char *dbaopts[] = {
01969 "-create",
01970 "-immutable_key",
01971 "-txn",
01972 NULL
01973 };
01974 enum dbaopts {
01975 DBA_CREATE,
01976 DBA_IMMUTABLE_KEY,
01977 DBA_TXN
01978 };
01979 DB *sdbp;
01980 DB_TXN *txn;
01981 DBTCL_INFO *sdbip;
01982 int i, optindex, result, ret;
01983 char *arg, msg[MSG_SIZE];
01984 u_int32_t flag;
01985 #ifdef CONFIG_TEST
01986
01987
01988
01989
01990
01991 const char *cbname;
01992 struct {
01993 const char *name;
01994 u_int32_t flag;
01995 } *cb, callbacks[] = {
01996 { "", 0 },
01997 { "_s_reversedata", DB_RPC2ND_REVERSEDATA },
01998 { "_s_noop", DB_RPC2ND_NOOP },
01999 { "_s_concatkeydata", DB_RPC2ND_CONCATKEYDATA },
02000 { "_s_concatdatakey", DB_RPC2ND_CONCATDATAKEY },
02001 { "_s_reverseconcat", DB_RPC2ND_REVERSECONCAT },
02002 { "_s_truncdata", DB_RPC2ND_TRUNCDATA },
02003 { "_s_reversedata", DB_RPC2ND_REVERSEDATA },
02004 { "_s_constant", DB_RPC2ND_CONSTANT },
02005 { "sj_getzip", DB_RPC2ND_GETZIP },
02006 { "sj_getname", DB_RPC2ND_GETNAME },
02007 { NULL, 0 }
02008 };
02009 #endif
02010
02011 txn = NULL;
02012 result = TCL_OK;
02013 flag = 0;
02014 if (objc < 2) {
02015 Tcl_WrongNumArgs(interp, 2, objv, "[callback] secondary");
02016 return (TCL_ERROR);
02017 }
02018
02019 i = 2;
02020 while (i < objc) {
02021 if (Tcl_GetIndexFromObj(interp, objv[i], dbaopts, "option",
02022 TCL_EXACT, &optindex) != TCL_OK) {
02023 result = IS_HELP(objv[i]);
02024 if (result == TCL_OK)
02025 return (result);
02026 result = TCL_OK;
02027 Tcl_ResetResult(interp);
02028 break;
02029 }
02030 i++;
02031 switch ((enum dbaopts)optindex) {
02032 case DBA_CREATE:
02033 flag |= DB_CREATE;
02034 break;
02035 case DBA_IMMUTABLE_KEY:
02036 flag |= DB_IMMUTABLE_KEY;
02037 break;
02038 case DBA_TXN:
02039 if (i > (objc - 1)) {
02040 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
02041 result = TCL_ERROR;
02042 break;
02043 }
02044 arg = Tcl_GetStringFromObj(objv[i++], NULL);
02045 txn = NAME_TO_TXN(arg);
02046 if (txn == NULL) {
02047 snprintf(msg, MSG_SIZE,
02048 "Associate: Invalid txn: %s\n", arg);
02049 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02050 result = TCL_ERROR;
02051 }
02052 break;
02053 }
02054 }
02055 if (result != TCL_OK)
02056 return (result);
02057
02058
02059
02060
02061
02062
02063
02064 arg = Tcl_GetStringFromObj(objv[objc - 1], NULL);
02065 sdbp = NAME_TO_DB(arg);
02066 if (sdbp == NULL) {
02067 snprintf(msg, MSG_SIZE,
02068 "Associate: Invalid database handle: %s\n", arg);
02069 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02070 return (TCL_ERROR);
02071 }
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081 sdbip = (DBTCL_INFO *)sdbp->api_internal;
02082
02083 #ifdef CONFIG_TEST
02084 if (i != objc - 1 && RPC_ON(dbp->dbenv)) {
02085
02086
02087
02088
02089
02090 if ((flag & DB_RPC2ND_MASK) != 0) {
02091 snprintf(msg, MSG_SIZE,
02092 "RPC secondary flags overlap -- recalculate!\n");
02093 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02094 return (TCL_ERROR);
02095 }
02096
02097 cbname = Tcl_GetStringFromObj(objv[objc - 2], NULL);
02098 for (cb = callbacks; cb->name != NULL; cb++)
02099 if (strcmp(cb->name, cbname) == 0) {
02100 flag |= cb->flag;
02101 break;
02102 }
02103
02104 if (cb->name == NULL) {
02105 snprintf(msg, MSG_SIZE,
02106 "Associate: unknown callback: %s\n", cbname);
02107 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02108 return (TCL_ERROR);
02109 }
02110
02111 ret = dbp->associate(dbp, txn, sdbp, NULL, flag);
02112
02113
02114
02115
02116
02117
02118 if (ret == 0)
02119 sdbp->s_primary = dbp;
02120 } else if (i != objc - 1) {
02121 #else
02122 if (i != objc - 1) {
02123 #endif
02124
02125
02126
02127 sdbip->i_second_call = objv[objc - 2];
02128 Tcl_IncrRefCount(sdbip->i_second_call);
02129
02130
02131 _debug_check();
02132 ret = dbp->associate(dbp, txn, sdbp, tcl_second_call, flag);
02133 } else {
02134
02135
02136
02137 sdbip->i_second_call = NULL;
02138 ret = dbp->associate(dbp, txn, sdbp, NULL, flag);
02139 }
02140 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "associate");
02141
02142 return (result);
02143 }
02144
02145
02146
02147
02148
02149
02150 static int
02151 tcl_second_call(dbp, pkey, data, skey)
02152 DB *dbp;
02153 const DBT *pkey, *data;
02154 DBT *skey;
02155 {
02156 DBTCL_INFO *ip;
02157 Tcl_Interp *interp;
02158 Tcl_Obj *pobj, *dobj, *objv[3];
02159 size_t len;
02160 int ilen, result, ret;
02161 void *retbuf, *databuf;
02162
02163 ip = (DBTCL_INFO *)dbp->api_internal;
02164 interp = ip->i_interp;
02165 objv[0] = ip->i_second_call;
02166
02167
02168
02169
02170
02171 pobj = Tcl_NewByteArrayObj(pkey->data, (int)pkey->size);
02172 Tcl_IncrRefCount(pobj);
02173 dobj = Tcl_NewByteArrayObj(data->data, (int)data->size);
02174 Tcl_IncrRefCount(dobj);
02175
02176 objv[1] = pobj;
02177 objv[2] = dobj;
02178
02179 result = Tcl_EvalObjv(interp, 3, objv, 0);
02180
02181 Tcl_DecrRefCount(pobj);
02182 Tcl_DecrRefCount(dobj);
02183
02184 if (result != TCL_OK) {
02185 __db_err(dbp->dbenv,
02186 "Tcl callback function failed with code %d", result);
02187 return (EINVAL);
02188 }
02189
02190 retbuf = Tcl_GetByteArrayFromObj(Tcl_GetObjResult(interp), &ilen);
02191 len = (size_t)ilen;
02192
02193
02194
02195
02196
02197
02198
02199 if ((ret = __os_umalloc(dbp->dbenv, len, &databuf)) != 0)
02200 return (ret);
02201 memcpy(databuf, retbuf, len);
02202
02203 skey->data = databuf;
02204 skey->size = len;
02205 F_SET(skey, DB_DBT_APPMALLOC);
02206
02207 return (0);
02208 }
02209
02210
02211
02212
02213 static int
02214 tcl_DbJoin(interp, objc, objv, dbp, dbcp)
02215 Tcl_Interp *interp;
02216 int objc;
02217 Tcl_Obj *CONST objv[];
02218 DB *dbp;
02219 DBC **dbcp;
02220 {
02221 static const char *dbjopts[] = {
02222 "-nosort",
02223 NULL
02224 };
02225 enum dbjopts {
02226 DBJ_NOSORT
02227 };
02228 DBC **listp;
02229 size_t size;
02230 u_int32_t flag;
02231 int adj, i, j, optindex, result, ret;
02232 char *arg, msg[MSG_SIZE];
02233
02234 result = TCL_OK;
02235 flag = 0;
02236 if (objc < 3) {
02237 Tcl_WrongNumArgs(interp, 2, objv, "curs1 curs2 ...");
02238 return (TCL_ERROR);
02239 }
02240
02241 for (adj = i = 2; i < objc; i++) {
02242 if (Tcl_GetIndexFromObj(interp, objv[i], dbjopts, "option",
02243 TCL_EXACT, &optindex) != TCL_OK) {
02244 result = IS_HELP(objv[i]);
02245 if (result == TCL_OK)
02246 return (result);
02247 result = TCL_OK;
02248 Tcl_ResetResult(interp);
02249 break;
02250 }
02251 switch ((enum dbjopts)optindex) {
02252 case DBJ_NOSORT:
02253 flag |= DB_JOIN_NOSORT;
02254 adj++;
02255 break;
02256 }
02257 }
02258 if (result != TCL_OK)
02259 return (result);
02260
02261
02262
02263 size = sizeof(DBC *) * (size_t)((objc - adj) + 1);
02264 ret = __os_malloc(dbp->dbenv, size, &listp);
02265 if (ret != 0) {
02266 Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
02267 return (TCL_ERROR);
02268 }
02269
02270 memset(listp, 0, size);
02271 for (j = 0, i = adj; i < objc; i++, j++) {
02272 arg = Tcl_GetStringFromObj(objv[i], NULL);
02273 listp[j] = NAME_TO_DBC(arg);
02274 if (listp[j] == NULL) {
02275 snprintf(msg, MSG_SIZE,
02276 "Join: Invalid cursor: %s\n", arg);
02277 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02278 result = TCL_ERROR;
02279 goto out;
02280 }
02281 }
02282 listp[j] = NULL;
02283 _debug_check();
02284 ret = dbp->join(dbp, listp, dbcp, flag);
02285 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db join");
02286
02287 out:
02288 __os_free(dbp->dbenv, listp);
02289 return (result);
02290 }
02291
02292
02293
02294
02295 static int
02296 tcl_DbGetjoin(interp, objc, objv, dbp)
02297 Tcl_Interp *interp;
02298 int objc;
02299 Tcl_Obj *CONST objv[];
02300 DB *dbp;
02301 {
02302 static const char *dbgetjopts[] = {
02303 #ifdef CONFIG_TEST
02304 "-nosort",
02305 #endif
02306 "-txn",
02307 NULL
02308 };
02309 enum dbgetjopts {
02310 #ifdef CONFIG_TEST
02311 DBGETJ_NOSORT,
02312 #endif
02313 DBGETJ_TXN
02314 };
02315 DB_TXN *txn;
02316 DB *elemdbp;
02317 DBC **listp;
02318 DBC *dbc;
02319 DBT key, data;
02320 Tcl_Obj **elemv, *retlist;
02321 void *ktmp;
02322 size_t size;
02323 u_int32_t flag;
02324 int adj, elemc, freekey, i, j, optindex, result, ret;
02325 char *arg, msg[MSG_SIZE];
02326
02327 result = TCL_OK;
02328 flag = 0;
02329 ktmp = NULL;
02330 freekey = 0;
02331 if (objc < 3) {
02332 Tcl_WrongNumArgs(interp, 2, objv, "{db1 key1} {db2 key2} ...");
02333 return (TCL_ERROR);
02334 }
02335
02336 txn = NULL;
02337 i = 2;
02338 adj = i;
02339 while (i < objc) {
02340 if (Tcl_GetIndexFromObj(interp, objv[i], dbgetjopts, "option",
02341 TCL_EXACT, &optindex) != TCL_OK) {
02342 result = IS_HELP(objv[i]);
02343 if (result == TCL_OK)
02344 return (result);
02345 result = TCL_OK;
02346 Tcl_ResetResult(interp);
02347 break;
02348 }
02349 i++;
02350 switch ((enum dbgetjopts)optindex) {
02351 #ifdef CONFIG_TEST
02352 case DBGETJ_NOSORT:
02353 flag |= DB_JOIN_NOSORT;
02354 adj++;
02355 break;
02356 #endif
02357 case DBGETJ_TXN:
02358 if (i == objc) {
02359 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
02360 result = TCL_ERROR;
02361 break;
02362 }
02363 arg = Tcl_GetStringFromObj(objv[i++], NULL);
02364 txn = NAME_TO_TXN(arg);
02365 adj += 2;
02366 if (txn == NULL) {
02367 snprintf(msg, MSG_SIZE,
02368 "GetJoin: Invalid txn: %s\n", arg);
02369 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02370 result = TCL_ERROR;
02371 }
02372 break;
02373 }
02374 }
02375 if (result != TCL_OK)
02376 return (result);
02377 size = sizeof(DBC *) * (size_t)((objc - adj) + 1);
02378 ret = __os_malloc(NULL, size, &listp);
02379 if (ret != 0) {
02380 Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
02381 return (TCL_ERROR);
02382 }
02383
02384 memset(listp, 0, size);
02385 for (j = 0, i = adj; i < objc; i++, j++) {
02386
02387
02388
02389 result = Tcl_ListObjGetElements(interp, objv[i],
02390 &elemc, &elemv);
02391 if (elemc != 2) {
02392 Tcl_SetResult(interp, "Lists must be {db key}",
02393 TCL_STATIC);
02394 result = TCL_ERROR;
02395 goto out;
02396 }
02397
02398
02399
02400
02401 elemdbp = NAME_TO_DB(Tcl_GetStringFromObj(elemv[0], NULL));
02402 if (elemdbp == NULL) {
02403 snprintf(msg, MSG_SIZE, "Get_join: Invalid db: %s\n",
02404 Tcl_GetStringFromObj(elemv[0], NULL));
02405 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02406 result = TCL_ERROR;
02407 goto out;
02408 }
02409 ret = elemdbp->cursor(elemdbp, txn, &listp[j], 0);
02410 if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
02411 "db cursor")) == TCL_ERROR)
02412 goto out;
02413 memset(&key, 0, sizeof(key));
02414 memset(&data, 0, sizeof(data));
02415 ret = _CopyObjBytes(interp, elemv[elemc-1], &ktmp,
02416 &key.size, &freekey);
02417 if (ret != 0) {
02418 result = _ReturnSetup(interp, ret,
02419 DB_RETOK_STD(ret), "db join");
02420 goto out;
02421 }
02422 key.data = ktmp;
02423 ret = (listp[j])->c_get(listp[j], &key, &data, DB_SET);
02424 if ((result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret),
02425 "db cget")) == TCL_ERROR)
02426 goto out;
02427 }
02428 listp[j] = NULL;
02429 _debug_check();
02430 ret = dbp->join(dbp, listp, &dbc, flag);
02431 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db join");
02432 if (result == TCL_ERROR)
02433 goto out;
02434
02435 retlist = Tcl_NewListObj(0, NULL);
02436 while (ret == 0 && result == TCL_OK) {
02437 memset(&key, 0, sizeof(key));
02438 memset(&data, 0, sizeof(data));
02439 key.flags |= DB_DBT_MALLOC;
02440 data.flags |= DB_DBT_MALLOC;
02441 ret = dbc->c_get(dbc, &key, &data, 0);
02442
02443
02444
02445 if (ret == 0) {
02446 result = _SetListElem(interp, retlist,
02447 key.data, key.size,
02448 data.data, data.size);
02449 __os_ufree(dbp->dbenv, key.data);
02450 __os_ufree(dbp->dbenv, data.data);
02451 }
02452 }
02453 (void)dbc->c_close(dbc);
02454 if (result == TCL_OK)
02455 Tcl_SetObjResult(interp, retlist);
02456 out:
02457 if (ktmp != NULL && freekey)
02458 __os_free(dbp->dbenv, ktmp);
02459 while (j) {
02460 if (listp[j])
02461 (void)(listp[j])->c_close(listp[j]);
02462 j--;
02463 }
02464 __os_free(dbp->dbenv, listp);
02465 return (result);
02466 }
02467
02468
02469
02470
02471 static int
02472 tcl_DbGetFlags(interp, objc, objv, dbp)
02473 Tcl_Interp *interp;
02474 int objc;
02475 Tcl_Obj *CONST objv[];
02476 DB *dbp;
02477 {
02478 int i, ret, result;
02479 u_int32_t flags;
02480 char buf[512];
02481 Tcl_Obj *res;
02482
02483 static const struct {
02484 u_int32_t flag;
02485 char *arg;
02486 } db_flags[] = {
02487 { DB_CHKSUM, "-chksum" },
02488 { DB_DUP, "-dup" },
02489 { DB_DUPSORT, "-dupsort" },
02490 { DB_ENCRYPT, "-encrypt" },
02491 { DB_INORDER, "-inorder" },
02492 { DB_TXN_NOT_DURABLE, "-notdurable" },
02493 { DB_RECNUM, "-recnum" },
02494 { DB_RENUMBER, "-renumber" },
02495 { DB_REVSPLITOFF, "-revsplitoff" },
02496 { DB_SNAPSHOT, "-snapshot" },
02497 { 0, NULL }
02498 };
02499
02500 if (objc != 2) {
02501 Tcl_WrongNumArgs(interp, 1, objv, NULL);
02502 return (TCL_ERROR);
02503 }
02504
02505 ret = dbp->get_flags(dbp, &flags);
02506 if ((result = _ReturnSetup(
02507 interp, ret, DB_RETOK_STD(ret), "db get_flags")) == TCL_OK) {
02508 buf[0] = '\0';
02509
02510 for (i = 0; db_flags[i].flag != 0; i++)
02511 if (LF_ISSET(db_flags[i].flag)) {
02512 if (strlen(buf) > 0)
02513 (void)strncat(buf, " ", sizeof(buf));
02514 (void)strncat(
02515 buf, db_flags[i].arg, sizeof(buf));
02516 }
02517
02518 res = NewStringObj(buf, strlen(buf));
02519 Tcl_SetObjResult(interp, res);
02520 }
02521
02522 return (result);
02523 }
02524
02525
02526
02527
02528 static int
02529 tcl_DbGetOpenFlags(interp, objc, objv, dbp)
02530 Tcl_Interp *interp;
02531 int objc;
02532 Tcl_Obj *CONST objv[];
02533 DB *dbp;
02534 {
02535 int i, ret, result;
02536 u_int32_t flags;
02537 char buf[512];
02538 Tcl_Obj *res;
02539
02540 static const struct {
02541 u_int32_t flag;
02542 char *arg;
02543 } open_flags[] = {
02544 { DB_AUTO_COMMIT, "-auto_commit" },
02545 { DB_CREATE, "-create" },
02546 { DB_EXCL, "-excl" },
02547 { DB_NOMMAP, "-nommap" },
02548 { DB_RDONLY, "-rdonly" },
02549 { DB_READ_COMMITTED, "-read_committed" },
02550 { DB_READ_UNCOMMITTED, "-read_uncommitted" },
02551 { DB_THREAD, "-thread" },
02552 { DB_TRUNCATE, "-truncate" },
02553 { 0, NULL }
02554 };
02555
02556 if (objc != 2) {
02557 Tcl_WrongNumArgs(interp, 1, objv, NULL);
02558 return (TCL_ERROR);
02559 }
02560
02561 ret = dbp->get_open_flags(dbp, &flags);
02562 if ((result = _ReturnSetup(
02563 interp, ret, DB_RETOK_STD(ret), "db get_open_flags")) == TCL_OK) {
02564 buf[0] = '\0';
02565
02566 for (i = 0; open_flags[i].flag != 0; i++)
02567 if (LF_ISSET(open_flags[i].flag)) {
02568 if (strlen(buf) > 0)
02569 (void)strncat(buf, " ", sizeof(buf));
02570 (void)strncat(
02571 buf, open_flags[i].arg, sizeof(buf));
02572 }
02573
02574 res = NewStringObj(buf, strlen(buf));
02575 Tcl_SetObjResult(interp, res);
02576 }
02577
02578 return (result);
02579 }
02580
02581
02582
02583
02584 static int
02585 tcl_DbCount(interp, objc, objv, dbp)
02586 Tcl_Interp *interp;
02587 int objc;
02588 Tcl_Obj *CONST objv[];
02589 DB *dbp;
02590 {
02591 Tcl_Obj *res;
02592 DBC *dbc;
02593 DBT key, data;
02594 void *ktmp;
02595 db_recno_t count, recno;
02596 int freekey, result, ret;
02597
02598 res = NULL;
02599 count = 0;
02600 freekey = ret = 0;
02601 ktmp = NULL;
02602 result = TCL_OK;
02603
02604 if (objc != 3) {
02605 Tcl_WrongNumArgs(interp, 2, objv, "key");
02606 return (TCL_ERROR);
02607 }
02608
02609
02610
02611
02612
02613
02614 memset(&key, 0, sizeof(key));
02615 memset(&data, 0, sizeof(data));
02616
02617
02618
02619
02620
02621 if (dbp->type == DB_RECNO || dbp->type == DB_QUEUE) {
02622 result = _GetUInt32(interp, objv[2], &recno);
02623 if (result == TCL_OK) {
02624 key.data = &recno;
02625 key.size = sizeof(db_recno_t);
02626 } else
02627 return (result);
02628 } else {
02629 ret = _CopyObjBytes(interp, objv[2], &ktmp,
02630 &key.size, &freekey);
02631 if (ret != 0) {
02632 result = _ReturnSetup(interp, ret,
02633 DB_RETOK_STD(ret), "db count");
02634 return (result);
02635 }
02636 key.data = ktmp;
02637 }
02638 _debug_check();
02639 ret = dbp->cursor(dbp, NULL, &dbc, 0);
02640 if (ret != 0) {
02641 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
02642 "db cursor");
02643 goto out;
02644 }
02645
02646
02647
02648 ret = dbc->c_get(dbc, &key, &data, DB_SET);
02649 if (ret == DB_KEYEMPTY || ret == DB_NOTFOUND)
02650 count = 0;
02651 else {
02652 ret = dbc->c_count(dbc, &count, 0);
02653 if (ret != 0) {
02654 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
02655 "db c count");
02656 goto out;
02657 }
02658 }
02659 res = Tcl_NewWideIntObj((Tcl_WideInt)count);
02660 Tcl_SetObjResult(interp, res);
02661
02662 out: if (ktmp != NULL && freekey)
02663 __os_free(dbp->dbenv, ktmp);
02664 (void)dbc->c_close(dbc);
02665 return (result);
02666 }
02667
02668 #ifdef CONFIG_TEST
02669
02670
02671
02672 static int
02673 tcl_DbKeyRange(interp, objc, objv, dbp)
02674 Tcl_Interp *interp;
02675 int objc;
02676 Tcl_Obj *CONST objv[];
02677 DB *dbp;
02678 {
02679 static const char *dbkeyropts[] = {
02680 "-txn",
02681 NULL
02682 };
02683 enum dbkeyropts {
02684 DBKEYR_TXN
02685 };
02686 DB_TXN *txn;
02687 DB_KEY_RANGE range;
02688 DBT key;
02689 DBTYPE type;
02690 Tcl_Obj *myobjv[3], *retlist;
02691 void *ktmp;
02692 db_recno_t recno;
02693 u_int32_t flag;
02694 int freekey, i, myobjc, optindex, result, ret;
02695 char *arg, msg[MSG_SIZE];
02696
02697 ktmp = NULL;
02698 flag = 0;
02699 freekey = 0;
02700 result = TCL_OK;
02701 if (objc < 3) {
02702 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id? key");
02703 return (TCL_ERROR);
02704 }
02705
02706 txn = NULL;
02707 for (i = 2; i < objc;) {
02708 if (Tcl_GetIndexFromObj(interp, objv[i], dbkeyropts, "option",
02709 TCL_EXACT, &optindex) != TCL_OK) {
02710 result = IS_HELP(objv[i]);
02711 if (result == TCL_OK)
02712 return (result);
02713 result = TCL_OK;
02714 Tcl_ResetResult(interp);
02715 break;
02716 }
02717 i++;
02718 switch ((enum dbkeyropts)optindex) {
02719 case DBKEYR_TXN:
02720 if (i == objc) {
02721 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
02722 result = TCL_ERROR;
02723 break;
02724 }
02725 arg = Tcl_GetStringFromObj(objv[i++], NULL);
02726 txn = NAME_TO_TXN(arg);
02727 if (txn == NULL) {
02728 snprintf(msg, MSG_SIZE,
02729 "KeyRange: Invalid txn: %s\n", arg);
02730 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02731 result = TCL_ERROR;
02732 }
02733 break;
02734 }
02735 }
02736 if (result != TCL_OK)
02737 return (result);
02738 (void)dbp->get_type(dbp, &type);
02739 ret = 0;
02740
02741
02742
02743 if (i != (objc - 1)) {
02744 Tcl_WrongNumArgs(interp, 2, objv, "?args? key");
02745 result = TCL_ERROR;
02746 goto out;
02747 }
02748 memset(&key, 0, sizeof(key));
02749 if (type == DB_RECNO || type == DB_QUEUE) {
02750 result = _GetUInt32(interp, objv[i], &recno);
02751 if (result == TCL_OK) {
02752 key.data = &recno;
02753 key.size = sizeof(db_recno_t);
02754 } else
02755 return (result);
02756 } else {
02757 ret = _CopyObjBytes(interp, objv[i++], &ktmp,
02758 &key.size, &freekey);
02759 if (ret != 0) {
02760 result = _ReturnSetup(interp, ret,
02761 DB_RETOK_STD(ret), "db keyrange");
02762 return (result);
02763 }
02764 key.data = ktmp;
02765 }
02766 _debug_check();
02767 ret = dbp->key_range(dbp, txn, &key, &range, flag);
02768 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db keyrange");
02769 if (result == TCL_ERROR)
02770 goto out;
02771
02772
02773
02774
02775 myobjc = 3;
02776 myobjv[0] = Tcl_NewDoubleObj(range.less);
02777 myobjv[1] = Tcl_NewDoubleObj(range.equal);
02778 myobjv[2] = Tcl_NewDoubleObj(range.greater);
02779 retlist = Tcl_NewListObj(myobjc, myobjv);
02780 if (result == TCL_OK)
02781 Tcl_SetObjResult(interp, retlist);
02782
02783 out: if (ktmp != NULL && freekey)
02784 __os_free(dbp->dbenv, ktmp);
02785 return (result);
02786 }
02787 #endif
02788
02789
02790
02791
02792 static int
02793 tcl_DbTruncate(interp, objc, objv, dbp)
02794 Tcl_Interp *interp;
02795 int objc;
02796 Tcl_Obj *CONST objv[];
02797 DB *dbp;
02798 {
02799 static const char *dbcuropts[] = {
02800 "-txn",
02801 NULL
02802 };
02803 enum dbcuropts {
02804 DBTRUNC_TXN
02805 };
02806 DB_TXN *txn;
02807 Tcl_Obj *res;
02808 u_int32_t count;
02809 int i, optindex, result, ret;
02810 char *arg, msg[MSG_SIZE];
02811
02812 txn = NULL;
02813 result = TCL_OK;
02814
02815 i = 2;
02816 while (i < objc) {
02817 if (Tcl_GetIndexFromObj(interp, objv[i], dbcuropts, "option",
02818 TCL_EXACT, &optindex) != TCL_OK) {
02819 result = IS_HELP(objv[i]);
02820 goto out;
02821 }
02822 i++;
02823 switch ((enum dbcuropts)optindex) {
02824 case DBTRUNC_TXN:
02825 if (i == objc) {
02826 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
02827 result = TCL_ERROR;
02828 break;
02829 }
02830 arg = Tcl_GetStringFromObj(objv[i++], NULL);
02831 txn = NAME_TO_TXN(arg);
02832 if (txn == NULL) {
02833 snprintf(msg, MSG_SIZE,
02834 "Truncate: Invalid txn: %s\n", arg);
02835 Tcl_SetResult(interp, msg, TCL_VOLATILE);
02836 result = TCL_ERROR;
02837 }
02838 break;
02839 }
02840 if (result != TCL_OK)
02841 break;
02842 }
02843 if (result != TCL_OK)
02844 goto out;
02845
02846 _debug_check();
02847 ret = dbp->truncate(dbp, txn, &count, 0);
02848 if (ret != 0)
02849 result = _ErrorSetup(interp, ret, "db truncate");
02850
02851 else {
02852 res = Tcl_NewWideIntObj((Tcl_WideInt)count);
02853 Tcl_SetObjResult(interp, res);
02854 }
02855 out:
02856 return (result);
02857 }
02858
02859 #ifdef CONFIG_TEST
02860
02861
02862
02863 static int
02864 tcl_DbCompact(interp, objc, objv, dbp)
02865 Tcl_Interp *interp;
02866 int objc;
02867 Tcl_Obj *CONST objv[];
02868 DB *dbp;
02869 {
02870 static const char *dbcuropts[] = {
02871 "-fillpercent",
02872 "-freespace",
02873 "-freeonly",
02874 "-pages",
02875 "-start",
02876 "-stop",
02877 "-timeout",
02878 "-txn",
02879 NULL
02880 };
02881 enum dbcuropts {
02882 DBREORG_FILLFACTOR,
02883 DBREORG_FREESPACE,
02884 DBREORG_FREEONLY,
02885 DBREORG_PAGES,
02886 DBREORG_START,
02887 DBREORG_STOP,
02888 DBREORG_TIMEOUT,
02889 DBREORG_TXN
02890 };
02891 DBTCL_INFO *ip;
02892 DBT *key, end, start, stop;
02893 DBTYPE type;
02894 DB_TXN *txn;
02895 Tcl_Obj *myobj, *retlist;
02896 db_recno_t recno, srecno;
02897 u_int32_t arg, fillfactor, flags, pages, timeout;
02898 char *carg, msg[MSG_SIZE];
02899 int freekey, i, optindex, result, ret;
02900 void *kp;
02901
02902 flags = 0;
02903 result = TCL_OK;
02904 txn = NULL;
02905 (void)dbp->get_type(dbp, &type);
02906 memset(&start, 0, sizeof(start));
02907 memset(&stop, 0, sizeof(stop));
02908 memset(&end, 0, sizeof(end));
02909 ip = (DBTCL_INFO *)dbp->api_internal;
02910 fillfactor = pages = timeout = 0;
02911
02912 i = 2;
02913 while (i < objc) {
02914 if (Tcl_GetIndexFromObj(interp, objv[i], dbcuropts, "option",
02915 TCL_EXACT, &optindex) != TCL_OK) {
02916 result = IS_HELP(objv[i]);
02917 goto out;
02918 }
02919 i++;
02920 switch ((enum dbcuropts)optindex) {
02921 case DBREORG_FILLFACTOR:
02922 if (i == objc) {
02923 Tcl_WrongNumArgs(interp,
02924 2, objv, "?-fillfactor number?");
02925 result = TCL_ERROR;
02926 break;
02927 }
02928 result = _GetUInt32(interp, objv[i++], &arg);
02929 if (result != TCL_OK)
02930 goto out;
02931 i++;
02932 fillfactor = arg;
02933 break;
02934 case DBREORG_FREESPACE:
02935 LF_SET(DB_FREE_SPACE);
02936 break;
02937
02938 case DBREORG_FREEONLY:
02939 LF_SET(DB_FREELIST_ONLY);
02940 break;
02941
02942 case DBREORG_PAGES:
02943 if (i == objc) {
02944 Tcl_WrongNumArgs(interp,
02945 2, objv, "?-pages number?");
02946 result = TCL_ERROR;
02947 break;
02948 }
02949 result = _GetUInt32(interp, objv[i++], &arg);
02950 if (result != TCL_OK)
02951 goto out;
02952 i++;
02953 pages = arg;
02954 break;
02955 case DBREORG_TIMEOUT:
02956 if (i == objc) {
02957 Tcl_WrongNumArgs(interp,
02958 2, objv, "?-timeout number?");
02959 result = TCL_ERROR;
02960 break;
02961 }
02962 result = _GetUInt32(interp, objv[i++], &arg);
02963 if (result != TCL_OK)
02964 goto out;
02965 i++;
02966 timeout = arg;
02967 break;
02968
02969 case DBREORG_START:
02970 case DBREORG_STOP:
02971 if (i == objc) {
02972 Tcl_WrongNumArgs(interp, 1, objv,
02973 "?-args? -start/stop key");
02974 result = TCL_ERROR;
02975 goto out;
02976 }
02977 if ((enum dbcuropts)optindex == DBREORG_START) {
02978 key = &start;
02979 key->data = &recno;
02980 } else {
02981 key = &stop;
02982 key->data = &srecno;
02983 }
02984 if (type == DB_RECNO || type == DB_QUEUE) {
02985 result = _GetUInt32(
02986 interp, objv[i], key->data);
02987 if (result == TCL_OK) {
02988 key->size = sizeof(db_recno_t);
02989 } else
02990 goto out;
02991 } else {
02992 ret = _CopyObjBytes(interp, objv[i],
02993 &key->data, &key->size, &freekey);
02994 if (ret != 0)
02995 goto err;
02996 if (freekey == 0) {
02997 if ((ret = __os_malloc(NULL,
02998 key->size, &kp)) != 0)
02999 goto err;
03000
03001 memcpy(kp, key->data, key->size);
03002 key->data = kp;
03003 key->ulen = key->size;
03004 }
03005 }
03006 i++;
03007 break;
03008 case DBREORG_TXN:
03009 if (i == objc) {
03010 Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?");
03011 result = TCL_ERROR;
03012 break;
03013 }
03014 carg = Tcl_GetStringFromObj(objv[i++], NULL);
03015 txn = NAME_TO_TXN(carg);
03016 if (txn == NULL) {
03017 snprintf(msg, MSG_SIZE,
03018 "Compact: Invalid txn: %s\n", carg);
03019 Tcl_SetResult(interp, msg, TCL_VOLATILE);
03020 result = TCL_ERROR;
03021 }
03022 }
03023 if (result != TCL_OK)
03024 break;
03025 }
03026 if (result != TCL_OK)
03027 goto out;
03028
03029 if (ip->i_cdata == NULL)
03030 if ((ret = __os_calloc(dbp->dbenv,
03031 1, sizeof(DB_COMPACT), &ip->i_cdata)) != 0) {
03032 Tcl_SetResult(interp,
03033 db_strerror(ret), TCL_STATIC);
03034 goto out;
03035 }
03036
03037 ip->i_cdata->compact_fillpercent = fillfactor;
03038 ip->i_cdata->compact_timeout = timeout;
03039 ip->i_cdata->compact_pages = pages;
03040
03041 _debug_check();
03042 ret = dbp->compact(dbp, txn, &start, &stop, ip->i_cdata, flags, &end);
03043 result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret), "dbp compact");
03044 if (result == TCL_ERROR)
03045 goto out;
03046
03047 retlist = Tcl_NewListObj(0, NULL);
03048 if (ret != 0)
03049 goto out;
03050 if (type == DB_RECNO || type == DB_QUEUE) {
03051 if (end.size == 0)
03052 recno = 0;
03053 else
03054 recno = *((db_recno_t *)end.data);
03055 myobj = Tcl_NewWideIntObj((Tcl_WideInt)recno);
03056 } else
03057 myobj = Tcl_NewByteArrayObj(end.data, (int)end.size);
03058 result = Tcl_ListObjAppendElement(interp, retlist, myobj);
03059 if (result == TCL_OK)
03060 Tcl_SetObjResult(interp, retlist);
03061
03062 if (0) {
03063 err: result = _ReturnSetup(interp,
03064 ret, DB_RETOK_DBCGET(ret), "dbc compact");
03065 }
03066 out:
03067 if (start.data != NULL && start.data != &recno)
03068 __os_free(NULL, start.data);
03069 if (stop.data != NULL && stop.data != &srecno)
03070 __os_free(NULL, stop.data);
03071
03072 return (result);
03073 }
03074
03075
03076
03077
03078 static int
03079 tcl_DbCompactStat(interp, objc, objv, dbp)
03080 Tcl_Interp *interp;
03081 int objc;
03082 Tcl_Obj *CONST objv[];
03083 DB *dbp;
03084 {
03085 DBTCL_INFO *ip;
03086
03087 COMPQUIET(objc, 0);
03088 COMPQUIET(objv, NULL);
03089
03090 ip = (DBTCL_INFO *)dbp->api_internal;
03091
03092 return (tcl_CompactStat(interp, ip));
03093 }
03094
03095
03096
03097
03098 int
03099 tcl_CompactStat(interp, ip)
03100 Tcl_Interp *interp;
03101 DBTCL_INFO *ip;
03102 {
03103 DB_COMPACT *rp;
03104 Tcl_Obj *res;
03105 int result;
03106 char msg[MSG_SIZE];
03107
03108 result = TCL_OK;
03109 rp = NULL;
03110
03111 _debug_check();
03112 if ((rp = ip->i_cdata) == NULL) {
03113 snprintf(msg, MSG_SIZE,
03114 "Compact stat: No stats available\n");
03115 Tcl_SetResult(interp, msg, TCL_VOLATILE);
03116 result = TCL_ERROR;
03117 goto error;
03118 }
03119
03120 res = Tcl_NewObj();
03121
03122 MAKE_STAT_LIST("Pages freed", rp->compact_pages_free);
03123 MAKE_STAT_LIST("Pages truncated", rp->compact_pages_truncated);
03124 MAKE_STAT_LIST("Pages examined", rp->compact_pages_examine);
03125 MAKE_STAT_LIST("Levels removed", rp->compact_levels);
03126 MAKE_STAT_LIST("Deadlocks encountered", rp->compact_deadlock);
03127
03128 Tcl_SetObjResult(interp, res);
03129 error:
03130 return (result);
03131 }
03132 #endif