tcl_dbcursor.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:21k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999-2001
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: tcl_dbcursor.c,v 11.51 2002/08/06 06:20:59 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <tcl.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "dbinc/tcl_db.h"
  19. /*
  20.  * Prototypes for procedures defined later in this file:
  21.  */
  22. static int tcl_DbcDup __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *));
  23. static int tcl_DbcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *, int));
  24. static int tcl_DbcPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBC *));
  25. /*
  26.  * PUBLIC: int dbc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
  27.  *
  28.  * dbc_cmd --
  29.  * Implements the cursor command.
  30.  */
  31. int
  32. dbc_Cmd(clientData, interp, objc, objv)
  33. ClientData clientData; /* Cursor handle */
  34. Tcl_Interp *interp; /* Interpreter */
  35. int objc; /* How many arguments? */
  36. Tcl_Obj *CONST objv[]; /* The argument objects */
  37. {
  38. static char *dbccmds[] = {
  39. #if CONFIG_TEST
  40. "pget",
  41. #endif
  42. "close",
  43. "del",
  44. "dup",
  45. "get",
  46. "put",
  47. NULL
  48. };
  49. enum dbccmds {
  50. #if CONFIG_TEST
  51. DBCPGET,
  52. #endif
  53. DBCCLOSE,
  54. DBCDELETE,
  55. DBCDUP,
  56. DBCGET,
  57. DBCPUT
  58. };
  59. DBC *dbc;
  60. DBTCL_INFO *dbip;
  61. int cmdindex, result, ret;
  62. Tcl_ResetResult(interp);
  63. dbc = (DBC *)clientData;
  64. dbip = _PtrToInfo((void *)dbc);
  65. result = TCL_OK;
  66. if (objc <= 1) {
  67. Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
  68. return (TCL_ERROR);
  69. }
  70. if (dbc == NULL) {
  71. Tcl_SetResult(interp, "NULL dbc pointer", TCL_STATIC);
  72. return (TCL_ERROR);
  73. }
  74. if (dbip == NULL) {
  75. Tcl_SetResult(interp, "NULL dbc info pointer", TCL_STATIC);
  76. return (TCL_ERROR);
  77. }
  78. /*
  79.  * Get the command name index from the object based on the berkdbcmds
  80.  * defined above.
  81.  */
  82. if (Tcl_GetIndexFromObj(interp, objv[1], dbccmds, "command",
  83.     TCL_EXACT, &cmdindex) != TCL_OK)
  84. return (IS_HELP(objv[1]));
  85. switch ((enum dbccmds)cmdindex) {
  86. #if CONFIG_TEST
  87. case DBCPGET:
  88. result = tcl_DbcGet(interp, objc, objv, dbc, 1);
  89. break;
  90. #endif
  91. case DBCCLOSE:
  92. /*
  93.  * No args for this.  Error if there are some.
  94.  */
  95. if (objc > 2) {
  96. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  97. return (TCL_ERROR);
  98. }
  99. _debug_check();
  100. ret = dbc->c_close(dbc);
  101. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  102.     "dbc close");
  103. if (result == TCL_OK) {
  104. (void)Tcl_DeleteCommand(interp, dbip->i_name);
  105. _DeleteInfo(dbip);
  106. }
  107. break;
  108. case DBCDELETE:
  109. /*
  110.  * No args for this.  Error if there are some.
  111.  */
  112. if (objc > 2) {
  113. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  114. return (TCL_ERROR);
  115. }
  116. _debug_check();
  117. ret = dbc->c_del(dbc, 0);
  118. result = _ReturnSetup(interp, ret, DB_RETOK_DBCDEL(ret),
  119.     "dbc delete");
  120. break;
  121. case DBCDUP:
  122. result = tcl_DbcDup(interp, objc, objv, dbc);
  123. break;
  124. case DBCGET:
  125. result = tcl_DbcGet(interp, objc, objv, dbc, 0);
  126. break;
  127. case DBCPUT:
  128. result = tcl_DbcPut(interp, objc, objv, dbc);
  129. break;
  130. }
  131. return (result);
  132. }
  133. /*
  134.  * tcl_DbcPut --
  135.  */
  136. static int
  137. tcl_DbcPut(interp, objc, objv, dbc)
  138. Tcl_Interp *interp; /* Interpreter */
  139. int objc; /* How many arguments? */
  140. Tcl_Obj *CONST objv[]; /* The argument objects */
  141. DBC *dbc; /* Cursor pointer */
  142. {
  143. static char *dbcutopts[] = {
  144. #if CONFIG_TEST
  145. "-nodupdata",
  146. #endif
  147. "-after",
  148. "-before",
  149. "-current",
  150. "-keyfirst",
  151. "-keylast",
  152. "-partial",
  153. NULL
  154. };
  155. enum dbcutopts {
  156. #if CONFIG_TEST
  157. DBCPUT_NODUPDATA,
  158. #endif
  159. DBCPUT_AFTER,
  160. DBCPUT_BEFORE,
  161. DBCPUT_CURRENT,
  162. DBCPUT_KEYFIRST,
  163. DBCPUT_KEYLAST,
  164. DBCPUT_PART
  165. };
  166. DB *thisdbp;
  167. DBT key, data;
  168. DBTCL_INFO *dbcip, *dbip;
  169. DBTYPE type;
  170. Tcl_Obj **elemv, *res;
  171. void *dtmp, *ktmp;
  172. db_recno_t recno;
  173. u_int32_t flag;
  174. int elemc, freekey, freedata, i, optindex, result, ret;
  175. result = TCL_OK;
  176. flag = 0;
  177. freekey = freedata = 0;
  178. if (objc < 2) {
  179. Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?");
  180. return (TCL_ERROR);
  181. }
  182. memset(&key, 0, sizeof(key));
  183. memset(&data, 0, sizeof(data));
  184. /*
  185.  * Get the command name index from the object based on the options
  186.  * defined above.
  187.  */
  188. i = 2;
  189. while (i < (objc - 1)) {
  190. if (Tcl_GetIndexFromObj(interp, objv[i], dbcutopts, "option",
  191.     TCL_EXACT, &optindex) != TCL_OK) {
  192. /*
  193.  * Reset the result so we don't get
  194.  * an errant error message if there is another error.
  195.  */
  196. if (IS_HELP(objv[i]) == TCL_OK) {
  197. result = TCL_OK;
  198. goto out;
  199. }
  200. Tcl_ResetResult(interp);
  201. break;
  202. }
  203. i++;
  204. switch ((enum dbcutopts)optindex) {
  205. #if CONFIG_TEST
  206. case DBCPUT_NODUPDATA:
  207. FLAG_CHECK(flag);
  208. flag = DB_NODUPDATA;
  209. break;
  210. #endif
  211. case DBCPUT_AFTER:
  212. FLAG_CHECK(flag);
  213. flag = DB_AFTER;
  214. break;
  215. case DBCPUT_BEFORE:
  216. FLAG_CHECK(flag);
  217. flag = DB_BEFORE;
  218. break;
  219. case DBCPUT_CURRENT:
  220. FLAG_CHECK(flag);
  221. flag = DB_CURRENT;
  222. break;
  223. case DBCPUT_KEYFIRST:
  224. FLAG_CHECK(flag);
  225. flag = DB_KEYFIRST;
  226. break;
  227. case DBCPUT_KEYLAST:
  228. FLAG_CHECK(flag);
  229. flag = DB_KEYLAST;
  230. break;
  231. case DBCPUT_PART:
  232. if (i > (objc - 2)) {
  233. Tcl_WrongNumArgs(interp, 2, objv,
  234.     "?-partial {offset length}?");
  235. result = TCL_ERROR;
  236. break;
  237. }
  238. /*
  239.  * Get sublist as {offset length}
  240.  */
  241. result = Tcl_ListObjGetElements(interp, objv[i++],
  242.     &elemc, &elemv);
  243. if (elemc != 2) {
  244. Tcl_SetResult(interp,
  245.     "List must be {offset length}", TCL_STATIC);
  246. result = TCL_ERROR;
  247. break;
  248. }
  249. data.flags |= DB_DBT_PARTIAL;
  250. result = _GetUInt32(interp, elemv[0], &data.doff);
  251. if (result != TCL_OK)
  252. break;
  253. result = _GetUInt32(interp, elemv[1], &data.dlen);
  254. /*
  255.  * NOTE: We don't check result here because all we'd
  256.  * do is break anyway, and we are doing that.  If you
  257.  * add code here, you WILL need to add the check
  258.  * for result.  (See the check for save.doff, a few
  259.  * lines above and copy that.)
  260.  */
  261. }
  262. if (result != TCL_OK)
  263. break;
  264. }
  265. if (result != TCL_OK)
  266. goto out;
  267. /*
  268.  * We need to determine if we are a recno database or not.  If we are,
  269.  * then key.data is a recno, not a string.
  270.  */
  271. dbcip = _PtrToInfo(dbc);
  272. if (dbcip == NULL)
  273. type = DB_UNKNOWN;
  274. else {
  275. dbip = dbcip->i_parent;
  276. if (dbip == NULL) {
  277. Tcl_SetResult(interp, "Cursor without parent database",
  278.     TCL_STATIC);
  279. result = TCL_ERROR;
  280. return (result);
  281. }
  282. thisdbp = dbip->i_dbp;
  283. (void)thisdbp->get_type(thisdbp, &type);
  284. }
  285. /*
  286.  * When we get here, we better have:
  287.  * 1 arg if -after, -before or -current
  288.  * 2 args in all other cases
  289.  */
  290. if (flag == DB_AFTER || flag == DB_BEFORE || flag == DB_CURRENT) {
  291. if (i != (objc - 1)) {
  292. Tcl_WrongNumArgs(interp, 2, objv,
  293.     "?-args? data");
  294. result = TCL_ERROR;
  295. goto out;
  296. }
  297. /*
  298.  * We want to get the key back, so we need to set
  299.  * up the location to get it back in.
  300.  */
  301. if (type == DB_RECNO || type == DB_QUEUE) {
  302. recno = 0;
  303. key.data = &recno;
  304. key.size = sizeof(db_recno_t);
  305. }
  306. } else {
  307. if (i != (objc - 2)) {
  308. Tcl_WrongNumArgs(interp, 2, objv,
  309.     "?-args? key data");
  310. result = TCL_ERROR;
  311. goto out;
  312. }
  313. if (type == DB_RECNO || type == DB_QUEUE) {
  314. result = _GetUInt32(interp, objv[objc-2], &recno);
  315. if (result == TCL_OK) {
  316. key.data = &recno;
  317. key.size = sizeof(db_recno_t);
  318. } else
  319. return (result);
  320. } else {
  321. ret = _CopyObjBytes(interp, objv[objc-2], &ktmp,
  322.     &key.size, &freekey);
  323. if (ret != 0) {
  324. result = _ReturnSetup(interp, ret,
  325.     DB_RETOK_DBCPUT(ret), "dbc put");
  326. return (result);
  327. }
  328. key.data = ktmp;
  329. }
  330. }
  331. ret = _CopyObjBytes(interp, objv[objc-1], &dtmp,
  332.     &data.size, &freedata);
  333. data.data = dtmp;
  334. if (ret != 0) {
  335. result = _ReturnSetup(interp, ret,
  336.     DB_RETOK_DBCPUT(ret), "dbc put");
  337. goto out;
  338. }
  339. _debug_check();
  340. ret = dbc->c_put(dbc, &key, &data, flag);
  341. result = _ReturnSetup(interp, ret, DB_RETOK_DBCPUT(ret),
  342.     "dbc put");
  343. if (ret == 0 &&
  344.     (flag == DB_AFTER || flag == DB_BEFORE) && type == DB_RECNO) {
  345. res = Tcl_NewLongObj((long)*(db_recno_t *)key.data);
  346. Tcl_SetObjResult(interp, res);
  347. }
  348. out:
  349. if (freedata)
  350. (void)__os_free(NULL, dtmp);
  351. if (freekey)
  352. (void)__os_free(NULL, ktmp);
  353. return (result);
  354. }
  355. /*
  356.  * tcl_dbc_get --
  357.  */
  358. static int
  359. tcl_DbcGet(interp, objc, objv, dbc, ispget)
  360. Tcl_Interp *interp; /* Interpreter */
  361. int objc; /* How many arguments? */
  362. Tcl_Obj *CONST objv[]; /* The argument objects */
  363. DBC *dbc; /* Cursor pointer */
  364. int ispget; /* 1 for pget, 0 for get */
  365. {
  366. static char *dbcgetopts[] = {
  367. #if CONFIG_TEST
  368. "-dirty",
  369. "-get_both_range",
  370. "-multi",
  371. "-multi_key",
  372. #endif
  373. "-current",
  374. "-first",
  375. "-get_both",
  376. "-get_recno",
  377. "-join_item",
  378. "-last",
  379. "-next",
  380. "-nextdup",
  381. "-nextnodup",
  382. "-partial",
  383. "-prev",
  384. "-prevnodup",
  385. "-rmw",
  386. "-set",
  387. "-set_range",
  388. "-set_recno",
  389. NULL
  390. };
  391. enum dbcgetopts {
  392. #if CONFIG_TEST
  393. DBCGET_DIRTY,
  394. DBCGET_BOTH_RANGE,
  395. DBCGET_MULTI,
  396. DBCGET_MULTI_KEY,
  397. #endif
  398. DBCGET_CURRENT,
  399. DBCGET_FIRST,
  400. DBCGET_BOTH,
  401. DBCGET_RECNO,
  402. DBCGET_JOIN,
  403. DBCGET_LAST,
  404. DBCGET_NEXT,
  405. DBCGET_NEXTDUP,
  406. DBCGET_NEXTNODUP,
  407. DBCGET_PART,
  408. DBCGET_PREV,
  409. DBCGET_PREVNODUP,
  410. DBCGET_RMW,
  411. DBCGET_SET,
  412. DBCGET_SETRANGE,
  413. DBCGET_SETRECNO
  414. };
  415. DB *thisdbp;
  416. DBT key, data, pdata;
  417. DBTCL_INFO *dbcip, *dbip;
  418. DBTYPE ptype, type;
  419. Tcl_Obj **elemv, *myobj, *retlist;
  420. void *dtmp, *ktmp;
  421. db_recno_t precno, recno;
  422. u_int32_t flag, op;
  423. int bufsize, elemc, freekey, freedata, i, optindex, result, ret;
  424. result = TCL_OK;
  425. flag = 0;
  426. freekey = freedata = 0;
  427. if (objc < 2) {
  428. Tcl_WrongNumArgs(interp, 2, objv, "?-args? ?key?");
  429. return (TCL_ERROR);
  430. }
  431. memset(&key, 0, sizeof(key));
  432. memset(&data, 0, sizeof(data));
  433. /*
  434.  * Get the command name index from the object based on the options
  435.  * defined above.
  436.  */
  437. i = 2;
  438. while (i < objc) {
  439. if (Tcl_GetIndexFromObj(interp, objv[i], dbcgetopts,
  440.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  441. /*
  442.  * Reset the result so we don't get
  443.  * an errant error message if there is another error.
  444.  */
  445. if (IS_HELP(objv[i]) == TCL_OK) {
  446. result = TCL_OK;
  447. goto out;
  448. }
  449. Tcl_ResetResult(interp);
  450. break;
  451. }
  452. i++;
  453. switch ((enum dbcgetopts)optindex) {
  454. #if CONFIG_TEST
  455. case DBCGET_DIRTY:
  456. flag |= DB_DIRTY_READ;
  457. break;
  458. case DBCGET_BOTH_RANGE:
  459. FLAG_CHECK2(flag,
  460.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  461. flag |= DB_GET_BOTH_RANGE;
  462. break;
  463. case DBCGET_MULTI:
  464. flag |= DB_MULTIPLE;
  465. result = Tcl_GetIntFromObj(interp, objv[i], &bufsize);
  466. if (result != TCL_OK)
  467. goto out;
  468. i++;
  469. break;
  470. case DBCGET_MULTI_KEY:
  471. flag |= DB_MULTIPLE_KEY;
  472. result = Tcl_GetIntFromObj(interp, objv[i], &bufsize);
  473. if (result != TCL_OK)
  474. goto out;
  475. i++;
  476. break;
  477. #endif
  478. case DBCGET_RMW:
  479. flag |= DB_RMW;
  480. break;
  481. case DBCGET_CURRENT:
  482. FLAG_CHECK2(flag,
  483.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  484. flag |= DB_CURRENT;
  485. break;
  486. case DBCGET_FIRST:
  487. FLAG_CHECK2(flag,
  488.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  489. flag |= DB_FIRST;
  490. break;
  491. case DBCGET_LAST:
  492. FLAG_CHECK2(flag,
  493.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  494. flag |= DB_LAST;
  495. break;
  496. case DBCGET_NEXT:
  497. FLAG_CHECK2(flag,
  498.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  499. flag |= DB_NEXT;
  500. break;
  501. case DBCGET_PREV:
  502. FLAG_CHECK2(flag,
  503.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  504. flag |= DB_PREV;
  505. break;
  506. case DBCGET_PREVNODUP:
  507. FLAG_CHECK2(flag,
  508.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  509. flag |= DB_PREV_NODUP;
  510. break;
  511. case DBCGET_NEXTNODUP:
  512. FLAG_CHECK2(flag,
  513.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  514. flag |= DB_NEXT_NODUP;
  515. break;
  516. case DBCGET_NEXTDUP:
  517. FLAG_CHECK2(flag,
  518.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  519. flag |= DB_NEXT_DUP;
  520. break;
  521. case DBCGET_BOTH:
  522. FLAG_CHECK2(flag,
  523.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  524. flag |= DB_GET_BOTH;
  525. break;
  526. case DBCGET_RECNO:
  527. FLAG_CHECK2(flag,
  528.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  529. flag |= DB_GET_RECNO;
  530. break;
  531. case DBCGET_JOIN:
  532. FLAG_CHECK2(flag,
  533.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  534. flag |= DB_JOIN_ITEM;
  535. break;
  536. case DBCGET_SET:
  537. FLAG_CHECK2(flag,
  538.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  539. flag |= DB_SET;
  540. break;
  541. case DBCGET_SETRANGE:
  542. FLAG_CHECK2(flag,
  543.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  544. flag |= DB_SET_RANGE;
  545. break;
  546. case DBCGET_SETRECNO:
  547. FLAG_CHECK2(flag,
  548.     DB_RMW|DB_MULTIPLE|DB_MULTIPLE_KEY|DB_DIRTY_READ);
  549. flag |= DB_SET_RECNO;
  550. break;
  551. case DBCGET_PART:
  552. if (i == objc) {
  553. Tcl_WrongNumArgs(interp, 2, objv,
  554.     "?-partial {offset length}?");
  555. result = TCL_ERROR;
  556. break;
  557. }
  558. /*
  559.  * Get sublist as {offset length}
  560.  */
  561. result = Tcl_ListObjGetElements(interp, objv[i++],
  562.     &elemc, &elemv);
  563. if (elemc != 2) {
  564. Tcl_SetResult(interp,
  565.     "List must be {offset length}", TCL_STATIC);
  566. result = TCL_ERROR;
  567. break;
  568. }
  569. data.flags |= DB_DBT_PARTIAL;
  570. result = _GetUInt32(interp, elemv[0], &data.doff);
  571. if (result != TCL_OK)
  572. break;
  573. result = _GetUInt32(interp, elemv[1], &data.dlen);
  574. /*
  575.  * NOTE: We don't check result here because all we'd
  576.  * do is break anyway, and we are doing that.  If you
  577.  * add code here, you WILL need to add the check
  578.  * for result.  (See the check for save.doff, a few
  579.  * lines above and copy that.)
  580.  */
  581. break;
  582. }
  583. if (result != TCL_OK)
  584. break;
  585. }
  586. if (result != TCL_OK)
  587. goto out;
  588. /*
  589.  * We need to determine if we are a recno database
  590.  * or not.  If we are, then key.data is a recno, not
  591.  * a string.
  592.  */
  593. dbcip = _PtrToInfo(dbc);
  594. if (dbcip == NULL) {
  595. type = DB_UNKNOWN;
  596. ptype = DB_UNKNOWN;
  597. } else {
  598. dbip = dbcip->i_parent;
  599. if (dbip == NULL) {
  600. Tcl_SetResult(interp, "Cursor without parent database",
  601.     TCL_STATIC);
  602. result = TCL_ERROR;
  603. goto out;
  604. }
  605. thisdbp = dbip->i_dbp;
  606. (void)thisdbp->get_type(thisdbp, &type);
  607. if (ispget && thisdbp->s_primary != NULL)
  608. (void)thisdbp->
  609.     s_primary->get_type(thisdbp->s_primary, &ptype);
  610. else
  611. ptype = DB_UNKNOWN;
  612. }
  613. /*
  614.  * When we get here, we better have:
  615.  * 2 args, key and data if GET_BOTH/GET_BOTH_RANGE was specified.
  616.  * 1 arg if -set, -set_range or -set_recno
  617.  * 0 in all other cases.
  618.  */
  619. op = flag & DB_OPFLAGS_MASK;
  620. switch (op) {
  621. case DB_GET_BOTH:
  622. #if CONFIG_TEST
  623. case DB_GET_BOTH_RANGE:
  624. #endif
  625. if (i != (objc - 2)) {
  626. Tcl_WrongNumArgs(interp, 2, objv,
  627.     "?-args? -get_both key data");
  628. result = TCL_ERROR;
  629. goto out;
  630. } else {
  631. if (type == DB_RECNO || type == DB_QUEUE) {
  632. result = _GetUInt32(
  633.     interp, objv[objc-2], &recno);
  634. if (result == TCL_OK) {
  635. key.data = &recno;
  636. key.size = sizeof(db_recno_t);
  637. } else
  638. goto out;
  639. } else {
  640. /*
  641.  * Some get calls (SET_*) can change the
  642.  * key pointers.  So, we need to store
  643.  * the allocated key space in a tmp.
  644.  */
  645. ret = _CopyObjBytes(interp, objv[objc-2],
  646.     &ktmp, &key.size, &freekey);
  647. if (ret != 0) {
  648. result = _ReturnSetup(interp, ret,
  649.     DB_RETOK_DBCGET(ret), "dbc get");
  650. return (result);
  651. }
  652. key.data = ktmp;
  653. }
  654. if (ptype == DB_RECNO || ptype == DB_QUEUE) {
  655. result = _GetUInt32(
  656.     interp, objv[objc-1], &precno);
  657. if (result == TCL_OK) {
  658. data.data = &precno;
  659. data.size = sizeof(db_recno_t);
  660. } else
  661. goto out;
  662. } else {
  663. ret = _CopyObjBytes(interp, objv[objc-1],
  664.     &dtmp, &data.size, &freedata);
  665. if (ret != 0) {
  666. result = _ReturnSetup(interp, ret,
  667.     DB_RETOK_DBCGET(ret), "dbc get");
  668. goto out;
  669. }
  670. data.data = dtmp;
  671. }
  672. }
  673. break;
  674. case DB_SET:
  675. case DB_SET_RANGE:
  676. case DB_SET_RECNO:
  677. if (i != (objc - 1)) {
  678. Tcl_WrongNumArgs(interp, 2, objv, "?-args? key");
  679. result = TCL_ERROR;
  680. goto out;
  681. }
  682. if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY)) {
  683. (void)__os_malloc(NULL, bufsize, &data.data);
  684. data.ulen = bufsize;
  685. data.flags |= DB_DBT_USERMEM;
  686. } else
  687. data.flags |= DB_DBT_MALLOC;
  688. if (op == DB_SET_RECNO ||
  689.     type == DB_RECNO || type == DB_QUEUE) {
  690. result = _GetUInt32(interp, objv[objc - 1], &recno);
  691. key.data = &recno;
  692. key.size = sizeof(db_recno_t);
  693. } else {
  694. /*
  695.  * Some get calls (SET_*) can change the
  696.  * key pointers.  So, we need to store
  697.  * the allocated key space in a tmp.
  698.  */
  699. ret = _CopyObjBytes(interp, objv[objc-1],
  700.     &ktmp, &key.size, &freekey);
  701. if (ret != 0) {
  702. result = _ReturnSetup(interp, ret,
  703.     DB_RETOK_DBCGET(ret), "dbc get");
  704. return (result);
  705. }
  706. key.data = ktmp;
  707. }
  708. break;
  709. default:
  710. if (i != objc) {
  711. Tcl_WrongNumArgs(interp, 2, objv, "?-args?");
  712. result = TCL_ERROR;
  713. goto out;
  714. }
  715. key.flags |= DB_DBT_MALLOC;
  716. if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY)) {
  717. (void)__os_malloc(NULL, bufsize, &data.data);
  718. data.ulen = bufsize;
  719. data.flags |= DB_DBT_USERMEM;
  720. } else
  721. data.flags |= DB_DBT_MALLOC;
  722. }
  723. _debug_check();
  724. memset(&pdata, 0, sizeof(DBT));
  725. if (ispget) {
  726. F_SET(&pdata, DB_DBT_MALLOC);
  727. ret = dbc->c_pget(dbc, &key, &data, &pdata, flag);
  728. } else
  729. ret = dbc->c_get(dbc, &key, &data, flag);
  730. result = _ReturnSetup(interp, ret, DB_RETOK_DBCGET(ret), "dbc get");
  731. if (result == TCL_ERROR)
  732. goto out;
  733. retlist = Tcl_NewListObj(0, NULL);
  734. if (ret == DB_NOTFOUND)
  735. goto out1;
  736. if (op == DB_GET_RECNO) {
  737. recno = *((db_recno_t *)data.data);
  738. myobj = Tcl_NewLongObj((long)recno);
  739. result = Tcl_ListObjAppendElement(interp, retlist, myobj);
  740. } else {
  741. if (flag & (DB_MULTIPLE|DB_MULTIPLE_KEY))
  742. result = _SetMultiList(interp,
  743.     retlist, &key, &data, type, flag);
  744. else if ((type == DB_RECNO || type == DB_QUEUE) &&
  745.     key.data != NULL) {
  746. if (ispget)
  747. result = _Set3DBTList(interp, retlist, &key, 1,
  748.     &data,
  749.     (ptype == DB_RECNO || ptype == DB_QUEUE),
  750.     &pdata);
  751. else
  752. result = _SetListRecnoElem(interp, retlist,
  753.     *(db_recno_t *)key.data,
  754.     data.data, data.size);
  755. } else {
  756. if (ispget)
  757. result = _Set3DBTList(interp, retlist, &key, 0,
  758.     &data,
  759.     (ptype == DB_RECNO || ptype == DB_QUEUE),
  760.     &pdata);
  761. else
  762. result = _SetListElem(interp, retlist,
  763.     key.data, key.size, data.data, data.size);
  764. }
  765. }
  766. if (key.data != NULL && F_ISSET(&key, DB_DBT_MALLOC))
  767. __os_ufree(dbc->dbp->dbenv, key.data);
  768. if (data.data != NULL && F_ISSET(&data, DB_DBT_MALLOC))
  769. __os_ufree(dbc->dbp->dbenv, data.data);
  770. if (pdata.data != NULL && F_ISSET(&pdata, DB_DBT_MALLOC))
  771. __os_ufree(dbc->dbp->dbenv, pdata.data);
  772. out1:
  773. if (result == TCL_OK)
  774. Tcl_SetObjResult(interp, retlist);
  775. out:
  776. if (data.data != NULL && flag & (DB_MULTIPLE|DB_MULTIPLE_KEY))
  777. __os_free(dbc->dbp->dbenv, data.data);
  778. if (freedata)
  779. (void)__os_free(NULL, dtmp);
  780. if (freekey)
  781. (void)__os_free(NULL, ktmp);
  782. return (result);
  783. }
  784. /*
  785.  * tcl_DbcDup --
  786.  */
  787. static int
  788. tcl_DbcDup(interp, objc, objv, dbc)
  789. Tcl_Interp *interp; /* Interpreter */
  790. int objc; /* How many arguments? */
  791. Tcl_Obj *CONST objv[]; /* The argument objects */
  792. DBC *dbc; /* Cursor pointer */
  793. {
  794. static char *dbcdupopts[] = {
  795. "-position",
  796. NULL
  797. };
  798. enum dbcdupopts {
  799. DBCDUP_POS
  800. };
  801. DBC *newdbc;
  802. DBTCL_INFO *dbcip, *newdbcip, *dbip;
  803. Tcl_Obj *res;
  804. u_int32_t flag;
  805. int i, optindex, result, ret;
  806. char newname[MSG_SIZE];
  807. result = TCL_OK;
  808. flag = 0;
  809. res = NULL;
  810. if (objc < 2) {
  811. Tcl_WrongNumArgs(interp, 2, objv, "?-args?");
  812. return (TCL_ERROR);
  813. }
  814. /*
  815.  * Get the command name index from the object based on the options
  816.  * defined above.
  817.  */
  818. i = 2;
  819. while (i < objc) {
  820. if (Tcl_GetIndexFromObj(interp, objv[i], dbcdupopts,
  821.     "option", TCL_EXACT, &optindex) != TCL_OK) {
  822. /*
  823.  * Reset the result so we don't get
  824.  * an errant error message if there is another error.
  825.  */
  826. if (IS_HELP(objv[i]) == TCL_OK) {
  827. result = TCL_OK;
  828. goto out;
  829. }
  830. Tcl_ResetResult(interp);
  831. break;
  832. }
  833. i++;
  834. switch ((enum dbcdupopts)optindex) {
  835. case DBCDUP_POS:
  836. flag = DB_POSITION;
  837. break;
  838. }
  839. if (result != TCL_OK)
  840. break;
  841. }
  842. if (result != TCL_OK)
  843. goto out;
  844. /*
  845.  * We need to determine if we are a recno database
  846.  * or not.  If we are, then key.data is a recno, not
  847.  * a string.
  848.  */
  849. dbcip = _PtrToInfo(dbc);
  850. if (dbcip == NULL) {
  851. Tcl_SetResult(interp, "Cursor without info structure",
  852.     TCL_STATIC);
  853. result = TCL_ERROR;
  854. goto out;
  855. } else {
  856. dbip = dbcip->i_parent;
  857. if (dbip == NULL) {
  858. Tcl_SetResult(interp, "Cursor without parent database",
  859.     TCL_STATIC);
  860. result = TCL_ERROR;
  861. goto out;
  862. }
  863. }
  864. /*
  865.  * Now duplicate the cursor.  If successful, we need to create
  866.  * a new cursor command.
  867.  */
  868. snprintf(newname, sizeof(newname),
  869.     "%s.c%d", dbip->i_name, dbip->i_dbdbcid);
  870. newdbcip = _NewInfo(interp, NULL, newname, I_DBC);
  871. if (newdbcip != NULL) {
  872. ret = dbc->c_dup(dbc, &newdbc, flag);
  873. if (ret == 0) {
  874. dbip->i_dbdbcid++;
  875. newdbcip->i_parent = dbip;
  876. Tcl_CreateObjCommand(interp, newname,
  877.     (Tcl_ObjCmdProc *)dbc_Cmd,
  878.     (ClientData)newdbc, NULL);
  879. res = Tcl_NewStringObj(newname, strlen(newname));
  880. _SetInfoData(newdbcip, newdbc);
  881. Tcl_SetObjResult(interp, res);
  882. } else {
  883. result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
  884.     "db dup");
  885. _DeleteInfo(newdbcip);
  886. }
  887. } else {
  888. Tcl_SetResult(interp, "Could not set up info", TCL_STATIC);
  889. result = TCL_ERROR;
  890. }
  891. out:
  892. return (result);
  893. }