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