📄 tcl_db.c
字号:
* Callback function for secondary indices. Get the callback * out of ip->i_second_call and call it. */static inttcl_second_call(dbp, pkey, data, skey) DB *dbp; const DBT *pkey, *data; DBT *skey;{ DBTCL_INFO *ip; Tcl_Interp *interp; Tcl_Obj *pobj, *dobj, *objv[3]; int len, result, ret; void *retbuf, *databuf; ip = (DBTCL_INFO *)dbp->api_internal; interp = ip->i_interp; objv[0] = ip->i_second_call; /* * Create two ByteArray objects, with the contents of the pkey * and data DBTs that are our inputs. */ pobj = Tcl_NewByteArrayObj(pkey->data, pkey->size); Tcl_IncrRefCount(pobj); dobj = Tcl_NewByteArrayObj(data->data, data->size); Tcl_IncrRefCount(dobj); objv[1] = pobj; objv[2] = dobj; result = Tcl_EvalObjv(interp, 3, objv, 0); Tcl_DecrRefCount(pobj); Tcl_DecrRefCount(dobj); if (result != TCL_OK) { __db_err(dbp->dbenv, "Tcl callback function failed with code %d", result); return (EINVAL); } retbuf = Tcl_GetByteArrayFromObj(Tcl_GetObjResult(interp), &len); /* * retbuf is owned by Tcl; copy it into malloc'ed memory. * We need to use __os_umalloc rather than ufree because this will * be freed by DB using __os_ufree--the DB_DBT_APPMALLOC flag * tells DB to free application-allocated memory. */ if ((ret = __os_umalloc(dbp->dbenv, len, &databuf)) != 0) return (ret); memcpy(databuf, retbuf, len); skey->data = databuf; skey->size = len; F_SET(skey, DB_DBT_APPMALLOC); return (0);}/* * tcl_db_join -- */static inttcl_DbJoin(interp, objc, objv, dbp, dbcp) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */ DBC **dbcp; /* Cursor pointer */{ static char *dbjopts[] = { "-nosort", NULL }; enum dbjopts { DBJ_NOSORT }; DBC **listp; u_int32_t flag; int adj, i, j, optindex, size, result, ret; char *arg, msg[MSG_SIZE]; result = TCL_OK; flag = 0; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "curs1 curs2 ..."); return (TCL_ERROR); } i = 2; adj = i; while (i < objc) { if (Tcl_GetIndexFromObj(interp, objv[i], dbjopts, "option", TCL_EXACT, &optindex) != TCL_OK) { result = IS_HELP(objv[i]); if (result == TCL_OK) return (result); result = TCL_OK; Tcl_ResetResult(interp); break; } i++; switch ((enum dbjopts)optindex) { case DBJ_NOSORT: flag |= DB_JOIN_NOSORT; adj++; break; } } if (result != TCL_OK) return (result); /* * Allocate one more for NULL ptr at end of list. */ size = sizeof(DBC *) * ((objc - adj) + 1); ret = __os_malloc(dbp->dbenv, size, &listp); if (ret != 0) { Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); return (TCL_ERROR); } memset(listp, 0, size); for (j = 0, i = adj; i < objc; i++, j++) { arg = Tcl_GetStringFromObj(objv[i], NULL); listp[j] = NAME_TO_DBC(arg); if (listp[j] == NULL) { snprintf(msg, MSG_SIZE, "Join: Invalid cursor: %s\n", arg); Tcl_SetResult(interp, msg, TCL_VOLATILE); result = TCL_ERROR; goto out; } } listp[j] = NULL; _debug_check(); ret = dbp->join(dbp, listp, dbcp, flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db join");out: __os_free(dbp->dbenv, listp); return (result);}/* * tcl_db_getjoin -- */static inttcl_DbGetjoin(interp, objc, objv, dbp) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */{ static char *dbgetjopts[] = {#if CONFIG_TEST "-nosort",#endif "-txn", NULL }; enum dbgetjopts {#if CONFIG_TEST DBGETJ_NOSORT,#endif DBGETJ_TXN }; DB_TXN *txn; DB *elemdbp; DBC **listp; DBC *dbc; DBT key, data; Tcl_Obj **elemv, *retlist; void *ktmp; u_int32_t flag; int adj, elemc, freekey, i, j, optindex, result, ret, size; char *arg, msg[MSG_SIZE]; result = TCL_OK; flag = 0; freekey = 0; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "{db1 key1} {db2 key2} ..."); return (TCL_ERROR); } txn = NULL; i = 2; adj = i; while (i < objc) { if (Tcl_GetIndexFromObj(interp, objv[i], dbgetjopts, "option", TCL_EXACT, &optindex) != TCL_OK) { result = IS_HELP(objv[i]); if (result == TCL_OK) return (result); result = TCL_OK; Tcl_ResetResult(interp); break; } i++; switch ((enum dbgetjopts)optindex) {#if CONFIG_TEST case DBGETJ_NOSORT: flag |= DB_JOIN_NOSORT; adj++; break;#endif case DBGETJ_TXN: if (i == objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); result = TCL_ERROR; break; } arg = Tcl_GetStringFromObj(objv[i++], NULL); txn = NAME_TO_TXN(arg); adj += 2; if (txn == NULL) { snprintf(msg, MSG_SIZE, "GetJoin: Invalid txn: %s\n", arg); Tcl_SetResult(interp, msg, TCL_VOLATILE); result = TCL_ERROR; } break; } } if (result != TCL_OK) return (result); size = sizeof(DBC *) * ((objc - adj) + 1); ret = __os_malloc(NULL, size, &listp); if (ret != 0) { Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC); return (TCL_ERROR); } memset(listp, 0, size); for (j = 0, i = adj; i < objc; i++, j++) { /* * Get each sublist as {db key} */ result = Tcl_ListObjGetElements(interp, objv[i], &elemc, &elemv); if (elemc != 2) { Tcl_SetResult(interp, "Lists must be {db key}", TCL_STATIC); result = TCL_ERROR; goto out; } /* * Get a pointer to that open db. Then, open a cursor in * that db, and go to the "key" place. */ elemdbp = NAME_TO_DB(Tcl_GetStringFromObj(elemv[0], NULL)); if (elemdbp == NULL) { snprintf(msg, MSG_SIZE, "Get_join: Invalid db: %s\n", Tcl_GetStringFromObj(elemv[0], NULL)); Tcl_SetResult(interp, msg, TCL_VOLATILE); result = TCL_ERROR; goto out; } ret = elemdbp->cursor(elemdbp, txn, &listp[j], 0); if ((result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db cursor")) == TCL_ERROR) goto out; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); ret = _CopyObjBytes(interp, elemv[elemc-1], &ktmp, &key.size, &freekey); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db join"); goto out; } key.data = ktmp; ret = (listp[j])->c_get(listp[j], &key, &data, DB_SET); if ((result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret), "db cget")) == TCL_ERROR) goto out; } listp[j] = NULL; _debug_check(); ret = dbp->join(dbp, listp, &dbc, flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db join"); if (result == TCL_ERROR) goto out; retlist = Tcl_NewListObj(0, NULL); while (ret == 0 && result == TCL_OK) { memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.flags |= DB_DBT_MALLOC; data.flags |= DB_DBT_MALLOC; ret = dbc->c_get(dbc, &key, &data, 0); /* * Build up our {name value} sublist */ if (ret == 0) { result = _SetListElem(interp, retlist, key.data, key.size, data.data, data.size); free(key.data); free(data.data); } } dbc->c_close(dbc); if (result == TCL_OK) Tcl_SetObjResult(interp, retlist);out: if (freekey) (void)__os_free(dbp->dbenv, ktmp); while (j) { if (listp[j]) (listp[j])->c_close(listp[j]); j--; } __os_free(dbp->dbenv, listp); return (result);}/* * tcl_DbCount -- */static inttcl_DbCount(interp, objc, objv, dbp) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */{ Tcl_Obj *res; DBC *dbc; DBT key, data; void *ktmp; db_recno_t count, recno; int freekey, result, ret; result = TCL_OK; count = 0; freekey = 0; res = NULL; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "key"); return (TCL_ERROR); } memset(&key, 0, sizeof(key)); /* * Get the count for our key. * We do this by getting a cursor for this DB. Moving the cursor * to the set location, and getting a count on that cursor. */ ret = 0; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); /* * If it's a queue or recno database, we must make sure to * treat the key as a recno rather than as a byte string. */ if (dbp->type == DB_RECNO || dbp->type == DB_QUEUE) { result = _GetUInt32(interp, objv[2], &recno); if (result == TCL_OK) { key.data = &recno; key.size = sizeof(db_recno_t); } else return (result); } else { ret = _CopyObjBytes(interp, objv[2], &ktmp, &key.size, &freekey); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db count"); return (result); } key.data = ktmp; } _debug_check(); ret = dbp->cursor(dbp, NULL, &dbc, 0); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db cursor"); goto out; } /* * Move our cursor to the key. */ ret = dbc->c_get(dbc, &key, &data, DB_SET); if (ret == DB_NOTFOUND) count = 0; else { ret = dbc->c_count(dbc, &count, 0); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db c count"); goto out; } } res = Tcl_NewLongObj((long)count); Tcl_SetObjResult(interp, res);out: if (freekey) (void)__os_free(dbp->dbenv, ktmp); (void)dbc->c_close(dbc); return (result);}#if CONFIG_TEST/* * tcl_DbKeyRange -- */static inttcl_DbKeyRange(interp, objc, objv, dbp) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */{ static char *dbkeyropts[] = { "-txn", NULL }; enum dbkeyropts { DBKEYR_TXN }; DB_TXN *txn; DB_KEY_RANGE range; DBT key; DBTYPE type; Tcl_Obj *myobjv[3], *retlist; void *ktmp; db_recno_t recno; u_int32_t flag; int freekey, i, myobjc, optindex, result, ret; char *arg, msg[MSG_SIZE]; result = TCL_OK; flag = 0; freekey = 0; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn id? key"); return (TCL_ERROR); } txn = NULL; i = 2; while (i < objc) { if (Tcl_GetIndexFromObj(interp, objv[i], dbkeyropts, "option", TCL_EXACT, &optindex) != TCL_OK) { result = IS_HELP(objv[i]); if (result == TCL_OK) return (result); result = TCL_OK; Tcl_ResetResult(interp); break; } i++; switch ((enum dbkeyropts)optindex) { case DBKEYR_TXN: if (i == objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); result = TCL_ERROR; break; } arg = Tcl_GetStringFromObj(objv[i++], NULL); txn = NAME_TO_TXN(arg); if (txn == NULL) { snprintf(msg, MSG_SIZE, "KeyRange: Invalid txn: %s\n", arg); Tcl_SetResult(interp, msg, TCL_VOLATILE); result = TCL_ERROR; } break; } } if (result != TCL_OK) return (result); (void)dbp->get_type(dbp, &type); ret = 0; /* * Make sure we have a key. */ if (i != (objc - 1)) { Tcl_WrongNumArgs(interp, 2, objv, "?args? key"); result = TCL_ERROR; goto out; } memset(&key, 0, sizeof(key)); if (type == DB_RECNO || type == DB_QUEUE) { result = _GetUInt32(interp, objv[i], &recno); if (result == TCL_OK) { key.data = &recno; key.size = sizeof(db_recno_t); } else return (result); } else { ret = _CopyObjBytes(interp, objv[i++], &ktmp, &key.size, &freekey); if (ret != 0) { result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db keyrange"); return (result); } key.data = ktmp; } _debug_check(); ret = dbp->key_range(dbp, txn, &key, &range, flag); result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "db keyrange"); if (result == TCL_ERROR) goto out; /* * If we succeeded, set up return list. */ myobjc = 3; myobjv[0] = Tcl_NewDoubleObj(range.less); myobjv[1] = Tcl_NewDoubleObj(range.equal); myobjv[2] = Tcl_NewDoubleObj(range.greater); retlist = Tcl_NewListObj(myobjc, myobjv); if (result == TCL_OK) Tcl_SetObjResult(interp, retlist);out: if (freekey) (void)__os_free(dbp->dbenv, ktmp); return (result);}#endif/* * tcl_DbTruncate -- */static inttcl_DbTruncate(interp, objc, objv, dbp) Tcl_Interp *interp; /* Interpreter */ int objc; /* How many arguments? */ Tcl_Obj *CONST objv[]; /* The argument objects */ DB *dbp; /* Database pointer */{ static char *dbcuropts[] = { "-auto_commit", "-txn", NULL }; enum dbcuropts { DBTRUNC_AUTO_COMMIT, DBTRUNC_TXN }; DB_TXN *txn; Tcl_Obj *res; u_int32_t count, flag; int i, optindex, result, ret; char *arg, msg[MSG_SIZE]; txn = NULL; flag = 0; result = TCL_OK; i = 2; while (i < objc) { if (Tcl_GetIndexFromObj(interp, objv[i], dbcuropts, "option", TCL_EXACT, &optindex) != TCL_OK) { result = IS_HELP(objv[i]); goto out; } i++; switch ((enum dbcuropts)optindex) { case DBTRUNC_AUTO_COMMIT: flag |= DB_AUTO_COMMIT; break; case DBTRUNC_TXN: if (i == objc) { Tcl_WrongNumArgs(interp, 2, objv, "?-txn id?"); result = TCL_ERROR; break; } arg = Tcl_GetStringFromObj(objv[i++], NULL); txn = NAME_TO_TXN(arg); if (txn == NULL) { snprintf(msg, MSG_SIZE, "Truncate: Invalid txn: %s\n", arg); Tcl_SetResult(interp, msg, TCL_VOLATILE); result = TCL_ERROR; } break; } if (result != TCL_OK) break; } if (result != TCL_OK) goto out; _debug_check(); ret = dbp->truncate(dbp, txn, &count, flag); if (ret != 0) result = _ErrorSetup(interp, ret, "db truncate"); else { res = Tcl_NewLongObj((long)count); Tcl_SetObjResult(interp, res); }out: return (result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -