About Cursor Positions and Extent

A Cursor has one or more positions. The current position of a Cursor is the position that is currently active in the Cursor. To move the current position of a Cursor call the setPosition or next methods on the Cursor.

Oracle OLAP does not validate the position that you set on the Cursor until you attempt an operation on the Cursor, such as calling the getCurrentValue method. If you set the current position to a negative value or to a value that is greater than the number of positions in the Cursor and then attempt a Cursor operation, the Cursor throws a PositionOutOfBoundsException.

Positions of a ValueCursor

The current position of a ValueCursor specifies a value, which you can retrieve. For example, productSel, a derived Source described in "Structure of a Cursor", is a selection of three products from a primary Source that specifies a dimension of products and their hierarchical groupings. The ValueCursor for productSel has three elements. The following example gets the position of each element of the ValueCursor, and displays the value at that position. The output object is a PrintWriter.

For more examples of getting the current value of a ValueCursor, see Chapter 9.

Positions of a CompoundCursor

A CompoundCursor has one position for each set of the elements of its descendent ValueCursor objects. The current position of the CompoundCursor specifies one of those sets.

For example, unitPriceByDay, the Source described in "Structure of a Cursor", has values from a measure, unitPrice. The values are the prices of product units at different times. The outputs of unitPriceByDay are Source objects that represent selections of four day values from a time dimension and three product values from a product dimension.

The result set for unitPriceByDay has one measure value for each tuple (each set of output values), so the total number of values is twelve (one value for each of the three products for each of the four days). Therefore, the queryCursorCompoundCursor created for unitPriceByDay has twelve positions.

Each position of queryCursor specifies one set of positions of its outputs and its base ValueCursor. For example, position 1 of queryCursor defines the following set of positions for its outputs and its base ValueCursor:

Position 1 of output 1 (the ValueCursor for timeSel)

Position 1 of output 2 (the ValueCursor for productSel)

Position 1 of the base ValueCursor for queryCursor (This position has the value from the unitPrice measure that is specified by the values of the outputs.)

Figure 8-4 illustrates the positions of queryCursorCompoundCursor, its base ValueCursor, and its outputs.

Figure 8-4 Cursor Positions in queryCursor

The ValueCursor for queryCursor has only one position because only one value of unitPrice is specified by any one set of values of the outputs. For a query like unitPriceByDay, the ValueCursor of its Cursor has only one value, and therefore only one position, at a time for any one position of the root CompoundCursor.

The following table illustrates one possible display of the data from queryCursor. It is a crosstab view with four columns and five rows. In the left column are the day values. In the top row are the product values. In each of the intersecting cells of the crosstab is the price of the product on the day.

A CompoundCursor coordinates the positions of its ValueCursor objects relative to each other. The current position of the CompoundCursor specifies the current positions of its descendent ValueCursor objects. Example 8-1 sets the position of queryCursor and then gets the current values and the positions of the child Cursor objects.

Example 8-1 Setting the CompoundCursor Position and Getting the Current Values

The positions of queryCursor are symmetric in that the result set for unitPriceByDay always has three product values for each time value. The ValueCursor for productSel, therefore, always has three positions for each value of the timeSelValueCursor. The timeSel output ValueCursor is slower varying than the productSelValueCursor.

In an asymmetric case, however, the number of positions in a ValueCursor is not always the same relative to its slower varying output. For example, if the price of units for product 2055 on October 1, 2000 were null because that product was no longer being purchased by that date, and if null values were suppressed in the query, then queryCursor would only have eleven positions. The ValueCursor for productSel would only have two positions when the position of the ValueCursor for timeSel was 4.

Example 8-2 produces an asymmetric result set by using a revision of the query from "Structure of a Cursor". The result set of the revised query specifies products by price on a day. The base values of productByPriceOnDay are the values from productSel as specified by the values of unitPrice and timeSel.

Because productByPriceOnDay is a derived Source, this example prepares and commits the current Transaction. The TransactionProvider in the example is tp. For information on Transaction objects, see Chapter 7.

The example creates a Cursor for productByPriceOnDay, loops through the positions of the CompoundCursor, gets the position and current value of each child ValueCursor object, and displays the positions and values.

The ValueCursor with unitPrice values (output 2) has only two positions for 01-JAN-00 and 01-JUL-00 because it has only two different values for those days. The prices of two of the products are the same on those two days: 24 for products 1050 and 2055 on January 1, 2000 and 25 for those same two products on July 1, 2000. The base ValueCursor for queryCursor2 has two positions when the timeSel value is 01-JAN-00 or 01-JUL-00 because each of the unitPrice values for those days is not unique.

About the Parent Starting and Ending Positions in a Cursor

To effectively manage the display of the data that you get from a CompoundCursor, you sometimes need to know how many faster varying values exist for the current slower varying value. For example, suppose that you are displaying in a crosstab one row of values from an edge of a cube, then you might want to know how many columns to draw in the display for the row.

To determine how many faster varying values exist for the current value of a child Cursor, you find the starting and ending positions of that current value in the parent Cursor. Subtract the starting position from the ending position and then add 1, as in the following.

long span = (cursor.getParentEnd() - cursor.getParentStart()) + 1;

The result is the span of the current value of the child Cursor in its parent Cursor, which tells you how many values of the fastest varying child Cursor exist for the current value. Calculating the starting and ending positions is costly in time and computing resources, so you should only specify that you want those calculations performed when your application needs the information.

An Oracle OLAP API Cursor enables your application to have only the data that it is currently displaying actually present on the client computer. For information on specifying the amount of data for a Cursor, see "About Fetch Sizes and Fetch Blocks".

From the data on the client computer, however, you cannot determine at what position of its parent Cursor the current value of a child Cursor begins or ends. To get that information, you use the getParentStart and getParentEnd methods of a Cursor.

For example, suppose your application has a Source named cube that represents a cube that has an asymmetric edge. The cube has four outputs. The cubeSource defines products with sales amounts greater than $5,000 purchased by customers in certain cities during the first three months of the calendar year 2000. The products were sold through the direct sales channel (S) during a television promotion (TV).

You create a Cursor for that Source and call it cubeCursor. The CompoundCursorcubeCursor has the following child Cursor objects:

output 1, a ValueCursor for the promotion values

output 2, a ValueCursor for the channel values

output 3, a ValueCursor for the time values

output 4, a ValueCursor for the customer values

The base ValueCursor, which has values that are the products with sales amounts over $5,000.

Figure 8-5 illustrates the parent, cubeCursor, with the values of its child Cursor objects layered horizontally. The slowest varying output, with the promotion values, is at the top and the fastest varying child, with the product values, is at the bottom. The only portion of the edge that you are currently displaying in the user interface is the block between positions 7 and 9 of cubeCursor, which is shown within the bold border. The positions, 1 through 10, of cubeCursor appear above the top row.

Figure 8-5 Values of ValueCursor Children of cubeCursor

The current value of the output ValueCursor for the time Source is 2000-02. You cannot determine from the data within the block that the starting and ending positions of the current value, 2000-02, in the parent, cubeCursor, are 4 and 7, respectively.

The cubeCursor from the previous figure is shown again in Figure 8-6, this time with the range of the positions of the parent, cubeCursor, for each of the values of the child Cursor objects. By subtracting the smaller value from the larger value and adding one, you can compute the span of each value. For example, the span of the time value 2000-02 is (7 - 4 + 1) = 4.

Figure 8-6 The Range of Positions of the Child Cursor Objects of cubeCursor

To specify that you want Oracle OLAP to calculate the starting and ending positions of a value of a child Cursor in its parent Cursor, call the setParentStartCalculationSpecified and setParentEndCalculationSpecified methods on the CursorSpecification corresponding to the Cursor. You can determine whether calculating the starting or ending positions is specified by calling the isParentStartCalculationSpecified or isParentEndCalculationSpecified methods on the CursorSpecification. For an example of specifying these calculations, see Chapter 9.

What is the Extent of a Cursor?

The extent of a Cursor is the total number of elements it contains relative to any slower varying outputs. Figure 8-7 illustrates the number of positions of each child Cursor of cubeCursor relative to the value of its slower varying output. The child Cursor objects are layered horizontally with the slowest varying output at the top.

The total number of elements in cubeCursor is 10 so the extent of cubeCursor is therefore 10. That number is above the top row of the figure. The top row is the ValueCursor for the promotion value and the next row down is the ValueCursor for the channel value. The extent of each of those ValueCursor objects is 1 because they each have only one value.

The third row down represents the time values. Its extent is 3, since there are 3 months values. The next row down is the ValueCursor for the customers by city. The extent of its elements depends on the value of the slower varying output, which is time. The extent of the customers ValueCursor for the first month is 2, for the second month it is 3, and for the third month it is 2.

The bottom row is the base ValueCursor for the cubeCursorCompoundCursor. Its values are products. The extent of the elements of the products ValueCursor depends on the values of the customers ValueCursor and the time ValueCursor. For example, since two products values are specified by the first set of month and city values (1050 and 2055 for Bonn in 2000-01), the extent of the products ValueCursor for that set is 2. For the second set of values for customers and times (2000-10, London), the extent of the products ValueCursor is 1, and so on.

Figure 8-7 The Number of Elements of the Child Cursor Objects of cubeCursor

The extent is information that you can use, for example, to display the correct number of columns or correctly-sized scroll bars. The extent, however, can be expensive to calculate. For example, a Source that represents a cube might have four outputs. Each output might have hundreds of values. If all null values and zero values of the measure for the sets of outputs are eliminated from the result set, then to calculate the extent of the CompoundCursor for the Source, Oracle OLAP must traverse the entire result space before it creates the CompoundCursor. If you do not specify that you wants the extent calculated, then Oracle OLAP only needs to traverse the sets of elements defined by the outputs of the cube as specified by the fetch size of the Cursor and as needed by your application.

To specify that you want Oracle OLAP to calculate the extent for a Cursor, call the setExtentCalculationSpecified method on the CursorSpecification corresponding to the Cursor. You can determine whether calculating the extent is specified by calling the isExtentCalculationSpecified method on the CursorSpecification. For an example of specifying the calculation of the extent of a Cursor, see Chapter 9.