summaryrefslogtreecommitdiff
path: root/lang/java/src/com/sleepycat/db/JoinCursor.java
blob: 60ae53c66e185a0d4fad0d100e76342610bed416 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 2002, 2015 Oracle and/or its affiliates.  All rights reserved.
 *
 * $Id$
 */

package com.sleepycat.db;

import com.sleepycat.db.internal.DbConstants;
import com.sleepycat.db.internal.Dbc;

/**
A specialized join cursor for use in performing equality or natural joins on
secondary indices.
<p>
A join cursor is returned when calling {@link Database#join Database.join}.
<p>
To open a join cursor using two secondary cursors:
<pre>
    Transaction txn = ...
    Database primaryDb = ...
    SecondaryDatabase secondaryDb1 = ...
    SecondaryDatabase secondaryDb2 = ...
    <p>
    SecondaryCursor cursor1 = null;
    SecondaryCursor cursor2 = null;
    JoinCursor joinCursor = null;
    try {
        DatabaseEntry key = new DatabaseEntry();
        DatabaseEntry data = new DatabaseEntry();
        <p>
        cursor1 = secondaryDb1.openSecondaryCursor(txn, null);
        cursor2 = secondaryDb2.openSecondaryCursor(txn, null);
        <p>
        key.setData(...); // initialize key for secondary index 1
        OperationStatus status1 =
        cursor1.getSearchKey(key, data, LockMode.DEFAULT);
        key.setData(...); // initialize key for secondary index 2
        OperationStatus status2 =
        cursor2.getSearchKey(key, data, LockMode.DEFAULT);
        <p>
        if (status1 == OperationStatus.SUCCESS &amp;&amp;
                status2 == OperationStatus.SUCCESS) {
            <p>
            SecondaryCursor[] cursors = {cursor1, cursor2};
            joinCursor = primaryDb.join(cursors, null);
            <p>
            while (true) {
                OperationStatus joinStatus = joinCursor.getNext(key, data,
                    LockMode.DEFAULT);
                if (joinStatus == OperationStatus.SUCCESS) {
                     // Do something with the key and data.
                } else {
                    break;
                }
            }
        }
    } finally {
        if (cursor1 != null) {
            cursor1.close();
        }
        if (cursor2 != null) {
            cursor2.close();
        }
        if (joinCursor != null) {
            joinCursor.close();
        }
    }
</pre>
*/
public class JoinCursor {
    private Database database;
    private Dbc dbc;
    private JoinConfig config;

    JoinCursor(final Database database,
               final Dbc dbc,
               final JoinConfig config) {
        this.database = database;
        this.dbc = dbc;
        this.config = config;
    }

    /**
    Closes the cursors that have been opened by this join cursor.
    <p>
    The cursors passed to {@link Database#join Database.join} are not closed
    by this method, and should be closed by the caller.
    <p>
    <p>
@throws DatabaseException if a failure occurs.
    */
    public void close()
        throws DatabaseException {

        dbc.close();
    }

    /**
    Returns the primary database handle associated with this cursor.
    <p>
    @return the primary database handle associated with this cursor.
    */
    public Database getDatabase() {
        return database;
    }

    /**
    Returns this object's configuration.
    <p>
    @return this object's configuration.
    */
    public JoinConfig getConfig() {
        return config;
    }

    /**
    Returns the next primary key resulting from the join operation.
<p>
An entry is returned by the join cursor for each primary key/data pair having
all secondary key values that were specified using the array of secondary
cursors passed to {@link Database#join Database.join}.
<p>
@param key the primary key
returned as output.  Its byte array does not need to be initialized by the
caller.
<p>
@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
found; {@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}.
<p>
@param lockMode the locking attributes; if null, default attributes are used.
<p>
@throws NullPointerException if a DatabaseEntry parameter is null or
does not contain a required non-null byte array.
<p>
@throws DeadlockException if the operation was selected to resolve a
deadlock.
<p>
@throws IllegalArgumentException if an invalid parameter was specified.
<p>
@throws DatabaseException if a failure occurs.
    */
    public OperationStatus getNext(final DatabaseEntry key, LockMode lockMode)
        throws DatabaseException {

        return OperationStatus.fromInt(
            dbc.get(key, DatabaseEntry.IGNORE,
                DbConstants.DB_JOIN_ITEM |
                LockMode.getFlag(lockMode)));
    }

    /**
    Returns the next primary key and data resulting from the join operation.
<p>
An entry is returned by the join cursor for each primary key/data pair having
all secondary key values that were specified using the array of secondary
cursors passed to {@link Database#join Database.join}.
<p>
@param key the primary key
returned as output.  Its byte array does not need to be initialized by the
caller.
<p>
@param data the primary data
returned as output.  Its byte array does not need to be initialized by the
caller.
<p>
@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is
found; {@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}.
<p>
@param lockMode the locking attributes; if null, default attributes are used.
<p>
@throws NullPointerException if a DatabaseEntry parameter is null or
does not contain a required non-null byte array.
<p>
@throws DeadlockException if the operation was selected to resolve a
deadlock.
<p>
@throws IllegalArgumentException if an invalid parameter was specified.
<p>
@throws DatabaseException if a failure occurs.
    */
    public OperationStatus getNext(final DatabaseEntry key,
                                   final DatabaseEntry data,
                                   LockMode lockMode)
        throws DatabaseException {

        return OperationStatus.fromInt(
            dbc.get(key, data, LockMode.getFlag(lockMode) |
                ((data == null) ? 0 : data.getMultiFlag())));
    }
}