Listing the Documents in a View
Chapter 6-3
Listing the Documents in a View
This chapter examines the sample program VIEWIDS, which prints out a list of all documents in a specified view of a specified database. VIEWIDS demonstrates the use of several data types and functions that you can use to access views.
Data Types
The following two data types relate to collections:
- The HCOLLECTION data type is a handle for an open collection of notes.
- The COLLECTIONPOSITION data structure is used to specify the position of a note in a view.
Functions
C API functions that relate to views use the prefix NIF (Notes Index Facility).
NIFFindView finds the note ID of a view, given the name of the view.
NIFOpenCollection opens a collection associated with the view and database being used. It returns the address of a collection handle (HCOLLECTION) as one of its output parameters.
NIFReadEntries scans a collection referenced by a collection handle (HCOLLECTION). You specify the starting position for the scan, by setting the COLLECTIONPOSITION parameter.
NIFCloseCollection closes the collection, updating data on disk if required and freeing memory allocated to the collection.
The VIEWIDS Sample Program
The sample program VIEWIDS builds a collection from a view and then finds the note IDs of all documents in the collection. The program does not actually read the documents. This section describes fragments of the program that illustrate use of the functions described above.
Example: Get Note ID of the Specified View in VIEWIDS |
char ViewName; / name of the view we'll read /
DBHANDLE hDB; / handle of the database /
NOTEID ViewID; / note id of the view /
/ Get the note id of the view we want. */
if (error = NIFFindView (hDB, ViewName, &ViewID))
{
NSFDbClose (hDB);
text_len=OSLoadString(NULLHANDLE,ERR(error),error_text,sizeof(error_text));
printf("error: %s\n",error_text);
NotesTerm();
return(error);
}
This fragment calls NIFFindView. The inputs to the function are the handle of a database and the name of a view in the database. The output of the function is the note ID of the view. (Remember that views are a type of note.)
Example: Opening a Collection in VIEWIDS |
DBHANDLE hDB; / handle of the database /
NOTEID ViewID; / note id of the view /
HCOLLECTION hCollection; / collection handle /
/ Get a collection using this view. /
if (error = NIFOpenCollection(
hDB, / handle of db with view /
hDB, / handle of db with data /
ViewID, / note id of the view /
0, / collection open flags /
NULLHANDLE, / handle to unread ID list (input and return) /
&hCollection,/ collection handle (return) /
NULLHANDLE, / handle to open view note (return) /
NULL, / universal note id of view (return) /
NULLHANDLE, / handle to collapsed list (return) /
NULLHANDLE)) / handle to selected list (return) /
{
NSFDbClose (hDB);
text_len=OSLoadString(NULLHANDLE,ERR(error),error_text,sizeof(error_text));
printf("error: %s\n",error_text);
NotesTerm();
return(error);
}
This fragment calls the function NIFOpenCollection to open the collection associated with the view that the program is using. The first argument (input) to this function is the handle of the database that contains the view note. The second argument (input) is the handle of the database that contains the data to which the view is applied.
NOTE: When you use the Notes user interface, these two databases always are the same. With the C API, you can apply views from one database to another database. You can take advantage of this feature by using the user interface to create a special database containing views that you need in C API programs. Your C API code can then apply the views in the"view database" to any other database.
The third argument (input) to NIFOpenCollection is the note ID of the view to use. This note ID, of course, is in the database referred to by the first argument; we obtained the view's note ID when we called NIFFindView. The fourth argument (input) is a set of flags that control the way the collection is opened. For more information about these flags, see the Reference. This program uses none of the flags.
The sixth argument (output) to NIFOpenCollection is the handle of the current collection for this view of the database. The collection reflects the data in the database at the moment the call completes.
NOTE: If a database might change while your program is running, use the function NIFUpdateCollection. This function re-synchronizes a collection with the database whenever you call it.
The other arguments to NIFOpenCollection return information about the collection that you may find useful in some programs. For more information about these arguments, see the Reference.
Example: Reading Entries In a Collection in VIEWIDS |
HCOLLECTION hCollection; / collection handle /
COLLECTIONPOSITION CollPosition; / position within collection /
HANDLE hBuffer; / handle to buffer of note ids /
DWORD EntriesFound; / number of entries found /
DWORD NotesFound=0; / number of documents found /
WORD SignalFlag / signal and share warning flags /
/ Set up the data structure, COLLECTIONPOSITION, that controls where in
the collection we will begin when we read the collection. Specify that we
want to start at the beginning. /
CollPosition.Level = 0;
CollPosition.Tumbler[0] = 0;
/ Get a buffer with information about each entry in the collection.
Perform this routine in a loop. Terminate loop when SignalFlag
indicates that there is no more information to get. /
do
{
if ( error = NIFReadEntries(
hCollection, / handle to this collection /
&CollPosition, / where to start in collection /
NAVIGATE_NEXT, / order to use when skipping /
1L, / number to skip /
NAVIGATE_NEXT, / order to use when reading /
0xFFFFFFFF, / max number to read /
READ_MASK_NOTEID, / info we want /
&hBuffer, / handle to info buffer (return) /
NULL, / length of info buffer (return) /
NULL, / entries skipped (return) /
&EntriesFound, / entries read (return) /
&SignalFlag)) / share warning and more signal flag
(return) /
{
NIFCloseCollection (hCollection);
NSFDbClose (hDB);
text_len=OSLoadString(NULLHANDLE,ERR(error),error_text,sizeof(error_text));
printf("error: %s\n",error_text);
NotesTerm();
return(error);
}
The code initializes the COLLECTIONPOSITION structure to the beginning of the collection. For structure operations other than initialization, such as sets and reads, use the C API functions explained below.
After initializing COLLECTIONPOSITION, the program calls NIFReadEntries, which reads a collection and returns information from it. The first argument (input) to this function is the handle of the collection, obtained through the call to NIFOpenCollection. The second argument (input) is a COLLECTIONPOSITION, which points to the location in the collection where NIFReadEntries starts its actions.
From this starting point, NIFReadEntries operates in two phases. First, the function skips some number of entries in the collection, based on your instructions contained in the third and fourth arguments (both inputs). The third argument is the manner in which to navigate the collection tree while skipping entries, and the fourth argument is the number of entries to skip. For information about the flags that can appear in the third argument, see NAVIGATE_FLAG in the Reference. As the function skips entries, the COLLECTIONPOSITION structure changes to indicate the skipping.
In the example code, when NIFReadEntries is called for the first time, the second argument means, "Start at the beginning, before the first entry"; the third argument means, "Go to the next entry as indicated by the skip count"; and the fourth argument means, "Skip one." After the skipping phase, the COLLECTIONPOSITION points to the first entry in the collection.
In its second phase, NIFReadEntries reads some number of entries in the collection and returns information about them. The fifth, sixth, and seventh arguments (all inputs) control the manner in which NIFReadEntries does this. The fifth argument specifies how to navigate the collection tree while reading entries. The sixth argument is the number of entries to read. The seventh argument is the information to return about each entry read. The reading phase begins at the COLLECTIONPOSITION set by the skipping phase.
In the example code, the fifth argument means, "Find the next entry using a pre-order (node-left-right) scan of the collection tree." This reads the collection just as it is displayed by the Notes user interface. The sixth argument means, "Find as many entries as possible." The seventh argument specifies that the note ID of each entry be returned. For information about the flags you can specify in the seventh argument, see READ_MASK_XXX in the Reference.
Based on these settings for arguments three through seven, NIFReadEntries reads each entry in the collection and returns its note ID in the same order as the notes appear in the view at the user interface.
NOTE: While navigating a collection, NIFReadEntries treats all objects in the tree identically, skipping and reading categories, documents, and responses in the same way.
The eighth argument (output) to NIFReadEntries is a handle to the buffer of information that the function returns. In this example, the buffer contains note IDs. As in the example, your programs should check that a valid handle is returned and exit if it is a NULLHANDLE, signifying that no data buffer exists. The eleventh argument (output) is the number of entries read.
The ninth and tenth arguments to NIFReadEntries return other information that you may find useful in your programs. For more information about these arguments, see the Reference.
The twelfth argument returns a set of flags indicating whether there is more information than can fit in the returned buffer and/or whether the collection has changed since it was last read. The example code calls NIFReadEntries repeatedly in a loop until the SIGNAL_MORE_TO_DO bit is cleared in this parameter, to ensure that it obtains information about all the notes in a collection. When NIFReadEntries is about to be called again, the COLLECTION position points to the last entry read in the previous call. Using NAVIGATE_NEXT for the skip navigate flag (the third parameter) and 1L for the skip count (the fourth parameter) properly updates the COLLECTION position to point to the next entry. For more information about these arguments, see the Reference.
Example: Parsing the Buffer Returned by NIFReadEntries in VIEWIDS |
HANDLE hBuffer; / handle to buffer of note ids /
NOTEID IdList; / pointer to a note id /
/ Lock down (freeze the location of) the buffer of entry IDs. Cast
the resulting pointer to the type we need. /
IdList = (NOTEID ) OSLockObject (hBuffer);
/ Print out the list of note IDs found by this search. Don't print a note
ID if it is a "dummy" ID that stands for a category in the collection. /
printf ("\n");
for (i=0; i<EntriesFound; i++)
{
if (NOTEID_CATEGORY & IdList[i]) continue;
printf ("Note count is %lu. \t Note ID is: %lX\n",
++NotesFound, IdList[i]);
}
/ Unlock the list of IDs. /
OSUnlockObject (hBuffer);
/ Free the memory allocated by NIFReadEntries. /
OSMemFree (hBuffer);
/ Loop if the end of the collection has not been reached because the buffer
was full. /
} while (SignalFlag & SIGNAL_MORE_TO_DO);
This code calls OSLockObject to lock the memory location of the returned note ID buffer and cast the resulting locked pointer to the type of data in the buffer, then prints out all the note IDs in the buffer. If the view uses categories, there will be a category entry in the buffer at each place that a category heading appears in the collection. The code tests for these category entries so they are not printed along with the note IDs.
The code then unlocks and frees the buffer allocated by NIFReadEntries and closes the collection, because a program must close every resource that it opens. Although we don't show it here, the program should close the database properly.