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
__db_cdelchk(dbp,flags,isrdonly,isvalid)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
__db_cgetchk(dbp,key,data,flags,isvalid)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
__db_cputchk(dbp,key,data,flags,isrdonly,isvalid)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
__db_closechk(dbp,flags)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
__db_delchk(dbp,key,flags,isrdonly)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
__db_getchk(dbp,key,data,flags)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
__db_joinchk(dbp,flags)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
__db_putchk(dbp,key,data,flags,isrdonly,isdup)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
__db_statchk(dbp,flags)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
__db_syncchk(dbp,flags)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
__dbt_ferr(dbp,name,dbt,check_thread)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
__db_eopnotsup(dbenv)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
__db_keyempty(dbenv)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
__db_rdonly(dbenv,name)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