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