00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: db__iface_8c-source.html,v 1.1 2008年06月08日 10:17:40 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 00017 #include <errno.h> 00018 #endif 00019 00020 #include "db_int.h" 00021 #include "db_page.h" 00022 #include "db_am.h" 00023 #include "btree.h" 00024 00025 static int __db_curinval __P((const DB_ENV *)); 00026 static int __db_rdonly __P((const DB_ENV *, const char *)); 00027 static int __dbt_ferr __P((const DB *, const char *, const DBT *, int)); 00028 00029 /* 00030 * CDB___db_cursorchk -- 00031 * Common cursor argument checking routine. 00032 * 00033 * PUBLIC: int CDB___db_cursorchk __P((const DB *, u_int32_t, int)); 00034 */ 00035 int 00036 CDB___db_cursorchk(dbp, flags, isrdonly) 00037 const DB *dbp; 00038 u_int32_t flags; 00039 int isrdonly; 00040 { 00041 /* Check for invalid function flags. */ 00042 switch (flags) { 00043 case 0: 00044 break; 00045 case DB_WRITECURSOR: 00046 if (isrdonly) 00047 return (__db_rdonly(dbp->dbenv, "DB->cursor")); 00048 if (!LOCKING(dbp->dbenv)) 00049 return (CDB___db_ferr(dbp->dbenv, "DB->cursor", 0)); 00050 break; 00051 case DB_WRITELOCK: 00052 if (isrdonly) 00053 return (__db_rdonly(dbp->dbenv, "DB->cursor")); 00054 break; 00055 default: 00056 return (CDB___db_ferr(dbp->dbenv, "DB->cursor", 0)); 00057 } 00058 00059 return (0); 00060 } 00061 00062 /* 00063 * CDB___db_ccountchk -- 00064 * Common cursor count argument checking routine. 00065 * 00066 * PUBLIC: int CDB___db_ccountchk __P((const DB *, u_int32_t, int)); 00067 */ 00068 int 00069 CDB___db_ccountchk(dbp, flags, isvalid) 00070 const DB *dbp; 00071 u_int32_t flags; 00072 int isvalid; 00073 { 00074 /* Check for invalid function flags. */ 00075 switch (flags) { 00076 case 0: 00077 break; 00078 default: 00079 return (CDB___db_ferr(dbp->dbenv, "DBcursor->c_count", 0)); 00080 } 00081 00082 /* 00083 * The cursor must be initialized, return EINVAL for an invalid cursor, 00084 * otherwise 0. 00085 */ 00086 return (isvalid ? 0 : __db_curinval(dbp->dbenv)); 00087 } 00088 00089 /* 00090 * CDB___db_cdelchk -- 00091 * Common cursor delete argument checking routine. 00092 * 00093 * PUBLIC: int CDB___db_cdelchk __P((const DB *, u_int32_t, int, int)); 00094 */ 00095 int 00096 CDB___db_cdelchk(dbp, flags, isrdonly, isvalid) 00097 const DB *dbp; 00098 u_int32_t flags; 00099 int isrdonly, isvalid; 00100 { 00101 /* Check for changes to a read-only tree. */ 00102 if (isrdonly) 00103 return (__db_rdonly(dbp->dbenv, "c_del")); 00104 00105 /* Check for invalid function flags. */ 00106 switch (flags) { 00107 case 0: 00108 break; 00109 default: 00110 return (CDB___db_ferr(dbp->dbenv, "DBcursor->c_del", 0)); 00111 } 00112 00113 /* 00114 * The cursor must be initialized, return EINVAL for an invalid cursor, 00115 * otherwise 0. 00116 */ 00117 return (isvalid ? 0 : __db_curinval(dbp->dbenv)); 00118 } 00119 00120 /* 00121 * CDB___db_cgetchk -- 00122 * Common cursor get argument checking routine. 00123 * 00124 * PUBLIC: int CDB___db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int)); 00125 */ 00126 int 00127 CDB___db_cgetchk(dbp, key, data, flags, isvalid) 00128 const DB *dbp; 00129 DBT *key, *data; 00130 u_int32_t flags; 00131 int isvalid; 00132 { 00133 int key_einval, ret; 00134 00135 key_einval = 0; 00136 00137 /* 00138 * Check for read-modify-write validity. DB_RMW doesn't make sense 00139 * with CDB cursors since if you're going to write the cursor, you 00140 * had to create it with DB_WRITECURSOR. Regardless, we check for 00141 * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. 00142 * If this changes, confirm that DB does not itself set the DB_RMW 00143 * flag in a path where CDB may have been configured. 00144 */ 00145 if (LF_ISSET(DB_RMW)) { 00146 if (!LOCKING_ON(dbp->dbenv)) { 00147 CDB___db_err(dbp->dbenv, 00148 "the DB_RMW flag requires locking"); 00149 return (EINVAL); 00150 } 00151 LF_CLR(DB_RMW); 00152 } 00153 00154 /* Check for invalid function flags. */ 00155 switch (flags) { 00156 case DB_CONSUME: 00157 if (dbp->type != DB_QUEUE) 00158 goto err; 00159 break; 00160 case DB_CURRENT: 00161 case DB_FIRST: 00162 case DB_LAST: 00163 case DB_NEXT: 00164 case DB_NEXT_DUP: 00165 case DB_NEXT_NODUP: 00166 case DB_PREV: 00167 case DB_PREV_NODUP: 00168 break; 00169 case DB_GET_BOTHC: 00170 if (dbp->type == DB_QUEUE) 00171 goto err; 00172 /* FALLTHROUGH */ 00173 case DB_GET_BOTH: 00174 case DB_SET: 00175 case DB_SET_RANGE: 00176 key_einval = 1; 00177 break; 00178 case DB_GET_RECNO: 00179 if (!F_ISSET(dbp, DB_BT_RECNUM)) 00180 goto err; 00181 break; 00182 case DB_SET_RECNO: 00183 if (!F_ISSET(dbp, DB_BT_RECNUM)) 00184 goto err; 00185 key_einval = 1; 00186 break; 00187 default: 00188 err: return (CDB___db_ferr(dbp->dbenv, "DBcursor->c_get", 0)); 00189 } 00190 00191 /* Check for invalid key/data flags. */ 00192 if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 00193 return (ret); 00194 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 00195 return (ret); 00196 00197 /* 00198 * The cursor must be initialized for DB_CURRENT or DB_NEXT_DUP, 00199 * return EINVAL for an invalid cursor, otherwise 0. 00200 */ 00201 if (isvalid || (flags != DB_CURRENT && flags != DB_NEXT_DUP)) 00202 return (0); 00203 00204 return(__db_curinval(dbp->dbenv)); 00205 } 00206 00207 /* 00208 * CDB___db_cputchk -- 00209 * Common cursor put argument checking routine. 00210 * 00211 * PUBLIC: int CDB___db_cputchk __P((const DB *, 00212 * PUBLIC: const DBT *, DBT *, u_int32_t, int, int)); 00213 */ 00214 int 00215 CDB___db_cputchk(dbp, key, data, flags, isrdonly, isvalid) 00216 const DB *dbp; 00217 const DBT *key; 00218 DBT *data; 00219 u_int32_t flags; 00220 int isrdonly, isvalid; 00221 { 00222 int key_einval, key_flags, ret; 00223 00224 key_einval = key_flags = 0; 00225 00226 /* Check for changes to a read-only tree. */ 00227 if (isrdonly) 00228 return (__db_rdonly(dbp->dbenv, "c_put")); 00229 00230 /* Check for invalid function flags. */ 00231 switch (flags) { 00232 case DB_AFTER: 00233 case DB_BEFORE: 00234 switch (dbp->type) { 00235 case DB_BTREE: 00236 case DB_HASH: /* Only with unsorted duplicates. */ 00237 if (!F_ISSET(dbp, DB_AM_DUP)) 00238 goto err; 00239 if (dbp->dup_compare != NULL) 00240 goto err; 00241 break; 00242 case DB_QUEUE: /* Not permitted. */ 00243 goto err; 00244 case DB_RECNO: /* Only with mutable record numbers. */ 00245 if (!F_ISSET(dbp, DB_RE_RENUMBER)) 00246 goto err; 00247 key_flags = 1; 00248 break; 00249 default: 00250 goto err; 00251 } 00252 break; 00253 case DB_CURRENT: 00254 /* 00255 * If there is a comparison function, doing a DB_CURRENT 00256 * must not change the part of the data item that is used 00257 * for the comparison. 00258 */ 00259 break; 00260 case DB_NODUPDATA: 00261 if (!F_ISSET(dbp, DB_AM_DUPSORT)) 00262 goto err; 00263 /* FALLTHROUGH */ 00264 case DB_KEYFIRST: 00265 case DB_KEYLAST: 00266 if (dbp->type == DB_QUEUE || dbp->type == DB_RECNO) 00267 goto err; 00268 key_einval = key_flags = 1; 00269 break; 00270 default: 00271 err: return (CDB___db_ferr(dbp->dbenv, "DBcursor->c_put", 0)); 00272 } 00273 00274 /* Check for invalid key/data flags. */ 00275 if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 00276 return (ret); 00277 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 00278 return (ret); 00279 00280 /* 00281 * The cursor must be initialized for anything other than DB_KEYFIRST 00282 * and DB_KEYLAST, return EINVAL for an invalid cursor, otherwise 0. 00283 */ 00284 if (isvalid || flags == DB_KEYFIRST || 00285 flags == DB_KEYLAST || flags == DB_NODUPDATA) 00286 return (0); 00287 00288 return (__db_curinval(dbp->dbenv)); 00289 } 00290 00291 /* 00292 * CDB___db_closechk -- 00293 * DB->close flag check. 00294 * 00295 * PUBLIC: int CDB___db_closechk __P((const DB *, u_int32_t)); 00296 */ 00297 int 00298 CDB___db_closechk(dbp, flags) 00299 const DB *dbp; 00300 u_int32_t flags; 00301 { 00302 /* Check for invalid function flags. */ 00303 switch (flags) { 00304 case 0: 00305 case DB_NOSYNC: 00306 break; 00307 default: 00308 return (CDB___db_ferr(dbp->dbenv, "DB->close", 0)); 00309 } 00310 00311 return (0); 00312 } 00313 00314 /* 00315 * CDB___db_delchk -- 00316 * Common delete argument checking routine. 00317 * 00318 * PUBLIC: int CDB___db_delchk __P((const DB *, DBT *, u_int32_t, int)); 00319 */ 00320 int 00321 CDB___db_delchk(dbp, key, flags, isrdonly) 00322 const DB *dbp; 00323 DBT *key; 00324 u_int32_t flags; 00325 int isrdonly; 00326 { 00327 COMPQUIET(key, NULL); 00328 00329 /* Check for changes to a read-only tree. */ 00330 if (isrdonly) 00331 return (__db_rdonly(dbp->dbenv, "delete")); 00332 00333 /* Check for invalid function flags. */ 00334 switch (flags) { 00335 case 0: 00336 break; 00337 default: 00338 return (CDB___db_ferr(dbp->dbenv, "DB->del", 0)); 00339 } 00340 00341 return (0); 00342 } 00343 00344 /* 00345 * CDB___db_getchk -- 00346 * Common get argument checking routine. 00347 * 00348 * PUBLIC: int CDB___db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t)); 00349 */ 00350 int 00351 CDB___db_getchk(dbp, key, data, flags) 00352 const DB *dbp; 00353 const DBT *key; 00354 DBT *data; 00355 u_int32_t flags; 00356 { 00357 int ret; 00358 00359 /* 00360 * Check for read-modify-write validity. DB_RMW doesn't make sense 00361 * with CDB cursors since if you're going to write the cursor, you 00362 * had to create it with DB_WRITECURSOR. Regardless, we check for 00363 * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. 00364 * If this changes, confirm that DB does not itself set the DB_RMW 00365 * flag in a path where CDB may have been configured. 00366 */ 00367 if (LF_ISSET(DB_RMW)) { 00368 if (!LOCKING_ON(dbp->dbenv)) { 00369 CDB___db_err(dbp->dbenv, 00370 "the DB_RMW flag requires locking"); 00371 return (EINVAL); 00372 } 00373 LF_CLR(DB_RMW); 00374 } 00375 00376 /* Check for invalid function flags. */ 00377 switch (flags) { 00378 case 0: 00379 case DB_GET_BOTH: 00380 break; 00381 case DB_SET_RECNO: 00382 if (!F_ISSET(dbp, DB_BT_RECNUM)) 00383 goto err; 00384 break; 00385 default: 00386 err: return (CDB___db_ferr(dbp->dbenv, "DB->get", 0)); 00387 } 00388 00389 /* Check for invalid key/data flags. */ 00390 if ((ret = __dbt_ferr(dbp, "key", key, flags == DB_SET_RECNO)) != 0) 00391 return (ret); 00392 if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0) 00393 return (ret); 00394 00395 return (0); 00396 } 00397 00398 /* 00399 * CDB___db_joinchk -- 00400 * Common join argument checking routine. 00401 * 00402 * PUBLIC: int CDB___db_joinchk __P((const DB *, u_int32_t)); 00403 */ 00404 int 00405 CDB___db_joinchk(dbp, flags) 00406 const DB *dbp; 00407 u_int32_t flags; 00408 { 00409 switch (flags) { 00410 case 0: 00411 case DB_JOIN_NOSORT: 00412 break; 00413 default: 00414 return (CDB___db_ferr(dbp->dbenv, "DB->join", 0)); 00415 } 00416 00417 return (0); 00418 } 00419 00420 /* 00421 * CDB___db_joingetchk -- 00422 * Common join_get argument checking routine. 00423 * 00424 * PUBLIC: int CDB___db_joingetchk __P((const DB *, DBT *, u_int32_t)); 00425 */ 00426 int 00427 CDB___db_joingetchk(dbp, key, flags) 00428 const DB *dbp; 00429 DBT *key; 00430 u_int32_t flags; 00431 { 00432 00433 if (LF_ISSET(DB_RMW)) { 00434 if (!LOCKING_ON(dbp->dbenv)) { 00435 CDB___db_err(dbp->dbenv, 00436 "the DB_RMW flag requires locking"); 00437 return (EINVAL); 00438 } 00439 LF_CLR(DB_RMW); 00440 } 00441 00442 switch (flags) { 00443 case 0: 00444 case DB_JOIN_ITEM: 00445 break; 00446 default: 00447 return (CDB___db_ferr(dbp->dbenv, "DBcursor->c_get", 0)); 00448 } 00449 00450 /* 00451 * A partial get of the key of a join cursor don't make much sense; 00452 * the entire key is necessary to query the primary database 00453 * and find the datum, and so regardless of the size of the key 00454 * it would not be a performance improvement. Since it would require 00455 * special handling, we simply disallow it. 00456 * 00457 * A partial get of the data, however, potentially makes sense (if 00458 * all possible data are a predictable large structure, for instance) 00459 * and causes us no headaches, so we permit it. 00460 */ 00461 if (F_ISSET(key, DB_DBT_PARTIAL)) { 00462 CDB___db_err(dbp->dbenv, 00463 "DB_DBT_PARTIAL may not be set on key during join_get"); 00464 return (EINVAL); 00465 } 00466 00467 return (0); 00468 } 00469 00470 /* 00471 * CDB___db_putchk -- 00472 * Common put argument checking routine. 00473 * 00474 * PUBLIC: int CDB___db_putchk 00475 * PUBLIC: __P((const DB *, DBT *, const DBT *, u_int32_t, int, int)); 00476 */ 00477 int 00478 CDB___db_putchk(dbp, key, data, flags, isrdonly, isdup) 00479 const DB *dbp; 00480 DBT *key; 00481 const DBT *data; 00482 u_int32_t flags; 00483 int isrdonly, isdup; 00484 { 00485 int key_einval, key_flags, ret; 00486 00487 key_einval = key_flags = 0; 00488 00489 /* Check for changes to a read-only tree. */ 00490 if (isrdonly) 00491 return (__db_rdonly(dbp->dbenv, "put")); 00492 00493 /* Check for invalid function flags. */ 00494 switch (flags) { 00495 case 0: 00496 case DB_NOOVERWRITE: 00497 key_einval = key_flags = 1; 00498 break; 00499 case DB_APPEND: 00500 if (dbp->type != DB_RECNO && dbp->type != DB_QUEUE) 00501 goto err; 00502 key_flags = 1; 00503 break; 00504 case DB_NODUPDATA: 00505 if (F_ISSET(dbp, DB_AM_DUPSORT)) 00506 break; 00507 /* FALLTHROUGH */ 00508 default: 00509 err: return (CDB___db_ferr(dbp->dbenv, "DB->put", 0)); 00510 } 00511 00512 /* Check for invalid key/data flags. */ 00513 if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 00514 return (ret); 00515 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 00516 return (ret); 00517 00518 /* Check for partial puts in the presence of duplicates. */ 00519 if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) { 00520 CDB___db_err(dbp->dbenv, 00521 "a partial put in the presence of duplicates requires a cursor operation"); 00522 return (EINVAL); 00523 } 00524 00525 return (0); 00526 } 00527 00528 /* 00529 * CDB___db_removechk -- 00530 * DB->remove flag check. 00531 * 00532 * PUBLIC: int CDB___db_removechk __P((const DB *, u_int32_t)); 00533 */ 00534 int 00535 CDB___db_removechk(dbp, flags) 00536 const DB *dbp; 00537 u_int32_t flags; 00538 { 00539 /* Check for invalid function flags. */ 00540 switch (flags) { 00541 case 0: 00542 break; 00543 default: 00544 return (CDB___db_ferr(dbp->dbenv, "DB->remove", 0)); 00545 } 00546 00547 return (0); 00548 } 00549 00550 /* 00551 * CDB___db_statchk -- 00552 * Common stat argument checking routine. 00553 * 00554 * PUBLIC: int CDB___db_statchk __P((const DB *, u_int32_t)); 00555 */ 00556 int 00557 CDB___db_statchk(dbp, flags) 00558 const DB *dbp; 00559 u_int32_t flags; 00560 { 00561 /* Check for invalid function flags. */ 00562 switch (flags) { 00563 case 0: 00564 case DB_CACHED_COUNTS: 00565 break; 00566 case DB_RECORDCOUNT: 00567 if (dbp->type == DB_RECNO) 00568 break; 00569 if (dbp->type == DB_BTREE && F_ISSET(dbp, DB_BT_RECNUM)) 00570 break; 00571 goto err; 00572 default: 00573 err: return (CDB___db_ferr(dbp->dbenv, "DB->stat", 0)); 00574 } 00575 00576 return (0); 00577 } 00578 00579 /* 00580 * CDB___db_syncchk -- 00581 * Common sync argument checking routine. 00582 * 00583 * PUBLIC: int CDB___db_syncchk __P((const DB *, u_int32_t)); 00584 */ 00585 int 00586 CDB___db_syncchk(dbp, flags) 00587 const DB *dbp; 00588 u_int32_t flags; 00589 { 00590 /* Check for invalid function flags. */ 00591 switch (flags) { 00592 case 0: 00593 break; 00594 default: 00595 return (CDB___db_ferr(dbp->dbenv, "DB->sync", 0)); 00596 } 00597 00598 return (0); 00599 } 00600 00601 /* 00602 * __dbt_ferr -- 00603 * Check a DBT for flag errors. 00604 */ 00605 static int 00606 __dbt_ferr(dbp, name, dbt, check_thread) 00607 const DB *dbp; 00608 const char *name; 00609 const DBT *dbt; 00610 int check_thread; 00611 { 00612 DB_ENV *dbenv; 00613 int ret; 00614 00615 dbenv = dbp->dbenv; 00616 00617 /* 00618 * Check for invalid DBT flags. We allow any of the flags to be 00619 * specified to any DB or DBcursor call so that applications can 00620 * set DB_DBT_MALLOC when retrieving a data item from a secondary 00621 * database and then specify that same DBT as a key to a primary 00622 * database, without having to clear flags. 00623 */ 00624 if ((ret = CDB___db_fchk(dbenv, name, dbt->flags, 00625 DB_DBT_MALLOC | DB_DBT_DUPOK | 00626 DB_DBT_REALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0) 00627 return (ret); 00628 switch (F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) { 00629 case 0: 00630 case DB_DBT_MALLOC: 00631 case DB_DBT_REALLOC: 00632 case DB_DBT_USERMEM: 00633 break; 00634 default: 00635 return (CDB___db_ferr(dbenv, name, 1)); 00636 } 00637 00638 if (check_thread && DB_IS_THREADED(dbp) && 00639 !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM)) { 00640 CDB___db_err(dbenv, 00641 "DB_THREAD mandates memory allocation flag on DBT %s", 00642 name); 00643 return (EINVAL); 00644 } 00645 return (0); 00646 } 00647 00648 /* 00649 * __db_rdonly -- 00650 * Common readonly message. 00651 */ 00652 static int 00653 __db_rdonly(dbenv, name) 00654 const DB_ENV *dbenv; 00655 const char *name; 00656 { 00657 CDB___db_err(dbenv, "%s: attempt to modify a read-only tree", name); 00658 return (EACCES); 00659 } 00660 00661 /* 00662 * __db_curinval 00663 * Report that a cursor is in an invalid state. 00664 */ 00665 static int 00666 __db_curinval(dbenv) 00667 const DB_ENV *dbenv; 00668 { 00669 CDB___db_err(dbenv, 00670 "Cursor position must be set before performing this operation"); 00671 return (EINVAL); 00672 }