📄 db_iface.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996-2002 * Sleepycat Software. All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: db_iface.c,v 11.77 2002/08/08 03:57:47 bostic Exp $";#endif /* not lint */#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#endif#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_am.h"static int __db_curinval __P((const DB_ENV *));static int __db_fnl __P((const DB_ENV *, const char *));static int __db_rdonly __P((const DB_ENV *, const char *));static int __dbt_ferr __P((const DB *, const char *, const DBT *, int));/* * A database should be required to be readonly if it's been explicitly * specified as such or if we're a client in a replicated environment and * we don't have the special "client-writer" designation. */#define IS_READONLY(dbp) \ (F_ISSET(dbp, DB_AM_RDONLY) || \ (F_ISSET((dbp)->dbenv, DB_ENV_REP_CLIENT) && \ !F_ISSET((dbp), DB_AM_CL_WRITER)))/* * __db_cursorchk -- * Common cursor argument checking routine. * * PUBLIC: int __db_cursorchk __P((const DB *, u_int32_t)); */int__db_cursorchk(dbp, flags) const DB *dbp; u_int32_t flags;{ /* DB_DIRTY_READ is the only valid bit-flag and requires locking. */ if (LF_ISSET(DB_DIRTY_READ)) { if (!LOCKING_ON(dbp->dbenv)) return (__db_fnl(dbp->dbenv, "DB->cursor")); LF_CLR(DB_DIRTY_READ); } /* Check for invalid function flags. */ switch (flags) { case 0: break; case DB_WRITECURSOR: if (IS_READONLY(dbp)) return (__db_rdonly(dbp->dbenv, "DB->cursor")); if (!CDB_LOCKING(dbp->dbenv)) return (__db_ferr(dbp->dbenv, "DB->cursor", 0)); break; case DB_WRITELOCK: if (IS_READONLY(dbp)) return (__db_rdonly(dbp->dbenv, "DB->cursor")); break; default: return (__db_ferr(dbp->dbenv, "DB->cursor", 0)); } return (0);}/* * __db_ccountchk -- * Common cursor count argument checking routine. * * PUBLIC: int __db_ccountchk __P((const DB *, u_int32_t, int)); */int__db_ccountchk(dbp, flags, isvalid) const DB *dbp; u_int32_t flags; int isvalid;{ /* Check for invalid function flags. */ switch (flags) { case 0: break; default: return (__db_ferr(dbp->dbenv, "DBcursor->c_count", 0)); } /* * The cursor must be initialized, return EINVAL for an invalid cursor, * otherwise 0. */ return (isvalid ? 0 : __db_curinval(dbp->dbenv));}/* * __db_cdelchk -- * Common cursor delete argument checking routine. * * PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int)); */int__db_cdelchk(dbp, flags, isvalid) const DB *dbp; u_int32_t flags; int isvalid;{ /* Check for changes to a read-only tree. */ if (IS_READONLY(dbp)) return (__db_rdonly(dbp->dbenv, "c_del")); /* Check for invalid function flags. */ switch (flags) { case 0: break; case DB_UPDATE_SECONDARY: DB_ASSERT(F_ISSET(dbp, DB_AM_SECONDARY)); break; default: return (__db_ferr(dbp->dbenv, "DBcursor->c_del", 0)); } /* * The cursor must be initialized, return EINVAL for an invalid cursor, * otherwise 0. */ return (isvalid ? 0 : __db_curinval(dbp->dbenv));}/* * __db_cgetchk -- * Common cursor get argument checking routine. * * PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int)); */int__db_cgetchk(dbp, key, data, flags, isvalid) const DB *dbp; DBT *key, *data; u_int32_t flags; int isvalid;{ int dirty, multi, ret; /* * Check for read-modify-write validity. DB_RMW doesn't make sense * with CDB cursors since if you're going to write the cursor, you * had to create it with DB_WRITECURSOR. Regardless, we check for * LOCKING_ON and not STD_LOCKING, as we don't want to disallow it. * If this changes, confirm that DB does not itself set the DB_RMW * flag in a path where CDB may have been configured. */ dirty = 0; if (LF_ISSET(DB_DIRTY_READ | DB_RMW)) { if (!LOCKING_ON(dbp->dbenv)) return (__db_fnl(dbp->dbenv, "DBcursor->c_get")); if (LF_ISSET(DB_DIRTY_READ)) dirty = 1; LF_CLR(DB_DIRTY_READ | DB_RMW); } multi = 0; if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { multi = 1; if (LF_ISSET(DB_MULTIPLE) && LF_ISSET(DB_MULTIPLE_KEY)) goto multi_err; LF_CLR(DB_MULTIPLE | DB_MULTIPLE_KEY); } /* Check for invalid function flags. */ switch (flags) { case DB_CONSUME: case DB_CONSUME_WAIT: if (dirty) { __db_err(dbp->dbenv, "DB_DIRTY_READ is not supported with DB_CONSUME or DB_CONSUME_WAIT"); return (EINVAL); } if (dbp->type != DB_QUEUE) goto err; break; case DB_CURRENT: case DB_FIRST: case DB_GET_BOTH: case DB_GET_BOTH_RANGE: case DB_NEXT: case DB_NEXT_DUP: case DB_NEXT_NODUP: case DB_SET: case DB_SET_RANGE: break; case DB_LAST: case DB_PREV: case DB_PREV_NODUP: if (multi)multi_err: return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 1)); break; case DB_GET_BOTHC: if (dbp->type == DB_QUEUE) goto err; break; case DB_GET_RECNO: /* * The one situation in which this might be legal with a * non-RECNUM dbp is if dbp is a secondary and its primary is * DB_AM_RECNUM. */ if (!F_ISSET(dbp, DB_AM_RECNUM) && (!F_ISSET(dbp, DB_AM_SECONDARY) || !F_ISSET(dbp->s_primary, DB_AM_RECNUM))) goto err; break; case DB_SET_RECNO: if (!F_ISSET(dbp, DB_AM_RECNUM)) goto err; break; default:err: return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0)); } /* Check for invalid key/data flags. */ if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) return (ret); if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) return (ret); if (multi && !F_ISSET(data, DB_DBT_USERMEM)) { __db_err(dbp->dbenv, "DB_MULTIPLE(_KEY) requires that DB_DBT_USERMEM be set"); return (EINVAL); } if (multi && (F_ISSET(key, DB_DBT_PARTIAL) || F_ISSET(data, DB_DBT_PARTIAL))) { __db_err(dbp->dbenv, "DB_DBT_PARTIAL forbidden with DB_MULTIPLE(_KEY)"); return (EINVAL); } /* * The cursor must be initialized for DB_CURRENT, DB_GET_RECNO and * DB_NEXT_DUP. Return EINVAL for an invalid cursor, otherwise 0. */ if (isvalid || (flags != DB_CURRENT && flags != DB_GET_RECNO && flags != DB_NEXT_DUP)) return (0); return (__db_curinval(dbp->dbenv));}/* * __db_cputchk -- * Common cursor put argument checking routine. * * PUBLIC: int __db_cputchk __P((const DB *, * PUBLIC: const DBT *, DBT *, u_int32_t, int)); */int__db_cputchk(dbp, key, data, flags, isvalid) const DB *dbp; const DBT *key; DBT *data; u_int32_t flags; int isvalid;{ int key_flags, ret; key_flags = 0; /* Check for changes to a read-only tree. */ if (IS_READONLY(dbp)) return (__db_rdonly(dbp->dbenv, "c_put")); /* Check for puts on a secondary. */ if (F_ISSET(dbp, DB_AM_SECONDARY)) { if (flags == DB_UPDATE_SECONDARY) flags = DB_KEYLAST; else { __db_err(dbp->dbenv, "DBcursor->c_put forbidden on secondary indices"); return (EINVAL); } } /* Check for invalid function flags. */ switch (flags) { case DB_AFTER: case DB_BEFORE: switch (dbp->type) { case DB_BTREE: case DB_HASH: /* Only with unsorted duplicates. */ if (!F_ISSET(dbp, DB_AM_DUP)) goto err; if (dbp->dup_compare != NULL) goto err; break; case DB_QUEUE: /* Not permitted. */ goto err; case DB_RECNO: /* Only with mutable record numbers. */ if (!F_ISSET(dbp, DB_AM_RENUMBER)) goto err; key_flags = 1; break; default: goto err; } break; case DB_CURRENT: /* * If there is a comparison function, doing a DB_CURRENT * must not change the part of the data item that is used * for the comparison. */ break; case DB_NODUPDATA: if (!F_ISSET(dbp, DB_AM_DUPSORT)) goto err; /* FALLTHROUGH */ case DB_KEYFIRST: case DB_KEYLAST: key_flags = 1; break; default:err: return (__db_ferr(dbp->dbenv, "DBcursor->c_put", 0)); } /* Check for invalid key/data flags. */ if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0) return (ret); if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) return (ret); /* * The cursor must be initialized for anything other than DB_KEYFIRST * and DB_KEYLAST, return EINVAL for an invalid cursor, otherwise 0. */ if (isvalid || flags == DB_KEYFIRST || flags == DB_KEYLAST || flags == DB_NODUPDATA) return (0); return (__db_curinval(dbp->dbenv));}/* * __db_pgetchk -- * DB->pget flag check. * * PUBLIC: int __db_pgetchk __P((const DB *, const DBT *, DBT *, DBT *, * PUBLIC: u_int32_t)); */int__db_pgetchk(dbp, skey, pkey, data, flags) const DB *dbp; const DBT *skey; DBT *pkey, *data; u_int32_t flags;{ int ret; u_int32_t save_flags; save_flags = flags; if (!F_ISSET(dbp, DB_AM_SECONDARY)) { __db_err(dbp->dbenv, "DB->pget may only be used on secondary indices"); return (EINVAL); } if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { __db_err(dbp->dbenv, "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices"); return (EINVAL); } /* DB_CONSUME makes no sense on a secondary index. */ LF_CLR(DB_RMW); switch (flags) { case DB_CONSUME: case DB_CONSUME_WAIT: return (__db_ferr(dbp->dbenv, "DB->pget", 0)); default: /* __db_getchk will catch the rest. */ break; } /* * We allow the pkey field to be NULL, so that we can make the * two-DBT get calls into wrappers for the three-DBT ones. */ if (pkey != NULL && (ret = __dbt_ferr(dbp, "primary key", pkey, 1)) != 0) return (ret); /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */ if (pkey == NULL && flags == DB_GET_BOTH) { __db_err(dbp->dbenv, "DB_GET_BOTH on a secondary index requires a primary key"); return (EINVAL); } return (__db_getchk(dbp, skey, data, save_flags));}/* * __db_cpgetchk -- * Secondary-index cursor get argument checking routine. * * PUBLIC: int __db_cpgetchk __P((const DB *, * PUBLIC: DBT *, DBT *, DBT *, u_int32_t, int)); */int__db_cpgetchk(dbp, skey, pkey, data, flags, isvalid) const DB *dbp; DBT *skey, *pkey, *data; u_int32_t flags; int isvalid;{ int ret; u_int32_t save_flags; save_flags = flags; if (!F_ISSET(dbp, DB_AM_SECONDARY)) { __db_err(dbp->dbenv, "DBcursor->c_pget may only be used on secondary indices"); return (EINVAL); } if (LF_ISSET(DB_MULTIPLE | DB_MULTIPLE_KEY)) { __db_err(dbp->dbenv, "DB_MULTIPLE and DB_MULTIPLE_KEY may not be used on secondary indices"); return (EINVAL); } LF_CLR(DB_RMW); switch (flags) { case DB_CONSUME: case DB_CONSUME_WAIT: /* DB_CONSUME makes no sense on a secondary index. */ return (__db_ferr(dbp->dbenv, "DBcursor->c_pget", 0)); case DB_GET_BOTH: /* DB_GET_BOTH is "get both the primary and the secondary". */ if (pkey == NULL) { __db_err(dbp->dbenv, "DB_GET_BOTH requires both a secondary and a primary key"); return (EINVAL); } break; default: /* __db_cgetchk will catch the rest. */ break; } /* * We allow the pkey field to be NULL, so that we can make the * two-DBT get calls into wrappers for the three-DBT ones. */ if (pkey != NULL && (ret = __dbt_ferr(dbp, "primary key", pkey, 0)) != 0) return (ret); /* But the pkey field can't be NULL if we're doing a DB_GET_BOTH. */ if (pkey == NULL && flags == DB_GET_BOTH) { __db_err(dbp->dbenv, "DB_GET_BOTH on a secondary index requires a primary key"); return (EINVAL); } return (__db_cgetchk(dbp, skey, data, save_flags, isvalid));}/* * __db_delchk -- * Common delete argument checking routine. * * PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t)); */int__db_delchk(dbp, key, flags) const DB *dbp; DBT *key; u_int32_t flags;{ COMPQUIET(key, NULL); /* Check for changes to a read-only tree. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -