RecordsetCursor class: Difference between revisions
m (→Cursor state) |
mNo edit summary |
||
(11 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
<!-- RecordsetCursor class --> | <!-- RecordsetCursor class --> | ||
You can loop on the records in a Recordset or SortedRecordset object | You can loop on the records in a <var>[[Recordset class|Recordset]]</var> or <var>[[SortedRecordset class|SortedRecordset ]]</var> object | ||
using the traditional User Language | using the traditional <var class="product">User Language</var> <var>For Each Record</var> loop construct, as | ||
described in the preceding sections for those objects. | described in the preceding sections for those objects. | ||
However, it can be | However, it can be convenient to advance through a record set and access its records | ||
convenient to advance through a record set and access its records | |||
outside the context of a single record loop. | outside the context of a single record loop. | ||
The [[Janus SOAP]] RecordsetCursor object | The <var class="product">[[Janus SOAP]]</var> <var>RecordsetCursor</var> object | ||
gives you this additional capability for both Recordset and | gives you this additional capability for both <var>Recordset</var> and <var>SortedRecordset</var> objects. | ||
SortedRecordset objects. | Essentially, a <var>RecordsetCursor</var> is a position marker in a record set. | ||
Essentially, a RecordsetCursor is a position | A cursor can be used to access the record at its position, or the cursor can be moved to a new position. | ||
marker in a record set. | |||
A cursor can be used to access the record at | |||
its position, or the cursor can be moved to a new position | |||
==Cursor state== | ==Cursor state== | ||
A <var>RecordSetCursor</var> can be in various states as it navigates a record | A <var>RecordSetCursor</var> can be in various states as it navigates a record set: | ||
set | |||
<dl> | <dl> | ||
<dt>BeforeStart | <dt>BeforeStart | ||
Line 27: | Line 20: | ||
<dd>The cursor points to a record that is available for | <dd>The cursor points to a record that is available for | ||
processing. | processing. | ||
<dt>AfterEnd | <dt>AfterEnd | ||
<dd>The cursor is positioned after the last record in | <dd>The cursor is positioned after the last record in | ||
the set. | the set. | ||
<dt>NoRecord | <dt>NoRecord | ||
<dd>The cursor ''had'' a | <dd>The cursor ''had'' a | ||
valid position identifying a record in a record set, but a subsequent operation | valid position identifying a record in a record set, but a subsequent operation | ||
( | (a <var>Recordset</var> <var>[[Clear (Recordset subroutine)|Clear]]</var> or <var>[[RemoveRecord (Recordset subroutine)|RemoveRecord]]</var> method) removed the | ||
record from the underlying <var>Recordset</var>. | record from the underlying <var>Recordset</var>. | ||
<dt>Empty | <dt>Empty | ||
<dd>The cursor points to an empty record set. | <dd>The cursor points to an empty record set. | ||
Line 41: | Line 36: | ||
</dl> | </dl> | ||
These cursor states are the values returned by the <var>CursorState</var> [[Enumerations|enumeration]]: | |||
<p class="code"> %state is enumeration CursorState | <p class="code">%state is enumeration CursorState | ||
</p> | </p> | ||
'''Note:''' As with all enumerations, | '''Note:''' As with all enumerations, the <var>ToString</var> method implicitly converts an enumeration value to a character string whose value is the name of the enumeration value. For more information about methods available to all enumerations, see [[Enumerations#Common enumeration methods|Common enumeration methods]]. | ||
The RecordsetCursor | The <var>RecordsetCursor</var> read-only property <var>[[State (RecordsetCursor function)|State]]</var> returns a <var>CursorState</var> enumeration that indicates the current state of the cursor. | ||
current state of the cursor. | |||
Any method that repositions the cursor returns | Any method that repositions the cursor returns | ||
a CursorState enumeration that indicates the new state of the cursor | a <var>CursorState</var> enumeration that indicates the new state of the cursor | ||
after the completion of the operation performed by the method. | after the completion of the operation performed by the method. | ||
==Declaration and instantiation== | ==Declaration and instantiation== | ||
A RecordsetCursor is declared like any other file or group context | A <var>RecordsetCursor</var> is declared like any other file or group context | ||
based object. | based object. | ||
For example: | For example: | ||
<p class="code"> %myCurs1 is object RecordsetCursor in file ftptest | <p class="code">%myCurs1 is object RecordsetCursor in file ftptest | ||
%myCurs2 is object RecordsetCursor in group foo | |||
</p> | </p> | ||
Prior to version 7.6 of the <var class="product">Sirius Mods</var>, the RecordsetCursor class | Prior to version 7.6 of the <var class="product">Sirius Mods</var>, the <var>RecordsetCursor</var> class | ||
contained no native constructor methods, and | contained no native constructor methods, and | ||
the way to instantiate a RecordsetCursor object is to use | the way to instantiate a <var>RecordsetCursor</var> object is to use | ||
the Cursor method provided by | the <var>Cursor</var> method provided by both the <var>Recordset</var> and <var>SortedRecordset</var> classes. | ||
both the Recordset and SortedRecordset classes. | In version 7.6, the <var>RecordsetCursor</var> <var>New</var> method was added, | ||
In version 7.6, the RecordsetCursor New method was added, | primarily to enable the creation of extension classes of the <var>RecordsetCursor</var> class, which the <var>Cursor</var> constructor | ||
primarily to enable the creation of extension classes of | |||
the RecordsetCursor class, which the Cursor constructor | |||
cannot do. | cannot do. | ||
Instantiation by the Cursor and New methods is described below. | Instantiation by the <var>Cursor</var> and <var>New</var> methods is described below. | ||
<ul> | <ul> | ||
<li>The Cursor method instantiates a RecordsetCursor for a | <li>The <var>Cursor</var> method instantiates a <var>RecordsetCursor</var> for a | ||
particular instance of a Recordset or SortedRecordset object. | particular instance of a <var>Recordset</var> or <var>SortedRecordset</var> object. | ||
The method takes no arguments. | The method takes no arguments. | ||
If the set has at least | If the set has at least one record, <var>Cursor</var> instantiates an instance of the <var>RecordsetCursor</var> object. | ||
one record, Cursor instantiates an instance of the RecordsetCursor object. | If <var>Cursor</var> is called on a set that "isEmpty" (0 records), it | ||
If Cursor is called on a set that | returns a <var>Null</var> object. | ||
returns a Null object. | |||
Here is a small syntax example: | Here is a small syntax example: | ||
<p class="code"> %rs is object recordSet in file stooges | <p class="code">%rs is object recordSet in file stooges | ||
%srs is object SortedRecordset in file stooges | |||
%myCursor1 is object RecordsetCursor in file stooges | |||
%myCursor2 is object RecordsetCursor in file stooges | |||
... | |||
fd to %rs | |||
end find | |||
... | |||
sort records in %rs to %srs by name | |||
... | |||
%myCursor1 = %rs:Cursor | |||
%myCursor2 = %srs:Cursor | |||
</p> | </p> | ||
<li>Since a RecordsetCursor references a Recordset or SortedRecordset object | |||
and may have a LoopLockStrength, the RecordsetCursor < | <li>Since a <var>RecordsetCursor</var> references a <var>Recordset</var> or <var>SortedRecordset</var> object | ||
and may have a <var>LoopLockStrength</var>, the <var>RecordsetCursor</var> <var>[[New (RecordsetCursor constructor)|New]]</var> | |||
constructor is of this form: | constructor is of this form: | ||
<p class=" | <p class="syntax">%(<span class="literal">RecordsetCursor</span>):<span class="literal">New</span>(<span class="term">recset</span> <span class="squareb">[</span>, <span class="literal">LoopLockStrength</span>=<span class="term">lls</span><span class="squareb">]</span>) | ||
</p> | </p> | ||
Where: | Where: | ||
<dl> | <dl> | ||
<dt><recset> | <dt><i>recset</i> | ||
<dd>A required Recordset or SortedRecordset object. | <dd>A required <var>Recordset</var> or <var>SortedRecordset</var> object. | ||
<dt><lls> | |||
<dd>A LockStrength enumeration setting the minimum lock strength for a record | <dt><i>lls</i> | ||
in a For Record At loop on a RecordsetCursor object. | <dd>A <var>LockStrength</var> enumeration setting the minimum lock strength for a record | ||
This argument is only valid if < | in a <var>For Record At</var> loop on a <var>RecordsetCursor</var> object. | ||
SortedRecordset object. | This argument is only valid if <var class="term">recset</var> is a <var>SortedRecordset</var> object. | ||
</dl> | </dl> | ||
'''Note:''' | '''Note:''' | ||
If < | If <var class="term">recset</var> is empty, <var>New</var> returns a <var>RecordsetCursor</var> | ||
object with the state < | object with the state <var>Empty</var>. | ||
This is different from the Cursor methods instantiation, | This is different from the <var>Cursor</var> methods instantiation, | ||
which return a null if < | which return a null if <var class="term">recset</var> is empty. | ||
</ul> | </ul> | ||
With either of the instantiation methods, | With either of the instantiation methods, | ||
when a RecordsetCursor is instantiated, it is automatically | when a <var>RecordsetCursor</var> is instantiated, it is automatically | ||
positioned on the first record in the set (state=HasRecord). | positioned on the first record in the set (<code>state=HasRecord</code>). | ||
You can have as many cursors as you want for a record set. | You can have as many cursors as you want for a record set. | ||
==Referencing a RecordsetCursor object== | ==Referencing a RecordsetCursor object== | ||
If the [[State (RecordsetCursor | If the [[State (RecordsetCursor function)|state]] of a <var>RecordsetCursor</var> is <var>HasRecord</var>, it can be | ||
referenced on a new | referenced on a new <var>For</var>/<var>End For</var> variation: | ||
<p class="code"> | <p class="code">For Record At Cursor %RecordsetCursorObject | ||
... whatever | |||
End For | |||
</p> | </p> | ||
If the cursor is not in HasRecord state, the request is cancelled. | If the cursor is not in <var>HasRecord</var> state, the request is cancelled. | ||
Processing a record with this construct is very much like processing | Processing a record with this construct is very much like processing | ||
it with a | it with a <var>For Each Record</var> loop that runs on a set that only contains that record. | ||
that record. | |||
This means: | This means: | ||
<ul> | <ul> | ||
<li>No extra record locking is done. | <li>No extra record locking is done. | ||
The record is locked (or not) at | The record is locked (or not) at whatever level the underlying record set is. | ||
whatever level the underlying record set is. | |||
<li>If the cursor is for a SortedRecordset that was created using a | <li>If the cursor is for a <var>SortedRecordset</var> that was created using a | ||
<var>Sort Records To</var> statement, the records returned will be copies of the actual records. | |||
of the actual records. | If the <var>SortedRecordset</var> was created with | ||
If the SortedRecordset was created with | <var>Sort Record Keys</var>, the actual Table B record from the file is returned. | ||
This is consistent with the contrasting behavior of <var>Sort Records</var> and | |||
returned. | <var>Sort Record Keys</var> elsewhere in <var class="product">Model 204</var>. | ||
This is consistent with the contrasting | |||
</ul> | </ul> | ||
The <code> | The <code>For Record %recobj</code> construct can be used on the | ||
result of the | result of the <var>RecordsetCursor</var> <var>[[CurrentRecord (RecordsetCursor function)|CurrentRecord]]</var> method (or on a <var>Record</var> object | ||
RecordsetCursor CurrentRecord method (or on a | |||
to which the method result was assigned). | to which the method result was assigned). | ||
For example: | For example: | ||
<p class="code"> | <p class="code">For Record %myCursor1:CurrentRecord | ||
... whatever | |||
End For | |||
</p> | </p> | ||
Or, for example: | Or, for example: | ||
<p class="code"> %r is object record in foo | <p class="code">%r is object record in foo | ||
%r = %myCursor1:CurrentRecord(exclusive) | |||
For Record %r | |||
... whatever | |||
End For | |||
</p> | </p> | ||
This second technique is less efficient, because you incur the | This second technique is less efficient, because you incur the | ||
overhead of | overhead of <var>Record</var> object instantiation and record locking. | ||
It is more | It is more flexible because you can control the locking strength. | ||
flexible because you can control the locking strength. | |||
In addition, with this technique you always refer to the real record in Table | In addition, with this technique you always refer to the real record in Table | ||
B, and never to a Sort copy. | B, and never to a <var>Sort</var> copy. | ||
===LoopLockStrength for RecordsetCursors=== | ===LoopLockStrength for RecordsetCursors=== | ||
In addition to the LockStrength property, in <var class="product">Sirius Mods</var> 7.0 and later, | In addition to the <var>[[LockStrength (RecordsetCursor function)|LockStrength]]</var> property, in <var class="product">Sirius Mods</var> 7.0 and later, | ||
all RecordsetCursor objects also have a LoopLockStrength property. | all <var>RecordsetCursor</var> objects also have a <var>[[LoopLockStrength (RecordsetCursor property)|LoopLockStrength]]</var> property. | ||
Like the LockStrength property, the LoopLockStrength property's values | Like the <var>LockStrength</var> property, the <var>LoopLockStrength</var> property's values | ||
are of the LockStrength enumeration. | are of the <var>LockStrength</var> enumeration. | ||
The LoopLockStrength property indicates the minimum lock strength for | The <var>LoopLockStrength</var> property indicates the minimum lock strength for | ||
the record being processed in an iteration of a For Record At loop | the record being processed in an iteration of a <var>For Record At</var> loop | ||
on a RecordsetCursor object. | on a <var>RecordsetCursor</var> object. | ||
If the LoopLockStrength is the same as or weaker than the LockStrength | If the <var>LoopLockStrength</var> is the same as or weaker than the <var>LockStrength</var> | ||
of a RecordsetCursor object (which is, in fact, the lock strength of | of a <var>RecordsetCursor</var> object (which is, in fact, the lock strength of the underlying <var>Recordset</var> object), | ||
the underlying Recordset object), | |||
no action is required at the start of each loop | no action is required at the start of each loop | ||
— the record in the iteration is known to be locked at the | — the record in the iteration is known to be locked at the | ||
strength of the Recordset which is greater than the LoopLockStrength. | strength of the <var>Recordset</var> which is greater than the <var>LoopLockStrength</var>. | ||
If, however, the LoopLockStrength is stronger than the LockStrength, | If, however, the <var>LoopLockStrength</var> is stronger than the <var>LockStrength</var>, | ||
each execution of a For Record At loop on a RecordsetCursor object tries | each execution of a <var>For Record At</var> loop on a <var>RecordsetCursor</var> object tries | ||
to obtain a LoopLockStrength level lock on the record in the iteration. | to obtain a <var>LoopLockStrength</var> level lock on the record in the iteration. | ||
If successful, the iteration is processed and the lock is released | If successful, the iteration is processed and the lock is released at the end of the loop execution. | ||
at the end of the loop execution. | |||
The default value of LoopLockStrength is < | The default value of <var>LoopLockStrength</var> is <var>None</var>, which means that | ||
no additional locking is performed for the record in the RecordsetCursor | no additional locking is performed for the record in the <var>RecordsetCursor</var> | ||
during loop processing. | during loop processing. | ||
LoopLockStrength locking behavior is identical to the locking | <var>LoopLockStrength</var> locking behavior is identical to the locking | ||
behavior of the For Record Number (FRN) statement. | behavior of the <var>For Record Number</var> (<var>FRN</var>) statement. | ||
The meanings of certain statements in an On Record Locking conflict | The meanings of certain statements in an <var>On Record Locking</var> conflict | ||
unit are identical to their meaning for a For Record Number statement | unit are identical to their meaning for a <var>For Record Number</var> statement conflict: | ||
conflict: | |||
<dl> | <dl> | ||
<dt>Bypass | <dt>Bypass | ||
<dd>Causes processing of the record to be skipped, which means that | <dd>Causes processing of the record to be skipped, which means that | ||
the For Record loop is not processed. | the <var>For Record</var> loop is not processed. | ||
<dt>Retry | <dt>Retry | ||
<dd>Causes the For Record At statement to be re-executed and | <dd>Causes the <var>For Record At</var> statement to be re-executed and | ||
to try again to lock the record at the LoopLockStrength level. | to try again to lock the record at the <var>LoopLockStrength</var> level. | ||
</dl> | </dl> | ||
There are many similarities in LoopLockStrength processing for | There are many similarities in <var>LoopLockStrength</var> processing for | ||
RecordsetCursor and Recordset objects. | <var>RecordsetCursor</var> and <var>Recordset</var> objects. | ||
For more information about the use of LoopLockStrength with Recordset | For more information about the use of <var>LoopLockStrength</var> with <var>Recordset</var> | ||
objects see [[Recordset class#LoopLockStrength for Recordsets| | objects see [[Recordset class#LoopLockStrength for Recordsets|LoopLockStrength for Recordsets]]. | ||
==Discarding a cursor== | ==Discarding a cursor== | ||
In addition to the standard discard (<code>%myCursor1:Discard</code>), | In addition to the standard discard (<code>%myCursor1:Discard</code>), | ||
you can also use the Close method to discard a RecordsetCursor object: | you can also use the <var>[[Close (RecordsetCursor subroutine)|Close]]</var> method to discard a <var>RecordsetCursor</var> object: | ||
<p class="code"> %myCursor1:close | <p class="code">%myCursor1:close | ||
</p> | </p> | ||
==List of RecordsetCursor methods== | |||
The [[List of RecordsetCursor methods]] shows all the class methods. | |||
[[Category:System classes]] | [[Category:System classes]] |
Latest revision as of 21:18, 25 August 2014
You can loop on the records in a Recordset or SortedRecordset object using the traditional User Language For Each Record loop construct, as described in the preceding sections for those objects. However, it can be convenient to advance through a record set and access its records outside the context of a single record loop.
The Janus SOAP RecordsetCursor object gives you this additional capability for both Recordset and SortedRecordset objects. Essentially, a RecordsetCursor is a position marker in a record set. A cursor can be used to access the record at its position, or the cursor can be moved to a new position.
Cursor state
A RecordSetCursor can be in various states as it navigates a record set:
- BeforeStart
- The cursor is positioned before the first record in the set.
- HasRecord
- The cursor points to a record that is available for processing.
- AfterEnd
- The cursor is positioned after the last record in the set.
- NoRecord
- The cursor had a valid position identifying a record in a record set, but a subsequent operation (a Recordset Clear or RemoveRecord method) removed the record from the underlying Recordset.
- Empty
- The cursor points to an empty record set. This state is new in Sirius Mods version 7.6.
These cursor states are the values returned by the CursorState enumeration:
%state is enumeration CursorState
Note: As with all enumerations, the ToString method implicitly converts an enumeration value to a character string whose value is the name of the enumeration value. For more information about methods available to all enumerations, see Common enumeration methods.
The RecordsetCursor read-only property State returns a CursorState enumeration that indicates the current state of the cursor.
Any method that repositions the cursor returns a CursorState enumeration that indicates the new state of the cursor after the completion of the operation performed by the method.
Declaration and instantiation
A RecordsetCursor is declared like any other file or group context based object. For example:
%myCurs1 is object RecordsetCursor in file ftptest %myCurs2 is object RecordsetCursor in group foo
Prior to version 7.6 of the Sirius Mods, the RecordsetCursor class contained no native constructor methods, and the way to instantiate a RecordsetCursor object is to use the Cursor method provided by both the Recordset and SortedRecordset classes. In version 7.6, the RecordsetCursor New method was added, primarily to enable the creation of extension classes of the RecordsetCursor class, which the Cursor constructor cannot do.
Instantiation by the Cursor and New methods is described below.
- The Cursor method instantiates a RecordsetCursor for a
particular instance of a Recordset or SortedRecordset object.
The method takes no arguments.
If the set has at least one record, Cursor instantiates an instance of the RecordsetCursor object.
If Cursor is called on a set that "isEmpty" (0 records), it
returns a Null object.
Here is a small syntax example:
%rs is object recordSet in file stooges %srs is object SortedRecordset in file stooges %myCursor1 is object RecordsetCursor in file stooges %myCursor2 is object RecordsetCursor in file stooges ... fd to %rs end find ... sort records in %rs to %srs by name ... %myCursor1 = %rs:Cursor %myCursor2 = %srs:Cursor
- Since a RecordsetCursor references a Recordset or SortedRecordset object
and may have a LoopLockStrength, the RecordsetCursor New
constructor is of this form:
%(RecordsetCursor):New(recset [, LoopLockStrength=lls])
Where:
- recset
- A required Recordset or SortedRecordset object.
- lls
- A LockStrength enumeration setting the minimum lock strength for a record in a For Record At loop on a RecordsetCursor object. This argument is only valid if recset is a SortedRecordset object.
Note: If recset is empty, New returns a RecordsetCursor object with the state Empty. This is different from the Cursor methods instantiation, which return a null if recset is empty.
With either of the instantiation methods,
when a RecordsetCursor is instantiated, it is automatically
positioned on the first record in the set (state=HasRecord
).
You can have as many cursors as you want for a record set.
Referencing a RecordsetCursor object
If the state of a RecordsetCursor is HasRecord, it can be referenced on a new For/End For variation:
For Record At Cursor %RecordsetCursorObject ... whatever End For
If the cursor is not in HasRecord state, the request is cancelled.
Processing a record with this construct is very much like processing it with a For Each Record loop that runs on a set that only contains that record. This means:
- No extra record locking is done. The record is locked (or not) at whatever level the underlying record set is.
- If the cursor is for a SortedRecordset that was created using a Sort Records To statement, the records returned will be copies of the actual records. If the SortedRecordset was created with Sort Record Keys, the actual Table B record from the file is returned. This is consistent with the contrasting behavior of Sort Records and Sort Record Keys elsewhere in Model 204.
The For Record %recobj
construct can be used on the
result of the RecordsetCursor CurrentRecord method (or on a Record object
to which the method result was assigned).
For example:
For Record %myCursor1:CurrentRecord ... whatever End For
Or, for example:
%r is object record in foo %r = %myCursor1:CurrentRecord(exclusive) For Record %r ... whatever End For
This second technique is less efficient, because you incur the overhead of Record object instantiation and record locking. It is more flexible because you can control the locking strength.
In addition, with this technique you always refer to the real record in Table B, and never to a Sort copy.
LoopLockStrength for RecordsetCursors
In addition to the LockStrength property, in Sirius Mods 7.0 and later, all RecordsetCursor objects also have a LoopLockStrength property. Like the LockStrength property, the LoopLockStrength property's values are of the LockStrength enumeration. The LoopLockStrength property indicates the minimum lock strength for the record being processed in an iteration of a For Record At loop on a RecordsetCursor object.
If the LoopLockStrength is the same as or weaker than the LockStrength of a RecordsetCursor object (which is, in fact, the lock strength of the underlying Recordset object), no action is required at the start of each loop — the record in the iteration is known to be locked at the strength of the Recordset which is greater than the LoopLockStrength. If, however, the LoopLockStrength is stronger than the LockStrength, each execution of a For Record At loop on a RecordsetCursor object tries to obtain a LoopLockStrength level lock on the record in the iteration. If successful, the iteration is processed and the lock is released at the end of the loop execution.
The default value of LoopLockStrength is None, which means that no additional locking is performed for the record in the RecordsetCursor during loop processing.
LoopLockStrength locking behavior is identical to the locking behavior of the For Record Number (FRN) statement. The meanings of certain statements in an On Record Locking conflict unit are identical to their meaning for a For Record Number statement conflict:
- Bypass
- Causes processing of the record to be skipped, which means that the For Record loop is not processed.
- Retry
- Causes the For Record At statement to be re-executed and to try again to lock the record at the LoopLockStrength level.
There are many similarities in LoopLockStrength processing for RecordsetCursor and Recordset objects. For more information about the use of LoopLockStrength with Recordset objects see LoopLockStrength for Recordsets.
Discarding a cursor
In addition to the standard discard (%myCursor1:Discard
),
you can also use the Close method to discard a RecordsetCursor object:
%myCursor1:close
List of RecordsetCursor methods
The List of RecordsetCursor methods shows all the class methods.