1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9package com.sleepycat.db; 10 11import com.sleepycat.db.internal.DbConstants; 12import com.sleepycat.db.internal.Dbc; 13 14/** 15A specialized join cursor for use in performing equality or natural joins on 16secondary indices. 17<p> 18A join cursor is returned when calling {@link Database#join Database.join}. 19<p> 20To open a join cursor using two secondary cursors: 21<pre> 22 Transaction txn = ... 23 Database primaryDb = ... 24 SecondaryDatabase secondaryDb1 = ... 25 SecondaryDatabase secondaryDb2 = ... 26 <p> 27 SecondaryCursor cursor1 = null; 28 SecondaryCursor cursor2 = null; 29 JoinCursor joinCursor = null; 30 try { 31 DatabaseEntry key = new DatabaseEntry(); 32 DatabaseEntry data = new DatabaseEntry(); 33 <p> 34 cursor1 = secondaryDb1.openSecondaryCursor(txn, null); 35 cursor2 = secondaryDb2.openSecondaryCursor(txn, null); 36 <p> 37 key.setData(...); // initialize key for secondary index 1 38 OperationStatus status1 = 39 cursor1.getSearchKey(key, data, LockMode.DEFAULT); 40 key.setData(...); // initialize key for secondary index 2 41 OperationStatus status2 = 42 cursor2.getSearchKey(key, data, LockMode.DEFAULT); 43 <p> 44 if (status1 == OperationStatus.SUCCESS && 45 status2 == OperationStatus.SUCCESS) { 46 <p> 47 SecondaryCursor[] cursors = {cursor1, cursor2}; 48 joinCursor = primaryDb.join(cursors, null); 49 <p> 50 while (true) { 51 OperationStatus joinStatus = joinCursor.getNext(key, data, 52 LockMode.DEFAULT); 53 if (joinStatus == OperationStatus.SUCCESS) { 54 // Do something with the key and data. 55 } else { 56 break; 57 } 58 } 59 } 60 } finally { 61 if (cursor1 != null) { 62 cursor1.close(); 63 } 64 if (cursor2 != null) { 65 cursor2.close(); 66 } 67 if (joinCursor != null) { 68 joinCursor.close(); 69 } 70 } 71</pre> 72*/ 73public class JoinCursor { 74 private Database database; 75 private Dbc dbc; 76 private JoinConfig config; 77 78 JoinCursor(final Database database, 79 final Dbc dbc, 80 final JoinConfig config) { 81 this.database = database; 82 this.dbc = dbc; 83 this.config = config; 84 } 85 86 /** 87 Closes the cursors that have been opened by this join cursor. 88 <p> 89 The cursors passed to {@link Database#join Database.join} are not closed 90 by this method, and should be closed by the caller. 91 <p> 92 <p> 93@throws DatabaseException if a failure occurs. 94 */ 95 public void close() 96 throws DatabaseException { 97 98 dbc.close(); 99 } 100 101 /** 102 Returns the primary database handle associated with this cursor. 103 <p> 104 @return the primary database handle associated with this cursor. 105 */ 106 public Database getDatabase() { 107 return database; 108 } 109 110 /** 111 Returns this object's configuration. 112 <p> 113 @return this object's configuration. 114 */ 115 public JoinConfig getConfig() { 116 return config; 117 } 118 119 /** 120 Returns the next primary key resulting from the join operation. 121<p> 122An entry is returned by the join cursor for each primary key/data pair having 123all secondary key values that were specified using the array of secondary 124cursors passed to {@link Database#join Database.join}. 125<p> 126@param key the primary key 127returned as output. Its byte array does not need to be initialized by the 128caller. 129<p> 130@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is 131found; {@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}. 132<p> 133@param lockMode the locking attributes; if null, default attributes are used. 134<p> 135@throws NullPointerException if a DatabaseEntry parameter is null or 136does not contain a required non-null byte array. 137<p> 138@throws DeadlockException if the operation was selected to resolve a 139deadlock. 140<p> 141@throws IllegalArgumentException if an invalid parameter was specified. 142<p> 143@throws DatabaseException if a failure occurs. 144 */ 145 public OperationStatus getNext(final DatabaseEntry key, LockMode lockMode) 146 throws DatabaseException { 147 148 return OperationStatus.fromInt( 149 dbc.get(key, DatabaseEntry.IGNORE, 150 DbConstants.DB_JOIN_ITEM | 151 LockMode.getFlag(lockMode))); 152 } 153 154 /** 155 Returns the next primary key and data resulting from the join operation. 156<p> 157An entry is returned by the join cursor for each primary key/data pair having 158all secondary key values that were specified using the array of secondary 159cursors passed to {@link Database#join Database.join}. 160<p> 161@param key the primary key 162returned as output. Its byte array does not need to be initialized by the 163caller. 164<p> 165@param data the primary data 166returned as output. Its byte array does not need to be initialized by the 167caller. 168<p> 169@return {@link com.sleepycat.db.OperationStatus#NOTFOUND OperationStatus.NOTFOUND} if no matching key/data pair is 170found; {@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}. 171<p> 172@param lockMode the locking attributes; if null, default attributes are used. 173<p> 174@throws NullPointerException if a DatabaseEntry parameter is null or 175does not contain a required non-null byte array. 176<p> 177@throws DeadlockException if the operation was selected to resolve a 178deadlock. 179<p> 180@throws IllegalArgumentException if an invalid parameter was specified. 181<p> 182@throws DatabaseException if a failure occurs. 183 */ 184 public OperationStatus getNext(final DatabaseEntry key, 185 final DatabaseEntry data, 186 LockMode lockMode) 187 throws DatabaseException { 188 189 return OperationStatus.fromInt( 190 dbc.get(key, data, LockMode.getFlag(lockMode) | 191 ((data == null) ? 0 : data.getMultiFlag()))); 192 } 193} 194