1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998 5 * Sleepycat Software. All rights reserved. 6 */ 7 8 #include "config.h" 9 10 #ifndef lint 11 static const char sccsid[] = "@(#)db_iface.c 10.40 (Sleepycat) 12/19/98"; 12 #endif /* not lint */ 13 14 #ifndef NO_SYSTEM_INCLUDES 15 #include <sys/types.h> 16 17 #include <errno.h> 18 #endif 19 20 #include "db_int.h" 21 #include "db_page.h" 22 #include "db_auto.h" 23 #include "db_ext.h" 24 #include "common_ext.h" 25 26 static int __db_keyempty __P((const DB_ENV *)); 27 static int __db_rdonly __P((const DB_ENV *, const char *)); 28 static int __dbt_ferr __P((const DB *, const char *, const DBT *, int)); 29 30 /* 31 * __db_cdelchk -- 32 * Common cursor delete argument checking routine. 33 * 34 * PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int, int)); 35 */ 36 int 37 __db_cdelchk(dbp, flags, isrdonly, isvalid) 38 const DB *dbp; 39 u_int32_t flags; 40 int isrdonly, isvalid; 41 { 42 /* Check for changes to a read-only tree. */ 43 if (isrdonly) 44 return (__db_rdonly(dbp->dbenv, "c_del")); 45 46 /* Check for invalid function flags. */ 47 switch (flags) { 48 case 0: 49 break; 50 default: 51 return (__db_ferr(dbp->dbenv, "DBcursor->c_del", 0)); 52 } 53 54 /* 55 * The cursor must be initialized, return -1 for an invalid cursor, 56 * otherwise 0. 57 */ 58 return (isvalid ? 0 : EINVAL); 59 } 60 61 /* 62 * __db_cgetchk -- 63 * Common cursor get argument checking routine. 64 * 65 * PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int)); 66 */ 67 int 68 __db_cgetchk(dbp, key, data, flags, isvalid) 69 const DB *dbp; 70 DBT *key, *data; 71 u_int32_t flags; 72 int isvalid; 73 { 74 int key_einval, key_flags, ret; 75 76 key_einval = key_flags = 0; 77 78 /* Check for invalid function flags. */ 79 LF_CLR(DB_RMW); 80 switch (flags) { 81 case DB_NEXT_DUP: 82 if (dbp->type == DB_RECNO) 83 goto err; 84 /* FALLTHROUGH */ 85 case DB_CURRENT: 86 case DB_FIRST: 87 case DB_LAST: 88 case DB_NEXT: 89 case DB_PREV: 90 key_flags = 1; 91 break; 92 case DB_GET_BOTH: 93 case DB_SET_RANGE: 94 key_einval = key_flags = 1; 95 break; 96 case DB_SET: 97 key_einval = 1; 98 break; 99 case DB_GET_RECNO: 100 if (!F_ISSET(dbp, DB_BT_RECNUM)) 101 goto err; 102 break; 103 case DB_SET_RECNO: 104 if (!F_ISSET(dbp, DB_BT_RECNUM)) 105 goto err; 106 key_einval = key_flags = 1; 107 break; 108 default: 109 err: return (__db_ferr(dbp->dbenv, "DBcursor->c_get", 0)); 110 } 111 112 /* Check for invalid key/data flags. */ 113 if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 114 return (ret); 115 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 116 return (ret); 117 118 /* Check for missing keys. */ 119 if (key_einval && (key->data == NULL || key->size == 0)) 120 return (__db_keyempty(dbp->dbenv)); 121 122 /* 123 * The cursor must be initialized for DB_CURRENT, return -1 for an 124 * invalid cursor, otherwise 0. 125 */ 126 return (isvalid || flags != DB_CURRENT ? 0 : EINVAL); 127 } 128 129 /* 130 * __db_cputchk -- 131 * Common cursor put argument checking routine. 132 * 133 * PUBLIC: int __db_cputchk __P((const DB *, 134 * PUBLIC: const DBT *, DBT *, u_int32_t, int, int)); 135 */ 136 int 137 __db_cputchk(dbp, key, data, flags, isrdonly, isvalid) 138 const DB *dbp; 139 const DBT *key; 140 DBT *data; 141 u_int32_t flags; 142 int isrdonly, isvalid; 143 { 144 int key_einval, key_flags, ret; 145 146 key_einval = key_flags = 0; 147 148 /* Check for changes to a read-only tree. */ 149 if (isrdonly) 150 return (__db_rdonly(dbp->dbenv, "c_put")); 151 152 /* Check for invalid function flags. */ 153 switch (flags) { 154 case DB_AFTER: 155 case DB_BEFORE: 156 if (dbp->dup_compare != NULL) 157 goto err; 158 if (dbp->type == DB_RECNO && !F_ISSET(dbp, DB_RE_RENUMBER)) 159 goto err; 160 if (dbp->type != DB_RECNO && !F_ISSET(dbp, DB_AM_DUP)) 161 goto err; 162 break; 163 case DB_CURRENT: 164 /* 165 * If there is a comparison function, doing a DB_CURRENT 166 * must not change the part of the data item that is used 167 * for the comparison. 168 */ 169 break; 170 case DB_KEYFIRST: 171 case DB_KEYLAST: 172 if (dbp->type == DB_RECNO) 173 goto err; 174 key_einval = key_flags = 1; 175 break; 176 default: 177 err: return (__db_ferr(dbp->dbenv, "DBcursor->c_put", 0)); 178 } 179 180 /* Check for invalid key/data flags. */ 181 if (key_flags && (ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 182 return (ret); 183 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 184 return (ret); 185 186 /* Check for missing keys. */ 187 if (key_einval && (key->data == NULL || key->size == 0)) 188 return (__db_keyempty(dbp->dbenv)); 189 190 /* 191 * The cursor must be initialized for anything other than DB_KEYFIRST 192 * and DB_KEYLAST, return -1 for an invalid cursor, otherwise 0. 193 */ 194 return (isvalid || 195 flags == DB_KEYFIRST || flags == DB_KEYLAST ? 0 : EINVAL); 196 } 197 198 /* 199 * __db_closechk -- 200 * DB->close flag check. 201 * 202 * PUBLIC: int __db_closechk __P((const DB *, u_int32_t)); 203 */ 204 int 205 __db_closechk(dbp, flags) 206 const DB *dbp; 207 u_int32_t flags; 208 { 209 /* Check for invalid function flags. */ 210 if (flags != 0 && flags != DB_NOSYNC) 211 return (__db_ferr(dbp->dbenv, "DB->close", 0)); 212 213 return (0); 214 } 215 216 /* 217 * __db_delchk -- 218 * Common delete argument checking routine. 219 * 220 * PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t, int)); 221 */ 222 int 223 __db_delchk(dbp, key, flags, isrdonly) 224 const DB *dbp; 225 DBT *key; 226 u_int32_t flags; 227 int isrdonly; 228 { 229 /* Check for changes to a read-only tree. */ 230 if (isrdonly) 231 return (__db_rdonly(dbp->dbenv, "delete")); 232 233 /* Check for invalid function flags. */ 234 switch (flags) { 235 case 0: 236 break; 237 default: 238 return (__db_ferr(dbp->dbenv, "DB->del", 0)); 239 } 240 241 /* Check for missing keys. */ 242 if (key->data == NULL || key->size == 0) 243 return (__db_keyempty(dbp->dbenv)); 244 245 return (0); 246 } 247 248 /* 249 * __db_getchk -- 250 * Common get argument checking routine. 251 * 252 * PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t)); 253 */ 254 int 255 __db_getchk(dbp, key, data, flags) 256 const DB *dbp; 257 const DBT *key; 258 DBT *data; 259 u_int32_t flags; 260 { 261 int ret; 262 263 /* Check for invalid function flags. */ 264 LF_CLR(DB_RMW); 265 switch (flags) { 266 case 0: 267 case DB_GET_BOTH: 268 break; 269 case DB_SET_RECNO: 270 if (!F_ISSET(dbp, DB_BT_RECNUM)) 271 goto err; 272 break; 273 default: 274 err: return (__db_ferr(dbp->dbenv, "DB->get", 0)); 275 } 276 277 /* Check for invalid key/data flags. */ 278 if ((ret = __dbt_ferr(dbp, "key", key, flags == DB_SET_RECNO)) != 0) 279 return (ret); 280 if ((ret = __dbt_ferr(dbp, "data", data, 1)) != 0) 281 return (ret); 282 283 /* Check for missing keys. */ 284 if (key->data == NULL || key->size == 0) 285 return (__db_keyempty(dbp->dbenv)); 286 287 return (0); 288 } 289 290 /* 291 * __db_joinchk -- 292 * Common join argument checking routine. 293 * 294 * PUBLIC: int __db_joinchk __P((const DB *, u_int32_t)); 295 */ 296 int 297 __db_joinchk(dbp, flags) 298 const DB *dbp; 299 u_int32_t flags; 300 { 301 if (flags != 0) 302 return (__db_ferr(dbp->dbenv, "DB->join", 0)); 303 304 return (0); 305 } 306 307 /* 308 * __db_putchk -- 309 * Common put argument checking routine. 310 * 311 * PUBLIC: int __db_putchk 312 * PUBLIC: __P((const DB *, DBT *, const DBT *, u_int32_t, int, int)); 313 */ 314 int 315 __db_putchk(dbp, key, data, flags, isrdonly, isdup) 316 const DB *dbp; 317 DBT *key; 318 const DBT *data; 319 u_int32_t flags; 320 int isrdonly, isdup; 321 { 322 int ret; 323 324 /* Check for changes to a read-only tree. */ 325 if (isrdonly) 326 return (__db_rdonly(dbp->dbenv, "put")); 327 328 /* Check for invalid function flags. */ 329 switch (flags) { 330 case 0: 331 case DB_NOOVERWRITE: 332 break; 333 case DB_APPEND: 334 if (dbp->type != DB_RECNO) 335 goto err; 336 break; 337 default: 338 err: return (__db_ferr(dbp->dbenv, "DB->put", 0)); 339 } 340 341 /* Check for invalid key/data flags. */ 342 if ((ret = __dbt_ferr(dbp, "key", key, 0)) != 0) 343 return (ret); 344 if ((ret = __dbt_ferr(dbp, "data", data, 0)) != 0) 345 return (ret); 346 347 /* Check for missing keys. */ 348 if (key->data == NULL || key->size == 0) 349 return (__db_keyempty(dbp->dbenv)); 350 351 /* Check for partial puts in the presence of duplicates. */ 352 if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) { 353 __db_err(dbp->dbenv, 354 "a partial put in the presence of duplicates requires a cursor operation"); 355 return (EINVAL); 356 } 357 358 return (0); 359 } 360 361 /* 362 * __db_statchk -- 363 * Common stat argument checking routine. 364 * 365 * PUBLIC: int __db_statchk __P((const DB *, u_int32_t)); 366 */ 367 int 368 __db_statchk(dbp, flags) 369 const DB *dbp; 370 u_int32_t flags; 371 { 372 /* Check for invalid function flags. */ 373 switch (flags) { 374 case 0: 375 break; 376 case DB_RECORDCOUNT: 377 if (dbp->type == DB_RECNO) 378 break; 379 if (dbp->type == DB_BTREE && F_ISSET(dbp, DB_BT_RECNUM)) 380 break; 381 goto err; 382 default: 383 err: return (__db_ferr(dbp->dbenv, "DB->stat", 0)); 384 } 385 386 return (0); 387 } 388 389 /* 390 * __db_syncchk -- 391 * Common sync argument checking routine. 392 * 393 * PUBLIC: int __db_syncchk __P((const DB *, u_int32_t)); 394 */ 395 int 396 __db_syncchk(dbp, flags) 397 const DB *dbp; 398 u_int32_t flags; 399 { 400 /* Check for invalid function flags. */ 401 switch (flags) { 402 case 0: 403 break; 404 default: 405 return (__db_ferr(dbp->dbenv, "DB->sync", 0)); 406 } 407 408 return (0); 409 } 410 411 /* 412 * __dbt_ferr -- 413 * Check a DBT for flag errors. 414 */ 415 static int 416 __dbt_ferr(dbp, name, dbt, check_thread) 417 const DB *dbp; 418 const char *name; 419 const DBT *dbt; 420 int check_thread; 421 { 422 int ret; 423 424 /* 425 * Check for invalid DBT flags. We allow any of the flags to be 426 * specified to any DB or DBcursor call so that applications can 427 * set DB_DBT_MALLOC when retrieving a data item from a secondary 428 * database and then specify that same DBT as a key to a primary 429 * database, without having to clear flags. 430 */ 431 if ((ret = __db_fchk(dbp->dbenv, name, dbt->flags, 432 DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL)) != 0) 433 return (ret); 434 if ((ret = __db_fcchk(dbp->dbenv, name, 435 dbt->flags, DB_DBT_MALLOC, DB_DBT_USERMEM)) != 0) 436 return (ret); 437 438 if (check_thread && F_ISSET(dbp, DB_AM_THREAD) && 439 !F_ISSET(dbt, DB_DBT_MALLOC | DB_DBT_USERMEM)) { 440 __db_err(dbp->dbenv, 441 "missing flag thread flag for %s DBT", name); 442 return (EINVAL); 443 } 444 return (0); 445 } 446 447 /* 448 * __db_eopnotsup -- 449 * Common operation not supported message. 450 * 451 * PUBLIC: int __db_eopnotsup __P((const DB_ENV *)); 452 */ 453 int 454 __db_eopnotsup(dbenv) 455 const DB_ENV *dbenv; 456 { 457 __db_err(dbenv, "operation not supported"); 458 #ifdef EOPNOTSUPP 459 return (EOPNOTSUPP); 460 #else 461 return (EINVAL); 462 #endif 463 } 464 465 /* 466 * __db_keyempty -- 467 * Common missing or empty key value message. 468 */ 469 static int 470 __db_keyempty(dbenv) 471 const DB_ENV *dbenv; 472 { 473 __db_err(dbenv, "missing or empty key value specified"); 474 return (EINVAL); 475 } 476 477 /* 478 * __db_rdonly -- 479 * Common readonly message. 480 */ 481 static int 482 __db_rdonly(dbenv, name) 483 const DB_ENV *dbenv; 484 const char *name; 485 { 486 __db_err(dbenv, "%s: attempt to modify a read-only tree", name); 487 return (EACCES); 488 } 489