1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: Cursor.java,v 12.11 2008/04/02 13:43:38 bschmeck Exp $
7 */
8
9package com.sleepycat.db;
10
11import com.sleepycat.db.internal.DbConstants;
12import com.sleepycat.db.internal.Dbc;
13
14/**
15A database cursor. Cursors are used for operating on collections of
16records, for iterating over a database, and for saving handles to
17individual records, so that they can be modified after they have been
18read.
19<p>
20Cursors may be used by multiple threads, but only serially.  That is,
21the application must serialize access to the handle.
22<p>
23If the cursor is to be used to perform operations on behalf of a
24transaction, the cursor must be opened and closed within the context of
25that single transaction.
26<p>
27Once the cursor close method has been called, the handle may not be
28accessed again, regardless of the close method's success or failure.
29<p>
30To obtain a cursor with default attributes:
31<blockquote><pre>
32    Cursor cursor = myDatabase.openCursor(txn, null);
33</pre></blockquote>
34To customize the attributes of a cursor, use a CursorConfig object.
35<blockquote><pre>
36    CursorConfig config = new CursorConfig();
37    config.setDirtyRead(true);
38    Cursor cursor = myDatabase.openCursor(txn, config);
39</pre></blockquote>
40<p>
41Modifications to the database during a sequential scan will be reflected
42in the scan; that is, records inserted behind a cursor will not be
43returned while records inserted in front of a cursor will be returned.
44In Queue and Recno databases, missing entries (that is, entries that
45were never explicitly created or that were created and then deleted)
46will be ignored during a sequential scan.
47*/
48public class Cursor {
49    /* package */ Dbc dbc;
50    /* package */ Database database;
51    /* package */ CursorConfig config;
52
53    // Constructor needed by Java RPC server
54    protected Cursor(final Database database, final CursorConfig config) {
55        this.database = database;
56        this.config = config;
57    }
58
59    Cursor(final Database database, final Dbc dbc, final CursorConfig config)
60        throws DatabaseException {
61
62        this.database = database;
63        this.dbc = dbc;
64        this.config = config;
65    }
66
67    public synchronized void close()
68        throws DatabaseException {
69
70        if (dbc != null) {
71            try {
72                dbc.close();
73            } finally {
74                dbc = null;
75            }
76        }
77    }
78
79    /**
80    Return a new cursor with the same transaction and locker ID as the
81    original cursor.
82    <p>
83    This is useful when an application is using locking and requires two
84    or more cursors in the same thread of control.
85    <p>
86    @param samePosition
87    If true, the newly created cursor is initialized to refer to the
88    same position in the database as the original cursor (if any) and
89    hold the same locks (if any). If false, or the original cursor does
90    not hold a database position and locks, the returned cursor is
91    uninitialized and will behave like a newly created cursor.
92    <p>
93    @return
94    A new cursor with the same transaction and locker ID as the original
95    cursor.
96    <p>
97    <p>
98@throws DatabaseException if a failure occurs.
99    */
100    public Cursor dup(final boolean samePosition)
101        throws DatabaseException {
102
103        return new Cursor(database,
104            dbc.dup(samePosition ? DbConstants.DB_POSITION : 0), config);
105    }
106
107    /**
108    Return this cursor's configuration.
109    <p>
110    This may differ from the configuration used to open this object if
111    the cursor existed previously.
112    <p>
113    @return
114    This cursor's configuration.
115    <p>
116    <p>
117@throws DatabaseException if a failure occurs.
118    */
119    public CursorConfig getConfig() {
120        return config;
121    }
122
123    /**
124    Return the Database handle associated with this Cursor.
125    <p>
126    @return
127    The Database handle associated with this Cursor.
128    <p>
129    */
130    public Database getDatabase() {
131        return database;
132    }
133
134    /**
135    Return a count of the number of data items for the key to which the
136    cursor refers.
137    <p>
138    @return
139    A count of the number of data items for the key to which the cursor
140    refers.
141    <p>
142    <p>
143@throws DeadlockException if the operation was selected to resolve a
144deadlock.
145<p>
146@throws DatabaseException if a failure occurs.
147    */
148    public int count()
149        throws DatabaseException {
150
151        return dbc.count(0);
152    }
153
154    /**
155    Delete the key/data pair to which the cursor refers.
156    <p>
157    When called on a cursor opened on a database that has been made into a
158    secondary index, this method the key/data pair from the primary database
159    and all secondary indices.
160    <p>
161    The cursor position is unchanged after a delete, and subsequent calls
162to cursor functions expecting the cursor to refer to an existing key
163will fail.
164    <p>
165    <p>
166@throws DeadlockException if the operation was selected to resolve a
167deadlock.
168<p>
169@throws DatabaseException if a failure occurs.
170    */
171    public OperationStatus delete()
172        throws DatabaseException {
173
174        return OperationStatus.fromInt(dbc.del(0));
175    }
176
177    /**
178    Returns the key/data pair to which the cursor refers.
179<p>
180If this method fails for any reason, the position of the cursor will be
181unchanged.
182@throws NullPointerException if a DatabaseEntry parameter is null or
183does not contain a required non-null byte array.
184<p>
185@throws DeadlockException if the operation was selected to resolve a
186deadlock.
187<p>
188@throws IllegalArgumentException if an invalid parameter was specified.
189<p>
190@throws DatabaseException if a failure occurs.
191<p>
192@param key the  key
193returned as output.  Its byte array does not need to be initialized by the
194caller.
195@param data the  data
196returned as output.  Multiple results can be retrieved by passing an object
197that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
198need to be initialized by the caller.
199@param lockMode the locking attributes; if null, default attributes are used.
200@return {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the key/pair at the cursor
201position has been deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
202    */
203    public OperationStatus getCurrent(final DatabaseEntry key,
204                                      final DatabaseEntry data,
205                                      LockMode lockMode)
206        throws DatabaseException {
207
208        return OperationStatus.fromInt(
209            dbc.get(key, data, DbConstants.DB_CURRENT |
210                LockMode.getFlag(lockMode) |
211                ((data == null) ? 0 : data.getMultiFlag())));
212    }
213
214    /**
215    Move the cursor to the first key/data pair of the database, and return
216that pair.  If the first key has duplicate values, the first data item
217in the set of duplicates is returned.
218<p>
219If this method fails for any reason, the position of the cursor will be
220unchanged.
221@throws NullPointerException if a DatabaseEntry parameter is null or
222does not contain a required non-null byte array.
223<p>
224@throws DeadlockException if the operation was selected to resolve a
225deadlock.
226<p>
227@throws IllegalArgumentException if an invalid parameter was specified.
228<p>
229@throws DatabaseException if a failure occurs.
230<p>
231@param key the  key
232returned as output.  Its byte array does not need to be initialized by the
233caller.
234@param data the  data
235returned as output.  Multiple results can be retrieved by passing an object
236that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
237need to be initialized by the caller.
238@param lockMode the locking attributes; if null, default attributes are used.
239@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
240found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
241    */
242    public OperationStatus getFirst(final DatabaseEntry key,
243                                    final DatabaseEntry data,
244                                    LockMode lockMode)
245        throws DatabaseException {
246
247        return OperationStatus.fromInt(
248            dbc.get(key, data, DbConstants.DB_FIRST |
249                LockMode.getFlag(lockMode) |
250                ((data == null) ? 0 : data.getMultiFlag())));
251    }
252
253    /**
254    Move the cursor to the last key/data pair of the database, and return
255that pair.  If the last key has duplicate values, the last data item in
256the set of duplicates is returned.
257<p>
258If this method fails for any reason, the position of the cursor will be
259unchanged.
260@throws NullPointerException if a DatabaseEntry parameter is null or
261does not contain a required non-null byte array.
262<p>
263@throws DeadlockException if the operation was selected to resolve a
264deadlock.
265<p>
266@throws IllegalArgumentException if an invalid parameter was specified.
267<p>
268@throws DatabaseException if a failure occurs.
269<p>
270@param key the  key
271returned as output.  Its byte array does not need to be initialized by the
272caller.
273@param data the  data
274returned as output.  Its byte array does not need to be initialized by the
275caller.
276@param lockMode the locking attributes; if null, default attributes are used.
277@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
278found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
279    */
280    public OperationStatus getLast(final DatabaseEntry key,
281                                   final DatabaseEntry data,
282                                   LockMode lockMode)
283        throws DatabaseException {
284
285        return OperationStatus.fromInt(
286            dbc.get(key, data, DbConstants.DB_LAST |
287                LockMode.getFlag(lockMode) |
288                ((data == null) ? 0 : data.getMultiFlag())));
289    }
290
291    /**
292    Move the cursor to the next key/data pair and return that pair.  If
293the matching key has duplicate values, the first data item in the set
294of duplicates is returned.
295<p>
296If the cursor is not yet initialized, move the cursor to the first
297key/data pair of the database, and return that pair.  Otherwise, the
298cursor is moved to the next key/data pair of the database, and that pair
299is returned.  In the presence of duplicate key values, the value of the
300key may not change.
301<p>
302If this method fails for any reason, the position of the cursor will be
303unchanged.
304@throws NullPointerException if a DatabaseEntry parameter is null or
305does not contain a required non-null byte array.
306<p>
307@throws DeadlockException if the operation was selected to resolve a
308deadlock.
309<p>
310@throws IllegalArgumentException if an invalid parameter was specified.
311<p>
312@throws DatabaseException if a failure occurs.
313<p>
314@param key the  key
315returned as output.  Its byte array does not need to be initialized by the
316caller.
317@param data the  data
318returned as output.  Multiple results can be retrieved by passing an object
319that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
320need to be initialized by the caller.
321@param lockMode the locking attributes; if null, default attributes are used.
322@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
323found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
324    */
325    public OperationStatus getNext(final DatabaseEntry key,
326                                   final DatabaseEntry data,
327                                   LockMode lockMode)
328        throws DatabaseException {
329
330        return OperationStatus.fromInt(
331            dbc.get(key, data, DbConstants.DB_NEXT |
332                LockMode.getFlag(lockMode) |
333                ((data == null) ? 0 : data.getMultiFlag())));
334    }
335
336    /**
337    If the next key/data pair of the database is a duplicate data record for
338the current key/data pair, move the cursor to the next key/data pair
339of the database and return that pair.
340<p>
341If this method fails for any reason, the position of the cursor will be
342unchanged.
343@throws NullPointerException if a DatabaseEntry parameter is null or
344does not contain a required non-null byte array.
345<p>
346@throws DeadlockException if the operation was selected to resolve a
347deadlock.
348<p>
349@throws IllegalArgumentException if an invalid parameter was specified.
350<p>
351@throws DatabaseException if a failure occurs.
352<p>
353@param key the  key
354returned as output.  Its byte array does not need to be initialized by the
355caller.
356@param data the  data
357returned as output.  Multiple results can be retrieved by passing an object
358that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
359need to be initialized by the caller.
360@param lockMode the locking attributes; if null, default attributes are used.
361@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
362found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
363    */
364    public OperationStatus getNextDup(final DatabaseEntry key,
365                                      final DatabaseEntry data,
366                                      LockMode lockMode)
367        throws DatabaseException {
368
369        return OperationStatus.fromInt(
370            dbc.get(key, data, DbConstants.DB_NEXT_DUP |
371                LockMode.getFlag(lockMode) |
372                ((data == null) ? 0 : data.getMultiFlag())));
373    }
374
375    /**
376    Move the cursor to the next non-duplicate key/data pair and return
377that pair.  If the matching key has duplicate values, the first data
378item in the set of duplicates is returned.
379<p>
380If the cursor is not yet initialized, move the cursor to the first
381key/data pair of the database, and return that pair.  Otherwise, the
382cursor is moved to the next non-duplicate key of the database, and that
383key/data pair is returned.
384<p>
385If this method fails for any reason, the position of the cursor will be
386unchanged.
387@throws NullPointerException if a DatabaseEntry parameter is null or
388does not contain a required non-null byte array.
389<p>
390@throws DeadlockException if the operation was selected to resolve a
391deadlock.
392<p>
393@throws IllegalArgumentException if an invalid parameter was specified.
394<p>
395@throws DatabaseException if a failure occurs.
396<p>
397@param key the  key
398returned as output.  Its byte array does not need to be initialized by the
399caller.
400@param data the  data
401returned as output.  Multiple results can be retrieved by passing an object
402that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
403need to be initialized by the caller.
404@param lockMode the locking attributes; if null, default attributes are used.
405@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
406found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
407    */
408    public OperationStatus getNextNoDup(final DatabaseEntry key,
409                                        final DatabaseEntry data,
410                                        LockMode lockMode)
411        throws DatabaseException {
412
413        return OperationStatus.fromInt(
414            dbc.get(key, data, DbConstants.DB_NEXT_NODUP |
415                LockMode.getFlag(lockMode) |
416                ((data == null) ? 0 : data.getMultiFlag())));
417    }
418
419    /**
420    Move the cursor to the previous key/data pair and return that pair.
421If the matching key has duplicate values, the last data item in the set
422of duplicates is returned.
423<p>
424If the cursor is not yet initialized, move the cursor to the last
425key/data pair of the database, and return that pair.  Otherwise, the
426cursor is moved to the previous key/data pair of the database, and that
427pair is returned. In the presence of duplicate key values, the value of
428the key may not change.
429<p>
430If this method fails for any reason, the position of the cursor will be
431unchanged.
432@throws NullPointerException if a DatabaseEntry parameter is null or
433does not contain a required non-null byte array.
434<p>
435@throws DeadlockException if the operation was selected to resolve a
436deadlock.
437<p>
438@throws IllegalArgumentException if an invalid parameter was specified.
439<p>
440@throws DatabaseException if a failure occurs.
441<p>
442@param key the  key
443returned as output.  Its byte array does not need to be initialized by the
444caller.
445@param data the  data
446returned as output.  Its byte array does not need to be initialized by the
447caller.
448@param lockMode the locking attributes; if null, default attributes are used.
449@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
450found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
451    */
452    public OperationStatus getPrev(final DatabaseEntry key,
453                                   final DatabaseEntry data,
454                                   LockMode lockMode)
455        throws DatabaseException {
456
457        return OperationStatus.fromInt(
458            dbc.get(key, data, DbConstants.DB_PREV |
459                LockMode.getFlag(lockMode) |
460                ((data == null) ? 0 : data.getMultiFlag())));
461    }
462
463    /**
464    If the previous key/data pair of the database is a duplicate data record
465for the current key/data pair, move the cursor to the previous key/data
466pair of the database and return that pair.
467<p>
468If this method fails for any reason, the position of the cursor will be
469unchanged.
470@throws NullPointerException if a DatabaseEntry parameter is null or
471does not contain a required non-null byte array.
472<p>
473@throws DeadlockException if the operation was selected to resolve a
474deadlock.
475<p>
476@throws IllegalArgumentException if an invalid parameter was specified.
477<p>
478@throws DatabaseException if a failure occurs.
479<p>
480@param key the  key
481returned as output.  Its byte array does not need to be initialized by the
482caller.
483@param data the  data
484returned as output.  Its byte array does not need to be initialized by the
485caller.
486@param lockMode the locking attributes; if null, default attributes are used.
487@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
488found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
489    */
490    public OperationStatus getPrevDup(final DatabaseEntry key,
491                                      final DatabaseEntry data,
492                                      LockMode lockMode)
493        throws DatabaseException {
494
495        return OperationStatus.fromInt(
496            dbc.get(key, data, DbConstants.DB_PREV_DUP |
497                LockMode.getFlag(lockMode) |
498                ((data == null) ? 0 : data.getMultiFlag())));
499    }
500
501    /**
502    Move the cursor to the previous non-duplicate key/data pair and return
503that pair.  If the matching key has duplicate values, the last data item
504in the set of duplicates is returned.
505<p>
506If the cursor is not yet initialized, move the cursor to the last
507key/data pair of the database, and return that pair.  Otherwise, the
508cursor is moved to the previous non-duplicate key of the database, and
509that key/data pair is returned.
510<p>
511If this method fails for any reason, the position of the cursor will be
512unchanged.
513@throws NullPointerException if a DatabaseEntry parameter is null or
514does not contain a required non-null byte array.
515<p>
516@throws DeadlockException if the operation was selected to resolve a
517deadlock.
518<p>
519@throws IllegalArgumentException if an invalid parameter was specified.
520<p>
521@throws DatabaseException if a failure occurs.
522<p>
523@param key the  key
524returned as output.  Its byte array does not need to be initialized by the
525caller.
526@param data the  data
527returned as output.  Its byte array does not need to be initialized by the
528caller.
529@param lockMode the locking attributes; if null, default attributes are used.
530@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
531found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
532    */
533    public OperationStatus getPrevNoDup(final DatabaseEntry key,
534                                        final DatabaseEntry data,
535                                        LockMode lockMode)
536        throws DatabaseException {
537
538        return OperationStatus.fromInt(
539            dbc.get(key, data, DbConstants.DB_PREV_NODUP |
540                LockMode.getFlag(lockMode) |
541                ((data == null) ? 0 : data.getMultiFlag())));
542    }
543
544    /**
545    Return the record number associated with the cursor.  The record number
546will be returned in the data parameter.
547<p>
548For this method to be called, the underlying database must be of type
549Btree, and it must have been configured to support record numbers.
550<p>
551If this method fails for any reason, the position of the cursor will be
552unchanged.
553@throws NullPointerException if a DatabaseEntry parameter is null or
554does not contain a required non-null byte array.
555<p>
556@throws DeadlockException if the operation was selected to resolve a
557deadlock.
558<p>
559@throws IllegalArgumentException if an invalid parameter was specified.
560<p>
561@throws DatabaseException if a failure occurs.
562<p>
563@param data the  data
564returned as output.  Its byte array does not need to be initialized by the
565caller.
566@param lockMode the locking attributes; if null, default attributes are used.
567@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
568found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
569    */
570    public OperationStatus getRecordNumber(final DatabaseEntry data,
571                                           LockMode lockMode)
572        throws DatabaseException {
573
574        return OperationStatus.fromInt(
575            dbc.get(DatabaseEntry.IGNORE, data,
576                DbConstants.DB_GET_RECNO |
577                LockMode.getFlag(lockMode) |
578                ((data == null) ? 0 : data.getMultiFlag())));
579    }
580
581    /**
582    Move the cursor to the given key of the database, and return the datum
583associated with the given key.  If the matching key has duplicate
584values, the first data item in the set of duplicates is returned.
585<p>
586If this method fails for any reason, the position of the cursor will be
587unchanged.
588@throws NullPointerException if a DatabaseEntry parameter is null or
589does not contain a required non-null byte array.
590<p>
591@throws DeadlockException if the operation was selected to resolve a
592deadlock.
593<p>
594@throws IllegalArgumentException if an invalid parameter was specified.
595<p>
596@throws DatabaseException if a failure occurs.
597<p>
598@param key the  key
599used as input.  It must be initialized with a non-null byte array by the
600caller.
601@param data the  data
602returned as output.  Multiple results can be retrieved by passing an object
603that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
604need to be initialized by the caller.
605@param lockMode the locking attributes; if null, default attributes are used.
606@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
607found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
608    */
609    public OperationStatus getSearchKey(final DatabaseEntry key,
610                                        final DatabaseEntry data,
611                                        LockMode lockMode)
612        throws DatabaseException {
613
614        return OperationStatus.fromInt(
615            dbc.get(key, data, DbConstants.DB_SET |
616                LockMode.getFlag(lockMode) |
617                ((data == null) ? 0 : data.getMultiFlag())));
618    }
619
620    /**
621    Move the cursor to the closest matching key of the database, and return
622the data item associated with the matching key.  If the matching key has
623duplicate values, the first data item in the set of duplicates is returned.
624<p>
625The returned key/data pair is for the smallest key greater than or equal
626to the specified key (as determined by the key comparison function),
627permitting partial key matches and range searches.
628<p>
629If this method fails for any reason, the position of the cursor will be
630unchanged.
631@throws NullPointerException if a DatabaseEntry parameter is null or
632does not contain a required non-null byte array.
633<p>
634@throws DeadlockException if the operation was selected to resolve a
635deadlock.
636<p>
637@throws IllegalArgumentException if an invalid parameter was specified.
638<p>
639@throws DatabaseException if a failure occurs.
640<p>
641@param key the  key
642used as input and returned as output.  It must be initialized with a non-null
643byte array by the caller.
644@param data the  data
645returned as output.  Multiple results can be retrieved by passing an object
646that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
647need to be initialized by the caller.
648@param lockMode the locking attributes; if null, default attributes are used.
649@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
650found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
651    */
652    public OperationStatus getSearchKeyRange(final DatabaseEntry key,
653                                             final DatabaseEntry data,
654                                             LockMode lockMode)
655        throws DatabaseException {
656
657        return OperationStatus.fromInt(
658            dbc.get(key, data, DbConstants.DB_SET_RANGE |
659                LockMode.getFlag(lockMode) |
660                ((data == null) ? 0 : data.getMultiFlag())));
661    }
662
663    /**
664    Move the cursor to the specified key/data pair, where both the key and
665data items must match.
666<p>
667If this method fails for any reason, the position of the cursor will be
668unchanged.
669@throws NullPointerException if a DatabaseEntry parameter is null or
670does not contain a required non-null byte array.
671<p>
672@throws DeadlockException if the operation was selected to resolve a
673deadlock.
674<p>
675@throws IllegalArgumentException if an invalid parameter was specified.
676<p>
677@throws DatabaseException if a failure occurs.
678<p>
679@param key the  key
680used as input.  It must be initialized with a non-null byte array by the
681caller.
682@param data the  data
683used as input.  It must be initialized with a non-null byte array by the
684caller.
685@param lockMode the locking attributes; if null, default attributes are used.
686@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
687found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
688    */
689    public OperationStatus getSearchBoth(final DatabaseEntry key,
690                                         final DatabaseEntry data,
691                                         LockMode lockMode)
692        throws DatabaseException {
693
694        return OperationStatus.fromInt(
695            dbc.get(key, data, DbConstants.DB_GET_BOTH |
696                LockMode.getFlag(lockMode) |
697                ((data == null) ? 0 : data.getMultiFlag())));
698    }
699
700    /**
701    Move the cursor to the specified key and closest matching data item of the
702database.
703<p>
704In the case of any database supporting sorted duplicate sets, the returned
705key/data pair is for the smallest data item greater than or equal to the
706specified data item (as determined by the duplicate comparison function),
707permitting partial matches and range searches in duplicate data sets.
708<p>
709If this method fails for any reason, the position of the cursor will be
710unchanged.
711@throws NullPointerException if a DatabaseEntry parameter is null or
712does not contain a required non-null byte array.
713<p>
714@throws DeadlockException if the operation was selected to resolve a
715deadlock.
716<p>
717@throws IllegalArgumentException if an invalid parameter was specified.
718<p>
719@throws DatabaseException if a failure occurs.
720<p>
721@param key the  key
722used as input and returned as output.  It must be initialized with a non-null
723byte array by the caller.
724@param data the  data
725used as input and returned as output.  It must be initialized with a non-null
726byte array by the caller.
727@param lockMode the locking attributes; if null, default attributes are used.
728@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
729found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
730    */
731    public OperationStatus getSearchBothRange(final DatabaseEntry key,
732                                              final DatabaseEntry data,
733                                              LockMode lockMode)
734        throws DatabaseException {
735
736        return OperationStatus.fromInt(
737            dbc.get(key, data,
738                DbConstants.DB_GET_BOTH_RANGE |
739                LockMode.getFlag(lockMode) |
740                ((data == null) ? 0 : data.getMultiFlag())));
741    }
742
743    /**
744    Move the cursor to the specific numbered record of the database, and
745return the associated key/data pair.
746<p>
747The data field of the specified key must be a byte array containing a
748record number, as described in {@link com.sleepycat.db.DatabaseEntry DatabaseEntry}.  This determines
749the record to be retrieved.
750<p>
751For this method to be called, the underlying database must be of type
752Btree, and it must have been configured to support record numbers.
753<p>
754If this method fails for any reason, the position of the cursor will be
755unchanged.
756@throws NullPointerException if a DatabaseEntry parameter is null or
757does not contain a required non-null byte array.
758<p>
759@throws DeadlockException if the operation was selected to resolve a
760deadlock.
761<p>
762@throws IllegalArgumentException if an invalid parameter was specified.
763<p>
764@throws DatabaseException if a failure occurs.
765<p>
766@param key the  key
767returned as output.  Its byte array does not need to be initialized by the
768caller.
769@param data the  data
770returned as output.  Multiple results can be retrieved by passing an object
771that is a subclass of {@link com.sleepycat.db.MultipleEntry MultipleEntry}, otherwise its byte array does not
772need to be initialized by the caller.
773@param lockMode the locking attributes; if null, default attributes are used.
774@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
775found; {@link com.sleepycat.db.OperationStatus#KEYEMPTY OperationStatus.KEYEMPTY} if the database is a Queue or Recno database and the specified key exists, but was never explicitly created by the application or was later deleted; otherwise, {@link com.sleepycat.db.OperationStatus#SUCCESS OperationStatus.SUCCESS}.
776    */
777    public OperationStatus getSearchRecordNumber(final DatabaseEntry key,
778                                                 final DatabaseEntry data,
779                                                 LockMode lockMode)
780        throws DatabaseException {
781
782        return OperationStatus.fromInt(
783            dbc.get(key, data, DbConstants.DB_SET_RECNO |
784                LockMode.getFlag(lockMode) |
785                ((data == null) ? 0 : data.getMultiFlag())));
786    }
787
788    /**
789    Store a key/data pair into the database.
790<p>
791If the put method succeeds, the cursor is always positioned to refer to
792the newly inserted item.  If the put method fails for any reason, the
793state of the cursor will be unchanged.
794<p>
795If the key already appears in the database and duplicates are supported,
796the new data value is inserted at the correct sorted location.  If the
797key already appears in the database and duplicates are not supported,
798the existing key/data pair will be replaced.
799<p>
800@param key the key {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} operated on.
801<p>
802@param data the data {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} stored.
803<p>
804<p>
805@throws DeadlockException if the operation was selected to resolve a
806deadlock.
807<p>
808@throws IllegalArgumentException if an invalid parameter was specified.
809<p>
810@throws DatabaseException if a failure occurs.
811    */
812    public OperationStatus put(final DatabaseEntry key,
813                               final DatabaseEntry data)
814        throws DatabaseException {
815
816        return OperationStatus.fromInt(
817            dbc.put(key, data, DbConstants.DB_KEYLAST));
818    }
819
820    /**
821    Store a key/data pair into the database.
822<p>
823If the putAfter method succeeds, the cursor is always positioned to refer to
824the newly inserted item.  If the putAfter method fails for any reason, the
825state of the cursor will be unchanged.
826<p>
827In the case of the Btree and Hash access methods, insert the data
828element as a duplicate element of the key to which the cursor refers.
829The new element appears immediately
830after
831the current cursor position.  It is an error to call this method if the
832underlying Btree or Hash database does not support duplicate data items.
833The key parameter is ignored.
834<p>
835In the case of the Hash access method, the putAfter method will fail and
836throw an exception if the current cursor record has already been deleted.
837<p>
838In the case of the Recno access method, it is an error to call this
839method if the underlying Recno database was not configured to have
840mutable record numbers.  A new key is created, all records after the
841inserted item are automatically renumbered, and the key of the new
842record is returned in the key parameter.  The initial value of the key
843parameter is ignored.
844<p>
845The putAfter method may not be called for the Queue access method.
846<p>
847@param key the key {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} operated on.
848<p>
849@param data the data {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} stored.
850<p>
851<p>
852@throws DeadlockException if the operation was selected to resolve a
853deadlock.
854<p>
855@throws IllegalArgumentException if an invalid parameter was specified.
856<p>
857@throws DatabaseException if a failure occurs.
858    */
859    public OperationStatus putAfter(final DatabaseEntry key,
860                                    final DatabaseEntry data)
861        throws DatabaseException {
862
863        return OperationStatus.fromInt(
864            dbc.put(key, data, DbConstants.DB_AFTER));
865    }
866
867    /**
868    Store a key/data pair into the database.
869<p>
870If the putBefore method succeeds, the cursor is always positioned to refer to
871the newly inserted item.  If the putBefore method fails for any reason, the
872state of the cursor will be unchanged.
873<p>
874In the case of the Btree and Hash access methods, insert the data
875element as a duplicate element of the key to which the cursor refers.
876The new element appears immediately
877before
878the current cursor position.  It is an error to call this method if the
879underlying Btree or Hash database does not support duplicate data items.
880The key parameter is ignored.
881<p>
882In the case of the Hash access method, the putBefore method will fail and
883throw an exception if the current cursor record has already been deleted.
884<p>
885In the case of the Recno access method, it is an error to call this
886method if the underlying Recno database was not configured to have
887mutable record numbers.  A new key is created, all records after the
888inserted item are automatically renumbered, and the key of the new
889record is returned in the key parameter.  The initial value of the key
890parameter is ignored.
891<p>
892The putBefore method may not be called for the Queue access method.
893<p>
894@param key the key {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} operated on.
895<p>
896@param data the data {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} stored.
897<p>
898<p>
899@throws DeadlockException if the operation was selected to resolve a
900deadlock.
901<p>
902@throws IllegalArgumentException if an invalid parameter was specified.
903<p>
904@throws DatabaseException if a failure occurs.
905    */
906    public OperationStatus putBefore(final DatabaseEntry key,
907                                     final DatabaseEntry data)
908        throws DatabaseException {
909
910        return OperationStatus.fromInt(
911            dbc.put(key, data, DbConstants.DB_BEFORE));
912    }
913
914    /**
915    Store a key/data pair into the database.
916<p>
917If the putNoOverwrite method succeeds, the cursor is always positioned to refer to
918the newly inserted item.  If the putNoOverwrite method fails for any reason, the
919state of the cursor will be unchanged.
920<p>
921If the key already appears in the database, putNoOverwrite will return
922{@link com.sleepycat.db.OperationStatus#KEYEXIST OperationStatus.KEYEXIST}.
923<p>
924@param key the key {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} operated on.
925<p>
926@param data the data {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} stored.
927<p>
928<p>
929@throws DeadlockException if the operation was selected to resolve a
930deadlock.
931<p>
932@throws IllegalArgumentException if an invalid parameter was specified.
933<p>
934@throws DatabaseException if a failure occurs.
935    */
936    public OperationStatus putNoOverwrite(final DatabaseEntry key,
937                                          final DatabaseEntry data)
938        throws DatabaseException {
939
940        /*
941         * The tricks here are making sure the cursor doesn't move on error and
942         * noticing that if the key exists, that's an error and we don't want
943         * to return the data.
944         */
945        Dbc tempDbc = dbc.dup(0);
946        try {
947            int errCode = tempDbc.get(key, DatabaseEntry.IGNORE,
948                DbConstants.DB_SET | database.rmwFlag);
949            if (errCode == 0)
950                return OperationStatus.KEYEXIST;
951            else if (errCode != DbConstants.DB_NOTFOUND &&
952                errCode != DbConstants.DB_KEYEMPTY)
953                return OperationStatus.fromInt(errCode);
954            else {
955                Dbc tdbc = dbc;
956                dbc = tempDbc;
957                tempDbc = tdbc;
958
959                return OperationStatus.fromInt(
960                    dbc.put(key, data, DbConstants.DB_KEYLAST));
961            }
962        } finally {
963            tempDbc.close();
964        }
965    }
966
967    /**
968    Store a key/data pair into the database.
969<p>
970If the putKeyFirst method succeeds, the cursor is always positioned to refer to
971the newly inserted item.  If the putKeyFirst method fails for any reason, the
972state of the cursor will be unchanged.
973<p>
974In the case of the Btree and Hash access methods, insert the specified
975key/data pair into the database.
976<p>
977If the underlying database supports duplicate data items, and if the
978key already exists in the database and a duplicate sort function has
979been specified, the inserted data item is added in its sorted location.
980If the key already exists in the database and no duplicate sort function
981has been specified, the inserted data item is added as the
982first
983of the data items for that key.
984<p>
985The putKeyFirst method may not be called for the Queue or Recno access methods.
986<p>
987@param key the key {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} operated on.
988<p>
989@param data the data {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} stored.
990<p>
991<p>
992@throws DeadlockException if the operation was selected to resolve a
993deadlock.
994<p>
995@throws IllegalArgumentException if an invalid parameter was specified.
996<p>
997@throws DatabaseException if a failure occurs.
998    */
999    public OperationStatus putKeyFirst(final DatabaseEntry key,
1000                                       final DatabaseEntry data)
1001        throws DatabaseException {
1002
1003        return OperationStatus.fromInt(
1004            dbc.put(key, data, DbConstants.DB_KEYFIRST));
1005    }
1006
1007    /**
1008    Store a key/data pair into the database.
1009<p>
1010If the putKeyLast method succeeds, the cursor is always positioned to refer to
1011the newly inserted item.  If the putKeyLast method fails for any reason, the
1012state of the cursor will be unchanged.
1013<p>
1014In the case of the Btree and Hash access methods, insert the specified
1015key/data pair into the database.
1016<p>
1017If the underlying database supports duplicate data items, and if the
1018key already exists in the database and a duplicate sort function has
1019been specified, the inserted data item is added in its sorted location.
1020If the key already exists in the database and no duplicate sort function
1021has been specified, the inserted data item is added as the
1022last
1023of the data items for that key.
1024<p>
1025The putKeyLast method may not be called for the Queue or Recno access methods.
1026<p>
1027@param key the key {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} operated on.
1028<p>
1029@param data the data {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} stored.
1030<p>
1031<p>
1032@throws DeadlockException if the operation was selected to resolve a
1033deadlock.
1034<p>
1035@throws IllegalArgumentException if an invalid parameter was specified.
1036<p>
1037@throws DatabaseException if a failure occurs.
1038    */
1039    public OperationStatus putKeyLast(final DatabaseEntry key,
1040                                      final DatabaseEntry data)
1041        throws DatabaseException {
1042
1043        return OperationStatus.fromInt(
1044            dbc.put(key, data, DbConstants.DB_KEYLAST));
1045    }
1046
1047    /**
1048    Store a key/data pair into the database.
1049<p>
1050If the putNoDupData method succeeds, the cursor is always positioned to refer to
1051the newly inserted item.  If the putNoDupData method fails for any reason, the
1052state of the cursor will be unchanged.
1053<p>
1054In the case of the Btree and Hash access methods, insert
1055the specified key/data pair into the database, unless a key/data pair
1056comparing equally to it already exists in the database.  If a matching
1057key/data pair already exists in the database, {@link com.sleepycat.db.OperationStatus#KEYEXIST OperationStatus.KEYEXIST} is returned.
1058<p>
1059This method may only be called if the underlying database has been
1060configured to support sorted duplicate data items.
1061<p>
1062This method may not be called for the Queue or Recno access methods.
1063<p>
1064@param key the key {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} operated on.
1065<p>
1066@param data the data {@link com.sleepycat.db.DatabaseEntry DatabaseEntry} stored.
1067<p>
1068<p>
1069@throws DeadlockException if the operation was selected to resolve a
1070deadlock.
1071<p>
1072@throws IllegalArgumentException if an invalid parameter was specified.
1073<p>
1074@throws DatabaseException if a failure occurs.
1075    */
1076    public OperationStatus putNoDupData(final DatabaseEntry key,
1077                                        final DatabaseEntry data)
1078        throws DatabaseException {
1079
1080        return OperationStatus.fromInt(
1081            dbc.put(key, data, DbConstants.DB_NODUPDATA));
1082    }
1083
1084    /**
1085    Replaces the data in the key/data pair at the current cursor position.
1086    <p>
1087    Whether the putCurrent method succeeds or fails for any reason, the state
1088    of the cursor will be unchanged.
1089    <p>
1090    Overwrite the data of the key/data pair to which the cursor refers with the
1091    specified data item. This method will return OperationStatus.NOTFOUND if
1092    the cursor currently refers to an already-deleted key/data pair.
1093    <p>
1094    For a database that does not support duplicates, the data may be changed by
1095    this method.  If duplicates are supported, the data may be changed only if
1096    a custom partial comparator is configured and the comparator considers the
1097    old and new data to be equal (that is, the comparator returns zero).  For
1098    more information on partial comparators see {@link
1099    DatabaseConfig#setDuplicateComparator}.
1100    <p>
1101    If the old and new data are unequal according to the comparator, a {@code
1102    DatabaseException} is thrown.  Changing the data in this case would change
1103    the sort order of the record, which would change the cursor position, and
1104    this is not allowed.  To change the sort order of a record, delete it and
1105    then re-insert it.
1106    <p>
1107    @param data - the data DatabaseEntry stored.
1108    <br>
1109    @throws DeadlockException - if the operation was selected to resolve a
1110    deadlock.
1111    <br>
1112    @throws IllegalArgumentException - if an invalid parameter was specified.
1113    <br>
1114    @throws DatabaseException - if the old and new data are not equal according
1115    to the configured duplicate comparator or default comparator, or if a
1116    failure occurs.
1117    <br>
1118    */
1119    public OperationStatus putCurrent(final DatabaseEntry data)
1120        throws DatabaseException {
1121
1122        return OperationStatus.fromInt(
1123            dbc.put(DatabaseEntry.UNUSED, data, DbConstants.DB_CURRENT));
1124    }
1125
1126    /**
1127    Get the cache priority for pages referenced by the cursor.
1128    <p>
1129    This method may be called at any time during the life of the application.
1130    <p>
1131    <p>
1132@throws DatabaseException if a failure occurs.
1133    */
1134    public CacheFilePriority getPriority()
1135        throws DatabaseException {
1136
1137        return CacheFilePriority.fromFlag(dbc.get_priority());
1138    }
1139
1140    /**
1141    Set the cache priority for pages referenced by the DBC handle.
1142    <p>
1143    The priority of a page biases the replacement algorithm to be more or less
1144    likely to discard a page when space is needed in the buffer pool. The bias
1145    is temporary, and pages will eventually be discarded if they are not
1146    referenced again. The DBcursor->set_priority method is only advisory, and
1147    does not guarantee pages will be treated in a specific way.
1148    <p>
1149    This method may be called at any time during the life of the application.
1150    <p>
1151    <p>
1152@throws DatabaseException if a failure occurs.
1153    */
1154    public void setPriority(final CacheFilePriority priority)
1155        throws DatabaseException {
1156
1157        dbc.set_priority(priority.getFlag());
1158    }
1159}
1160