Additional QUEUE Considerations

Top  Previous  Next

 

This topic expands on important issues in understanding how supported processing statements and optional parameters can affect a QUEUE.

ADD, GET, PUT to a QUEUE by KEY

 

There are three ( 3 ) forms of the QUEUE key parameter: sequence, string and function. Each one is described as follows:

 

sequence [±]key1[,[±]key2...]

A list of up to 16 labels of QUEUE fields, separated by commas and with an optional + or - sign preceding the label. If the key component is specified with -, it is used in descending order. Reference field types (including ANY) and arrays are not permitted.

 

Name

A string constant, variable or expression. Its value must contain a list of up to 16 NAME attributes of QUEUE fields with an optional leading + or - sign, separated with commas. If the key component is specified with -, it is used in descending order. Reference field types (including ANY) and arrays are not permitted.

 

When comparing two keys using one of the two forms above, the keys are considered equal if all key components are equal.

A key is considered greater than another key, if its nth key component is greater than the second key, and the extra component defined is in ascending order (with all other key components being equal.)

Finally, a key is considered less than another key if its nth key component is greater than the second key, and the extra component defined is in descending order (with all other key components being equal.)

There is also a third form of KEY types regarding QUEUES:

 

Function

The label of the function containing two parameters of a *GROUP or named GROUP passed by address, and having a SIGNED return value. Both parameters must use the same parameter type, and cannot be omitted. The RAW, C and PASCAL attributes are not permitted in the prototype declaration.

 

The first parameter of the FUNCTION is the target parameter, or record that is about to be acted on. The second parameter is a comparison value, used to determine the position where the first parameter is to be placed or retrieved.

Using ADD, PUT or GET by FUNCTION will read or write from a positional value returned by the function.

If the function returns zero (0) the queue record of the first parameter is treated as equal to the second. In this case, no record is ADDed or PUT, since the values are equal.

If the function returns a negative value, the ADD or PUT of the record passed as a first parameter is treated as having less value than record passed as second parameter and is written accordingly.

If the function returns a positive value, the ADD or PUT of the record passed as a first parameter is treated as having a greater value than record passed as second parameter and is written accordingly.

 

Using Multiple Sort Orders

 

The following topic describes the internal paradigm regarding QUEUEs with multiple sort orders.

Prior to Clarion 5, it was possible to use the GET(Queue,Key) form to obtain a POINTER to the first or last record in a range.

For example:

 

Q QUEUE

A  LONG

B  STRING(20)

 END

 

 CODE

 ...

 SORT(Q, Q.A, Q.B)      !sort the queue in a,b sequence

 Q.A = 1                !set to the first record

 CLEAR (Q.B)            !clear secondary field to make sure

 GET (Q, Q.A)           !GET to first record

 first# = POINTER(Q)    !GET fails, but stores the POINTER where record would have existed

 Q.A = 5                !set to the last record or beyond

 CLEAR (Q.B)            !again, clear secondary sort field

 GET (Q, Q.A)           !GET will fail

 last# = POINTER(Q)-1   !and returns where new record will be

 

After this code executes, first# contains a pointer to the first record of the Q.A field in a range (in this example range is 1 through 4), and last# contains a pointer to the last record with value of Q.A within this range.

This technique is not possible for queues with multiple sort orders. Even if one set of key components is a subset of another one, sort orders based on them are handled separately.

Hence, if the program uses a partial key seed value in the GET(Queue,Key) statement, the queue logic must build the sort order based on specified key if it does not exist, and perform the GET operation using this sort order. In other words, the GET never fails.

Sort orders based on "full" and "partial" keys can be different because of queue rules: ADD adds a new record after all other records with the same key, and PUT updates an existing record after all other records with the same key. The new POSITION(Queue) function implements the behavior that an attempted GET on a partial key value used to have.

 

Every active QUEUE can have up to 16 sort orders that exist in memory simultaneously.

For the purpose of this topic, sort orders not defined as the current active sort, but exist in memory by prior QUEUE actions (described later), are defined as a memory key.

 

All memory keys share the same queue of records, but each one orders the records according to the key that it is based on.

 

At any point in time during the life of the queue, one of the memory keys is the "default". The default memory key is the one that a SORT has been performed on most recently. If no SORT has been executed, the default memory key can be either unsorted, or sorted by the ADD(key) or PUT(key) methods ("sorting as you go")

 

The unsorted key is often used for non-keyed operations (i.e., POINTER()).

 

FREE() removes all memory keys.

 

The memory key based on the last key used in the keyed ADD, GET, PUT, or a SORT statement is called the active key. It is considered active while this particular statement is executing. If the active key did not exist before the keyed statement, it is created by taking the initial sequence of records defined by the default sort order, and is resorted using the new memory key.

 

SORT makes the active key the default. For example, if the active key existed before the SORT, no resorting is performed, because it doesn’t need to.

 

GET(Queue,Key) retrieves the first record using the active key’s (Key parameter) sort order that matches current content of the queue buffer. If no records can be found, the buffer is not changed and value of next call to POINTER() is undefined.

 

GET(Queue,Pointer) retrieves record with the relative position equal to the Pointer position in the default memory key.

 

ADD and PUT work differently for default key and all other memory keys. All memory keys that are not the default are updated using their key values always, even for non-keyed operations. Hence, their current sort is always correct.

 

For the original sort order, the situation is a little more complex. Here, the traditional rules are in effect:

 

PUT(Queue):

Writes the record back to the same relative position in the original sort order as the GET or ADD retrieved it. If the original sort order was modified since the last GET or ADD, it is marked as unsorted.

 

PUT(Queue,Pointer):

If the passed Pointer is equal to relative position in the original sort order of the record that has been retrieved by GET or ADD, the statement is equivalent to PUT(queue). Otherwise, the record is removed from its old position in the original sort order and is added to the one specified by the new pointer value. If the original sort order becomes broken after that, it is marked as unsorted.

 

PUT(Queue,Key)

If Key is a key that the original sort order is based on, and the key value is not changed, PUT updates the record value in original sort order. If the key value is changed, the record's value is removed from its old position and added to a new one, based on the new key value. The original sort order always remains unbroken in this case.

 

If Key is not a key that the original sort order is based on, the original sort order is marked as unsorted, the record's entry is removed from its old position, and a new one added immediately before the first record it finds with the key value based on Key.

 

Because the search algorithm is based on the history of work with this queue and its memory keys, it is impossible to say where the new position will be. Use the POINTER() function to return it.

 

ADD(Queue)

Equivalent to ADD(Queue,RECORDS(Queue)+1)

 

ADD(Queue,Pointer)

The record in the queue buffer is added to given relative position in the original sort order. If the original sort order becomes broken after that, it is marked as unsorted.

 

ADD(Queue,Key)

The record in the queue buffer is added immediately before first record in the original sort order that has greater key value, or, to the end of the sort order if records with greater key value are not found. If Key is a key that the original sort order is based on, this is the correct position and the default sort order remains unbroken. Otherwise, it is marked as unsorted. Similar to using PUT on another key value, the position of the added record is unknown if the default sort order is not based on the Key.

 

 

Example 1:

 

Q QUEUE

A  LONG

B  LONG

 END

 

 CODE

  FREE(Q)

  Q.A = 1

  Q.B = 5

  ADD(Q, Q.A)

 

There is only one sort order based on the (Q.A) key; it is the active memory key

 

SORT (Q, Q.A, Q.B)

 

Now, there are two sort orders that exist, based on a (Q.A) and (Q.A,Q.B) keys. The latter key is now the active memory key.

 

The order of records is now:

 

(Q.A):

(1, 5)

(Q.A,Q.B)

(1, 5)

 

If we now execute:

 

 Q.A = 1

 Q.B = 1

 ADD (Q, Q.A, Q.B)

 

The order of records is now:

 

(Q.A):

(1, 5) (1, 1)

(Q.A,Q.B):

(1, 1) (1, 5)

 

Executing the statement:

   GET(Q, Q.A)

 

Retrieves the (1, 5) record, because it is the first record matching the key value in the current queue buffer based on (Q.A).

 

Example 2:

 

Q   QUEUE

A     LONG

B     LONG

   END

 

 CODE

 

 FREE(Q)

 Q.A = 1

 Q.B = 5

 ADD (Q)

 

There is one original sort order; and it is the active key.

 

SORT (Q, Q.A, Q.B)

 

Now, there is one sort order here based on the (Q.A,Q.B) key. It is now the new active key.

 

The current order of records is:

 

(Q.A,Q.B)

(1, 5)

 

After executing the following:

 

   Q.A = 1

   Q.B = 1

   ADD (Q, Q.A, Q.B)

 

The new order of records becomes:

 

(Q.A,Q.B)

(1, 1) (1, 5)

 

Executing:

 

GET(Q, Q.A)

 

The sort order based on (Q.A) does not exist. Hence, it is created as a new sequence of records in default order resorted with the (Q.A) key.

 

The memory keys after this GET:

 

(Q.A)

(1, 1) (1, 5)

(Q.A,Q.B)

(1, 1) (1, 5)

 

 

The GET retrieves the (1, 1) record because it is the first record with the key value that matches the current queue buffer based on (Q.A).