Documentation
Download Latest Version Index JumpStart FAQ History Classes Methods
CapeSoft Logo

CapeSoft MaxQueue
Documentation

Installed Version Latest Version Beta

Introduction

Please Note: MaxQueue requires StringTheory and Reflection

One of Clarions strongest features is a built-in data structure known as a Queue. MaxQueue builds on this feature, making queues more powerful, easier and safer to use.

Global Unthreaded Queues

Global, Unthreaded Queues are bad because they are not thread safe. They were popular in Clarion 5.5 and earlier (because they could be safely used there) but from Clarion 6 they became unsafe, and should be removed, where possible from a program. Unfortunately in large programs this is easier said than done, and replacing global unthreaded queues (with memory tables, or whatever) can be a large task.

MaxQueue offers an alternative to replacing global unthreaded queues, by making them thread safe. Changes are made at the global declaration level, but existing code which access the queue remains unaltered. [1] This increases the safety of the global queue, while at the same time reducing the number of changes required to existing code.

[1] Not all the queue functions are duplicated, so there are some possible places in the code where a compile error may occur. A simple alternate line of code can easily be used in these situations. The compiler will alert you to places where this is necessary[2].

[2] There is one catch. There is a Clarion system intrinsic which cannot be overridden with a method. And unfortunately the compiler will not detect it. So this is one case where a search of the source will be required.  For more information see Global Unthreaded Queues.

Extended Queue Syntax (More Methods!)

While the supplied Queue procedures are adequate to read and write to the queue, there are cases where the syntax is clumsy. It is also notable that the syntax is similar to, but does not match the syntax for the file drivers. MaxQueue offers additional methods which can make processing queues simpler and more intuitive (and in some cases faster).

New methods include Set, Next, Previous, Copy, Add and more.

Load and Save

Queues can be loaded from and to either StringTheory objects, or a text file, using Load, Save, LoadFile, SaveFile. For more information see Loading and Saving Queues.

Queues In Queues

It is possible, and reasonably straight-forward to create Queues-in-Queues. However working with these can tricky, and if they are not free'd correctly then they can lead to memory leaks. By linking into the Reflection accessory (which is free) safe Queue disposes are done internally using the normal FREE method.

Requirements

MaxQueue requires StringTheory 3 and Reflection.

ClarionLive

An introduction to MaxQueue, and the way in which it works, was described in ClarionLive session #638 , recorded on 19 November 2021.

Installation

Run the supplied installation file.

Support

Your questions, comments and suggestions are welcome. Check our web page (capesoft.com) for new versions. You can also contact us in one of the following ways:

CapeSoft Support
Email support@capesoft.com
Telephone +27 87 828 0123
(087) 828 0123

License and Distribution

No additional files are required for shipping. The files in this product are copyright 2024 by CapeSoft.

This product is provided as-is. CapeSoft Software and CapeSoft Electronics (collectively trading as CapeSoft), their employees and dealers explicitly accept no liability for any loss or damages which may occur from using this package. Use of this package constitutes agreement with this license. This package is used entirely at your own risk.

Use of this product implies your acceptance of this, along with the recognition of the copyright stated above. In no way will CapeSoft , their employees or affiliates be liable in any way for any damages or business losses you may incur as a direct or indirect result of using this product.

AnyScreen

MaxQueue is a class product, and has no User Interface, so it is completely compatible with programs running under AnyScreen.

Clarion Template (Legacy) Programs

The MaxQueueGlobalClass makes use of the CriticalSection component, which is part of ABC. So Legacy apps must have "Enable the use of ABC Classes" option turned on.

Use in a Hand-Coded Project

MaxQueue makes use of StringTheory and Reflection. Their equates are included here for your convenience. This assumes that MaxQueue, StringTheory and Reflection are exported from the same app.

Stand-along exe app, or DLL you are exporting MaxQueue from.

  1. Add the line
    Include('MaxQueue.Inc'),Once
    to your project in the appropriate scope, so the class is in scope.
  2. Set the Conditional Compiles in your project
    MaxQueueLM => 1
    StringTheoryLinkMode => 1
    ReflectionLM =>1
    _ABCLinkMode_ => 1
  3. Set the Conditional Compile in your project
    MaxQueueDM => 0
    StringTheoryDLLMode => 0
    ReflectionDM => 0
    _ABCDLLMode_ => 0

Exe app, or DLL using MaxQueue exported by another library

  1. Add the line
    Include('MaxQueue.Inc'),Once
    to your project in the appropriate scope, so the class is in scope.
  2. Set the Conditional Compiles in your project
    MaxQueueLM => 0
    StringTheoryLinkMode => 0
    ReflectionLM => 0
    _ABCLinkMode_ => 0
  3. Set the Conditional Compile in your project
    MaxQueueDM => 1
    StringTheoryDllMode => 1
    ReflectionDM =>1
    _ABCDLLMode_ => 1

Exporting from a Hand-Code project

This covers the case where you may be exporting a Global Queue from a hand-coded project.
In this example the Queue is named TMQueue. The Object is called TMQueue

Your current EXP file likely includes something like

  TYPE$TMQueue          @?
  TCB$TMQueue           @?
  $TMQueue              @?


This changes, so the above have the leading underscore;

  TYPE$_TMQueue          @?
  TCB$_TMQueue           @?
  $_TMQueue              @?

and the Object, and Group are exported as

  $TMQUEUE               @?
  TYPE$QTMRECORD         @?
  $TMQUEUERECORD         @?



Overriding Construct

In a template generated app, the global template takes care of calling the INIT method on every thread. In a hand-coded situation you would need to do this manually. The easiest way to do this is to derive the CONSTRUCT method for the object. As seen elsewhere in the docs, the typical declaration change is to go from

someq Queue,pre(sq)
      End


to

someq       MaxQueueGlobalClass,Thread
_someq      Queue,pre(_sq)
            End
someqrecord Group(_someq),pre(sq),Thread


This can be extended slightly, to include the INIT call.

someq Class(MaxQueueGlobalClass),Thread
        Construct Procedure()
      End


Then in the code have;

someq.Construct Procedure()
  code
  self.Init(_someq,someqrecord)

Global Unthreaded Queues

In Clarion 5.5 and earlier, Global Unthreaded, Queues were a useful global data structure, and they were safe to use, even across threads, because Clarion 5.5 and earlier employed a cooperative threading model. Clarion 6 and later switched to a preemptive threading model, which made the use of global, unthreaded, queues unsafe.

During the change over there was an incorrect assumption that global unthreaded queues were safe, as long as they were primed once, and then only read from. This is not the case though because queues have a record buffer, and the act of reading a queue entry overwrites the record buffer. Thus if multiple threads access (read or write) the queue at the same time then bad things can happen.

The solution is to wrap the queue access code in a Critical Section. This serializes access to the queue across threads, and thus makes it safe. The problem with this approach is that the programmer has to be sure each block of code is wrapped, and wrapped correctly. Mistakes in the wrapping could lead to program hangs, data corruption, or GPF's. Perhaps even worse all future code accessing the queue has to be wrapped correctly - so the solution depends on future programmers on the system knowing what to do, and to do it correctly.

Not surprisingly many programs have instead chosen to simply ignore the problem, noting that in most real-world situations the issue is not likely to arise in most cases.

Alas "hope for the best" is not a particularly scaleable programming strategy, and MaxQueue offers an alternative approach which solves the problems with minimal changes to the existing program.

The key difference when using MaxQueue is that code using the queue does not need to be altered[1]. Rather the declaration of the queue changes. Changing the declaration is much simpler than changing the code as it is in one place (per app).

[1] Actually that's almost true, but usefully where it does have to be altered it will generate a compiler error, so invalid code is automatically detected, and can be easily fixed.

Changing the Global Declaration

  1. Change the Label of the queue, by adding an underscore to the front of the Label. For example change DepartmentQueue to _DepartmentQueue. Do the same to the Prefix of the queue. Add an underscore to the front of it, for example changing dq to _dq.

  2. Add a new global declaration, using the original Queue label, but setting the Data Type to Type and the Base Type to MaxQueueGlobalClass. This object must have the THREAD attribute ticked on (on the Attributes tab)




  3. Create a new global group declaration, using the original queue label and adding Record to the name. For example DepartmentQueueRecord. Set the prefix of this group to be the original queue prefix. Set Data Type to Group and Set the Base Type of this group to the new Queue label. For example _DepartmentQueue. This new declaration must also be threaded.



  4. Note: In Multi-DLL systems this step only needs to be done in the DLL where the Queue is declared for the first time. In other words it does not need to happen in places where the Queue is declared as EXTERNAL.

    Go to the MaxQueue Global Extension, to the Global Unthreaded Queues tab, and add a line to the MaxQueueGlobalClass Objects list.
    This should name the three parts created above, first the object, then the queue, then the record. For example;

You should end up with the following;
If you are declaring in the Global Data Pad;



If you are declaring in a Global Data embed point;

DepartmentQueue      MaxQueueGlobalClass,THREAD
_DepartmentQueue     QUEUE,PRE(_dq)
! Queue fields go here, just as they were before
                     END
DepartmentQueueRecord GROUP(_DepartmentQueue),PRE(dq),THREAD
                     END

You can now go ahead, and compile the application. If it compiles ok, then all the existing code working on DepartmentQueue is now thread safe. If you get any compile errors, then carry on reading.

CLEAR(SomeQueue)

There is one line of code which may exist in your current program, and which will be legal in the new program (ie the compiler will not complain) but it will not work (correctly). That is the CLEAR(QUEUE) statement.

This clears the queue record buffer, or in the MaxQueueGlobalClass case clears the object (in other words clears all the properties in the object.)

The call to
Clear(DepartmentQueue)
must be replace with
ClearQueue(DepartmentQueue)
or
DepartmentQueue.ClearQueue()

The good news is that if you miss a call to CLEAR, and accidentally leave this in the program, then it will trigger a fatal call to ErrorTrap, which will display a message, and generate GPF. The GPF is handy because it leads you back to the line of code where you called a method after calling CLEAR. (If you're not sure how to read a GPF, see ClarionHub.)

Global Writing / Hold

In most cases a global unthreaded queue is written to on the main thread, then read from on the other threads. The considerations here do not apply in this case.

In other situations, records are written to the queue using the Add command. This is now safe, and will work as-is.

The Put and Delete commands are more problematic. In these cases a record is read first, then updated or deleted. MaxQueue will reget the most recently read record before doing a Put or Delete. However calls to Sort, Add or Delete on other threads can lead to index values being changed, which in turn can read to the wrong record being Put or Deleted.

So, for global unthreaded queues, that make use of Sort, Delete or Add (on various queues at various times) it is necessary for updates on the queue to be wrapped with the critical section. Since the read, and write, occur in the program code it will be necessary to change the program code.

A new method, Hold, is used before the record is read (via Get, Next or Previous). A hold is good for a single read. This hold will automatically be released on the next write into the class (via an Add, Put, Sort or Delete etc.) If a second read is done when a row is held, then the hold is cleared. The second read does not result in a new hold. If no write is necessary then call ClearHold to clear the hold on the queue. If a single read is done, and then no write (and no subsequent read) is done, and ClearHold is not called, then the queue will be locked until this thread ends.

In summary, Hold is designed to be used in a very tight block of code. Hold, then Read, then Write. more code than this will likely result in the Hold being lost.

Example

Loop x = 1 to mqg.records()
  mqg.Hold()
  mqg.Get(x)
  ! change the record here
  ! mqg.Put()
End


or, in old queue-style syntax

Loop x = 1 to records(Somequeue)
  Hold(Somequeue)
  Get(Somequeue,x)
  ! change the record here
  Put(Somequeue)
End

Pointer

The Pointer method returns the index to the most recently read record. However this value could quickly become out of date if the queue is altered by another thread, more specifically if a record is added, or deleted, with an index value lower than the value in the pointer.

For this reason the use of the Pointer method in the context of a global, unthreaded, queue, where writes are possible on other threads, should be avoided. The most common use of Pointer is simply to restore the queue record after doing some other work. New methods SaveGroup and RestoreGroup provide handy alternatives for this situation. these methods save, and restore, the threaded group and index values.

Compile Errors

There are two possible places in code where there will now be an error generated by the compiler. Errors generated by the compiler are good, because they are an affirmative defense against problems. In both cases the error is the same;
No matching prototype available.
  1.  When you inspect the code which caused the error it reads as

    someQueueLabel.someQueueField = whatever (or vice versa)

    for example

    DepartmentQueue.Code = 3

    This is the long-hand version of specifying a queue field. It is preferred over using the prefix for (dq:code) by some programmers (including myself.) This code has to be tweaked to add the suffix Record. Thus it becomes

    DepartmentQueueRecord.Code = 3
  2. If you inspect the code which caused the error it reads as

How Does it Work ?

The technique of changing the original queue label to be an object rather than a queue works because of a little-used Clarion syntax.

As you may know, when you call the method of an object, as in object.method(whatever) then there is a (hidden) first parameter which is a reference to the object itself. This is why the use of OMITTED inside a method should always use the parameter name not the parameter number.

This happens because the compiler transcribes the text to read method(object,whatever). In other words all methods are simply normal procedures that take a *Class (itself) as the first parameter. From there it's a simple matter for the compiler to route the call to the correct class method.

So In MaxQueue, if you make an object (called say DepartmentQueue) of MaxQueueGlobalClass, and then call the method Add, then this transcribes to
Add(DepartmentQueue)
which is exactly the syntax you would use to add to a Queue structure.

By cunningly naming all the methods (and parameters) the same as the ones for a Queue structure, code that works on existing queues will also work as-is on MaxQueue objects.

Internally (via the INIT method call) the object knows about the actual global queue (_DepartmentQueue) and the threaded record buffer (DepartmentQueueRecord). Putting all this together MaxQueue wraps up all the existing queue functionality, and then extends it with the addition of new methods, critical sections and so on.


Extended Queue Syntax

The Clarion language provides a simple, and sufficient set of commands to access a queue. However these commands can become unnecessarily complicated at times, and in some cases the commands do not match the commands offered by the File Driver interface. MaxQueue extendeds the command set available, simplifying code, and making some operations more intuitive.

Set / SetFirst / SetLast / Next / Previous

Perhaps the most glaring omission from the Queue command lineup is the lack of a SET / NEXT pattern which is used a lot when managing table data. MaxQueue addresses this by adding Set, Next and Previous methods.

Set sets the current order of the queue (by calling the Sort method[1]), then sets the Index to the first record that matches the current record values, or if none match then to the next record following the current record position. Next and Previous then loop through the queue, in the same way that the Clarion Next and Previous commands loop through a table.
In more specific terms, SET sets the sort order and current-record-index, while Next and Previous move the Index by 1 and do a Get.

If you call Set with no parameters, then the current sort order is not changed, but the current index is set to the position of the current record buffer (matching the fields in the current sort order.)

It is also possible to pass a simple index value to Set, and it will set the index to that position. In this case the sort order of the queue is not changed.

Set can take a comma separated string. This will be passed to the Sort method, and the queue will be sorted in this order. It will then set the index to the current record position.

Set does not read a record, the current record buffer is not altered. Therefore the first call to Next or Previous after a SET reads the current index position.

You do not need to call Set to make use of Next or Previous. Next and Previous are always ready and will loop through the queue from the current index position. In other words doing a Get, followed by Next is allowed.

SetFirst is the same as Set(1) and SetLast is the same as Set(self.Records()).

Note 1: If you pass a sort order to Set, then the Queue will be sorted into that order. It will remain in that order after the Set, and by implication it will remain in that order after the Next loop.

AddTo / AddFrom / Subtract / CopyTo / CopyFrom / MergeTo / MergeFrom

Clarion Queue functions work on a single queue structure. But in some cases it's useful to deal with two, or more, queues at a time. MaxQueue offers methods which allow you to move data between queues of the same structure.

CopyTo / CopyFrom first clear the destination queue, then copy the records across. Thus the result are two queues exactly the same.

AddTo / AddFrom add records from one queue to another, while keeping the existing records. So the resultant queue contains all the original records, plus all the new records, and may contain duplicates.

MergeFrom / MergeTo copies the records from one queue to another, but (based on the current sort order) does not duplicate records. Merge uses the current sort order, so call Sort before calling MergeFrom / MergeTo to determine the fields to be checked when duplicating.
If the source queue contains a record that matches the destination queue then the Options parameter determine if the record will be overwritten or not.



Loading and Saving Queues

Simple queues can be saved to StringTheory objects using the Save method. They can then be loaded into queues using the Load method. If you need to store the queue data persistently then use SaveFile, and then LoadFile to load it.

mq.Init(DepartmentQueue)
mq.Load(str)


The methods are only suitable for simple queues - in other words queues that do not contain any references. (ie &something). For queues with references a more suitable save, and load option - such as the one provided by jFiles or xFiles is recommended.

The goal of these methods is not to create a CSV-export feature, but rather as a was of persistently storing queue data.

These methods include short-hand versions which allow you to include the queue being saved or loaded. This removes the need to call the Init method. The Init method will be called internally, so the object is then bound to the passed in queue, and can be used as such.

mq.Load(DepartmentQueue,str)

Required Code Changes

As mentioned earlier almost all existing code will just work as-is. there are however a few cases where a small change to the code is required. Fortunately the compiler will spit an error in these places.

Calls with Ascending and Descending sort orders

Some methods, notable Sort, Add and Put allow for the specification of a sort order, and more specifically the use of a + and - to indicate ascending and descending sort orders. So for example;

Sort(ItemQ,-INQ:TaxAmount1,-INQ:Sell_Price,+INQ:Color)

This has to change to use the "string" form. So the above changes with the addition of two single quotes;

Sort(ItemQ,'-INQ:TaxAmount1,-INQ:Sell_Price,+INQ:Color')


Examples

GlobalUnthreaded/Unsafe.app

This app demonstrates in inherent lack of safely when using global unthreaded queues.

Click the PrimeQueue button to prime the queues, then turn on the Run Test checkbox, and click on the TestUnsafe button. At this point the test is running on a single thread, and no issues are encountered. However if you click the Test Unsafe button again (thus having 2 instances of the procedure running) you will immediately see issues starting to appear.

If you close the Unsafe windows, and open the TestSafe windows, you will notice that multiple windows can be opened and no issues will occur. This is because the TestSafe procedure makes use of the MaxQueueGlobalClass as described above.

UnitTest.app

This application is shipped in the latest Clarion version, so (currently) will only open in Clarion 10 or later.

It contains a suite of tests. This example will grow regularly as more and more tests are added to the app. The tests are run automatically when the program starts, and results are visible in Debugview.

Template Reference

Global Extension

This template activates the reflection class in the application.

General Tab

Disable All MaxQueue Features
If this is ticked on then the template does nothing.

Options Tab


Global Unthreaded Queues

This tab allows you to bind Global Unthreaded Queues, to MaxQueueGlobalClass objects, and the associated threaded Group. For mosre details on these three parts, and how they work together, see Global Unthreaded Queues.

Multi-DLL Tab

This is part of a Multi-DLL program
Tick this on if this app is part of a multiple-app system. This is turned on for all the DLL's and the EXE's.
Export MaxQueue Class from this DLL
Tick this on in the app which will export the class. This is almost always the Data DLL app. In all other apps, DLLs and EXE's, leave this off.

Classes Tab

Class Version
The last date when the class was parsed from the LibSrc folder. Used internally. Do not change.

Class Reference


MaxQueueClass

Properties

Property Type Description
Error String The value of Error() after the last call to a queue method.
ErrorCode Long The value of Errorcode() after the last call to a queue method.
Index Long An index pointing to a specific row, which has been (or will be) loaded. Can be set using the Set method. Will be updated whenever a record is fetched from the queue into the record buffer.
NamesQueue NamesQueueType A simple list of the name, fullname, and name without prefix of the fields in the queue.

Methods

Method Description
Add
Add a record to the queue [Clarion]
AddFrom
Add the contents of another queue to this queue
AddTo Add the contents of this queue to another queue
ClearQueue Clear the record contents of the queue structure.
CopyFrom Free this queue, then copy the contents of another queue to this queue
CopyTo Free that queue, then copy the contents of this queue to that queue.
Delete Delete a record in the queue [Clarion]
ErrorTrap Called when unexpected errors occur.
Free Delete all the records in the queue [Clarion]
Get Get a specific record in the queue [Clarion]
GetFirst Get the first record in the queue.
GetLast Get the last record in the queue.
Init Bind the object to the queue. MUST be called first.
Kill Unbind the object from a queue.
Load Load the queue from the contents of a StringTheory object
LoadFile Load the queue from a file on the disk
MergeFrom Merge the data in two separate queues without duplicating records
MergeTo Merge the data in two separate queues without duplicating records
Next Read the next record in the queue
Pointer Get the record number of the record currently in the queue buffer.
Previous read the previous record in the queue
Put Put the record buffer back into the queue [Clarion]
Records Get the number of records in the queue [Clarion]
Save Save the contents of the queue to a StringTheory object
SaveFile Save the contents of the queue to a file on the disk.
Set Set a position in the queue, ready for calls to Next.
SetFirst Sets the index to the first position in the queue
SetLast Sets the index to the last position in the queue
Sort Sort the entries in the queue [Clarion]
Subtract Remove entries from a queue that exist in another queue.
Start Return the object to a virgin state - but still bound to the queue (as done by Init)
Trace Send the contents of a string to Debugview
Classes

Add

Add()
Add(String pIndex)
Add(String pOrder)
Add(queuefield,<queuefield>,<queuefield>,<queuefield>,<queuefield>)
Add(mq:QueueFunction pFunction)

Description

Works the same as the normal Clarion ADD(QUEUE) command.

Adds a record to the queue. If no parameters are passed then the record is added to the end of the queue.

Up to five queue fields can be used to add the new record to a specific position. These fields must match the current sort order of the queue.

A comma separated string of field names can be used. These fields must match the current sort order of the queue. This form allows for leading + and - symbols to be added to the field names to indicate ascending or descending order.

Parameters

Parameter Description
pIndex A specific position to add the record into the queue. Using this approach (or passing no parameters) will "break" the existing sort order, and the queue must be resorted (using Sort) to reestablish the sort order.
pOrder A comma separated list of field names, and can include + and - symbols. These fields must match the current sort order of the queue.
queuefield (up to 5 of them)
Up to five queue fields can be used to add the new record to a specific position. These fields must match the current sort order of the queue.
pFunction A function, with the prototype Procedure(*Group pGroup1, *Group pGroup2),Signed
This will be passed through to the Clarion Queue engine in place of the Clarion Add call.

Return Value

Nothing

Example

mq  MaxQueueClass
  code
  mq.Init(DepartmentQueue)
  dq:name = 'Sales'
  mq.Add()


See Also

Add, Sort, Get, Put, Delete, Free, Clarion Help on ADD

Classes

AddFrom

AddFrom(MaxQueueClass pSource)
AddFrom(Queue pSource)

Description

Adds the contents of the Source queue into this queue. This queue is  not free'd before adding takes place. (If you do want it to be free'd see the CopyFrom method or use the Free method.)

The current Queue and the queue referenced by the pSource parameter must have (exactly) the same structure.

Parameters

Parameter Description
pSource
The source queue or source MaxQuery object

Return Value

Nothing

Example

mq.AddFrom(SomeOtherMaxQueueObject)
mq.AddFrom(SomeOtherQueue)


See Also

AddFrom, AddTo, CopyFrom, CopyTo, MergeFrom, MergeTo, Subtract .

Classes

AddTo

AddTo(MaxQueueClass pDestination)
Add(Queue pDestination)

Description

Adds the contents of this queue to the destination queue. This queue is not free'd before adding takes place. (If you do want it to be free'd see the CopyTo method or use the Free method.)

The current Queue and the queue referenced by the pDestination parameter must have (exactly) the same structure.

Parameters

Parameter Description
pDestination
The destination queue or destingation MaxQuery object

Return Value

Nothing

Example

mq.AddTo(SomeOtherMaxQueueObject)
mq.AddTo(SomeOtherQueue)


See Also

AddFrom, AddTo, CopyFrom, CopyTo, MergeFrom, MergeTo, Subtract .

Classes

ClearQueue

ClearQueue()

Description

This clears the Queue Record buffer. This should be called instead of just CLEAR(Queue) because if the MaxQueueGlobal class is used then the record buffer is not the queue. Also, in all cases (including the MaxQueue case) ClearQueue is capable of clearing references in a non-memory-leaking way (which CLEAR(Queue) does not do.)

Return Value

Nothing

Example

mq.ClearQueue()


See Also



Classes

CopyFrom

CopyFrom(MaxQueueClass pSource)
CopyFrom(Queue pSource)

Description

Copies the contents of the Source queue into this queue. This queue is free'd before copying takes place. (If you don't want it to be free'd see the AddFrom method)

The current Queue and the queue referenced by the pSource parameter must have (exactly) the same structure.

Parameters

Parameter Description
pSource
The source queue, as either a queue structure or MaxQueue object to copy into this queue.

Return Value

Nothing

Example


mq.CopyFrom(SomeOtherMaxQueueObject)
mq.
CopyFrom(SomeOtherQueue)

See Also

AddFrom, AddTo, CopyFrom, CopyTo, MergeFrom, MergeTo, Subtract .

Classes

CopyTo

CopyTo(MaxQueueClass pDestination)
CopyTo(Queue pDestination)

Description

Copies the contents of the this queue into the destination queue. This queue is free'd before copying takes place. (If you don't want it to be free'd see the AddTo method)

The current Queue and the queue referenced by the pDestination parameter must have (exactly) the same structure.

Parameters

Parameter Description
pDestination The destinationqueue, as either a queue structure or MaxQueue object to receive the copy of this queue.

Return Value

Nothing

Example


mq.CopyTo(SomeOtherMaxQueueObject)
mq.
CopyTo(SomeOtherQueue)

See Also

AddFrom, AddTo, CopyFrom, CopyTo, MergeFrom, MergeTo, Subtract .

Classes

Delete

Delete()

Description

Works the same as the normal Clarion DELETE(QUEUE) command.

Deletes the most recently fetched record from the queue.

Delete cannot be called immediately after a Set. Set only sets the index position, it does not read the record. Calling Delete after a Set will result in no record being deleted.

In a global, unthreaded, queue context Delete can be tricky if other threads are adding to the queue. In this context the record is reloaded before the delete, but using the index position of the most recent read. So if other records are added into the queue before this record, this could end up deleting the wrong record.


Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also

Add, Sort, Get, Put, Delete, Free, Clarion Help on DELETE

Classes

ErrorTrap

ErrorTrap(String pFrom, String pError, Long pOptions=0)

Description

This method is called in places where the normal method of returning errorcodes will be insufficient.

Parameters

Parameter Description
pFrom
The location int he code that triggered the error.
pError The text of the error
pOptions If set to mq:fatal then a GPF will occur. This allows the programmer to track the source of the error.
For more information on reading a GPF report see ClarionHub.

Return Value

Nothing

See Also

Trace, TraceRecord, ErrorTrap .

Classes

Free

Free()

Description

Deletes all the rows from the queue.

Works the same as the normal Clarion FREE(QUEUE) command, but with the added feature that reference fields are followed and disposed as well. Nesting Queues-in-queues is supported by this call.

Return Value

Nothing

Example

mq.Free()
Free(Mq)

See Also

Add, Sort, Get, Put, Delete, Free, Clarion Help on FREE

Classes

Get

Get()
Get(Long pIndex)
Get(String pOrder)
Get(queuefield,<queuefield>,<queuefield>,<queuefield>,<queuefield>)
Get(mq:QueueFunction pFunction)

Description

Gets a record from the queue, and moves it into the record buffer.

Works the same as the normal Clarion GET(QUEUE) command.

If passed with no parameters then the the Index property of the object is is used. In other words, Self.Get() is the same as self.Get(self.Index).

Parameters

Parameter Description
pIndex
The index number of the record to get
pOrder A string, containing a comma-delimited-list of field names. The names can optionally be prepended with + and - signs.
queuefield The name of field in the queue. Up to 5 fields can be passed. The record matching these fields will be fetched.
pFunction A function, with the prototype Procedure(*Group pGroup1, *Group pGroup2),Signed
This will be passed through to the Clarion Queue engine in place of the Clarion Get call.

Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also

Add, Sort, Get, Put, Delete, Free, Clarion Help on GET

Classes

GetFirst

GetFirst()

Description

This

Parameters

Parameter Description



Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also



Classes

GetLast

GetLast()

Description

This

Parameters

Parameter Description



Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also



Classes

Init

Init(*Queue pQueue)

Description

This method "binds" a local queue to a local object. It allows the object to work on the queue, and allows all the additional features of the MaxQueue methods to work. It needs to be called before any other methods for the object."

Note that this binding is NOT unset with a Call to the Start method. To switch the assignment of the object from one queue to another, the INIT method can be called again.

Parameters

Parameter Description
pQueue The Queue structure associated with this object.

Return Value

Nothing

Example

DeptQ  MaxQueueClass
_DeptQ  Queue
        ! some fields here
        End
  Code
  DeptQ.Init(_DeptQ)


See Also

  Kill .

Classes

Kill

Kill()

Description

This method "unbinds" the queue from the object.
It will return the object to a virgin state.

Return Value

Nothing

Example

mq.kill()

See Also

Init

Classes

Load

Load(StringTheory pStr,Long pOptions=mq:free)

Description

Loads the queue from a CSV-like format, in a StringTheory object, to the queue.

Note that Load does not follow reference fields, so this method is only useful on queues that do not contain reference fields. For more complex queues load the queue using jFiles or xFiles.

Parameters

Parameter Description
pStr
The StringTheory object, containing the CSV content.
pOptions A bit mask containing any of the following;
mq:free : The queue is free'd before the new content is loaded
mq:append : The new content is appended to the existing queue.

Return Value

Nothing

Example

DeptQ MaxQueueClass
str.Stringtheory
  code
  str.SetValue(whatever)
  DeptQ.Init(DepartmentQueue)
  DeptQ.Load(str)


See Also

LoadFile, Save, SaveFile, Loading and Saving Queues

Classes

LoadFile

LoadFile(String pFileName,Long pOptions=mq:free)

Description

Loads the queue from a CSV-like format, in a file on the disk, to the queue.

Note that Load does not follow reference fields, so this method is only useful on queues that do not contain reference fields. For more complex queues load the queue using jFiles or xFiles.

Parameters

Parameter Description
pFileName
The name of the file on disk to load.
pOptions A bit mask containing any of the following;
mq:free : The queue is free'd before the new content is loaded
mq:append : The new content is appended to the existing queue.

Return Value

Nothing

Example

DeptQ MaxQueueClass
  code
  DeptQ.Init(DepartmentQueue)
  DeptQ.Load('c:\temp\departments.txt')


See Also

Load, Save, SaveFile, Loading and Saving Queues .

Classes

MergeFrom

MergeFrom(MaxQueueClass pSource,Long pOptions=mq:overwrite)
MergeFrom(Queue pSource,Long pOptions=mq:overwrite)

Description

Merges the data from two queues, without duplicating rows.

NOTE: NOT YET RELEASED

Parameters

Parameter Description





Return Value

Nothing

Example

DeptQ MaxQueueClass
 


See Also

AddFrom, AddTo, CopyFrom, CopyTo, MergeFrom, MergeTo, Subtract .

Classes

MergeTo

MergeTo()

Description

Merges the data from two queues, without duplicating rows.

NOTE: NOT YET RELEASED

Parameters

Parameter Description



Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also

AddFrom, AddTo, CopyFrom, CopyTo, MergeFrom, MergeTo, Subtract .

Classes

Next

Next()

Description

Next takes the current record position, and returns the next record. The current record position can be set with a call to the Set method, however it can also be called after any other queue access, for example after a Get.

Return Value

mq:ok if a record was retrieved, mq:notok if the end of the queue has been reached.

Example

DeptQ MaxQueueClass
  code
  DeptQ.Init(DepartmentQueue)
  DeptQ.Set()
  Loop until DeptQ.Next()
    ! do something
  End


See Also

Set, Next, Previous, Set / Next Previous .

Classes

Pointer

Pointer()

Description

Works the same as the normal Clarion POINTER(QUEUE) command.

Return Value

Nothing

Example

x = mq.Pointer()
x = Pointer(mq)

See Also



Classes

Previous

Previous()

Description

Next takes the current record position, and returns the previous record. The current record position can be set with a call to the Set method, however it can also be called after any other queue access, for example after a Get.


Return Value

mq:ok if a record was retrieved, mq:notok if the end of the queue has been reached.

Example

DeptQ MaxQueueClass
  code
  DeptQ.Init(DepartmentQueue)
  DeptQ.Set()
  Loop until DeptQ.Previous()
    ! do something
  End


See Also

Set, Next, Previous, Set / Next Previous .

Classes

Put

Put()
Put(String pOrder)
Put(queuefield,<queuefield>,<queuefield>,<queuefield>,<queuefield>)

Description

Works the same as the normal Clarion PUT(QUEUE) command.
This writes back a row previously read with a Get (or Next, Previous Etc).
If no parameter is passed then the row is written back into the same place it was retrieved from. This could potentially break the sort order.

Parameters

Parameter Description
pOrder A string, containing a comma-delimited-list of field names. The names can optionally be prepended with + and - signs.
queuefield The name of field in the queue. Up to 5 fields can be passed. The record will be inserted into the queue in order, depending on these fields. These must match the current queue sort order.
pFunction A function, with the prototype Procedure(*Group pGroup1, *Group pGroup2),Signed
This will be passed through to the Clarion Queue engine in place of the Clarion Put call.

Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also

Add, Sort, Get, Put, Delete, Free, Clarion Help on PUT

Classes

Records

Records()

Description

Works the same as the normal Clarion RECORDS(QUEUE) command

Return Value

Nothing

Example

recs = mq.Records()
recs = Records(mq)

See Also



Classes

Save

Save(StringTheory pStr)

Description

Saves the queue to a CSV-like format, in a StringTheory object.

Note that Save does not follow reference fields, so this method is only useful on queues that do not contain reference fields. For more complex queues save the queue using jFiles or xFiles.

Parameters

Parameter Description
pStr
A StringTheory object to take the result of the method call

Return Value

Nothing

Example

DeptQ MaxQueueClass
str   StringTheory
  code
  deptQ.Init(DepartmentQueue)
  DeptQ.Save(str)


See Also

SaveFile, Load, LoadFile, Loading and Saving Queues

Classes

SaveFile

SaveFile(String pFileName)

Description

Saves the queue to a CSV-like format, to a file on the disk.

Note that Save does not follow reference fields, so this method is only useful on queues that do not contain reference fields. For more complex queues save the queue using jFiles or xFiles.

Parameters

Parameter Description
pFileName
The full path name of the file on the disk to receive the output of the method.

Return Value

Nothing

Example

DeptQ MaxQueueClass
  code
  DeptQ.Init(DepartmentQueue)
  DeptQ.SaveFile('c:\temp\departmentqueue.txt')


See Also

Save, Load, LoadFile, Loading and Saving Queues

Classes

Set

Set()
Set(String pIndex)
Set(String pOrder)
Set(queuefield,<queuefield>,<queuefield>,<queuefield>,<queuefield>) 

Description

Sorts the queue and sets the index ready to start processing with Next or Previous.

If no parameters are passed, then the index is set to the current record buffer position, using the existing sort-order fields. In this case the sort order is not changed.

The sort order can be set using a comma-delimited string, containing field names, optionally with the leading + or - symbol. the queue will then be sorted to this order. The current record position will be set.

The method can also take up to 5 specific queue fields. The queue will then be sorted on these fields, and the current record position set.


Parameters

Parameter Description
queuefield
Up to 5 fields in the queue. The queue will be sorted on these fields, and then the index will be set to the current position of the record.
pOrder The order desired when walking through the queue. This field is a string, containing a comma separated list of field names. The field names can be prefixed with either a + or - symbol to indicate the preferred sort direction.

Note that this field is a string, the list of field(s) should be in quotes. However if a single queue field, that belongs to this queue, is used here, the the queue will sort on this field. It will not evaluate the actual contents of the field before sorting.

Return Value

Nothing

Example

DeptQ MaxQueueClass
  code
  DeptQ.Init(DepartmentQueue)
  DeptQ.Set()
  Loop until DeptQ.Next()
    ! do something
  End

See Also

Set, SetFirst, SetLast, Next, Previous, Set / Next Previous .

Classes

SetFirst

SetFirst()

Description

Sets the position index to 1.
Equivalent to Set(1)

Return Value

Nothing

Example

DeptQ MaxQueueClass
code
DeptQ.Init(DepartmentQueue)
DeptQ.SetFirst()
Loop until DeptQ.Next()
! do something
End

See Also

Set, SetFirst, SetLast, Next, Previous, Set / Next Previous .

Classes

SetLast

SetLast()

Description

Sets the position index to the last record in the queue.
Equivalent to Set(Self.Records()).

Return Value

Nothing

Example

DeptQ MaxQueueClass
code
DeptQ.Init(DepartmentQueue)
DeptQ.SetLast()
Loop until DeptQ.Previous()
! do something
End

See Also

Set, SetFirst, SetLast, Next, Previous, Set / Next Previous .

Classes

Sort

Sort(queuefield,<queuefield>,<queuefield>,<queuefield>,<queuefield>)
Sort(String pOrder)
Sort(mq:QueueFunction pFunction)

Description

Works the same as the normal Clarion SORT(QUEUE) command. The queue is sorted

Parameters

Parameter Description
queuefield


Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also

Add, Sort, Get, Put, Delete, Free, Clarion Help on SORT

Classes

Start

Start()

Description

This returns the object to a virgin state, however the object does not detach from the queue (so a repeat call to Init is not required.)
Calling the Init method implicitly calls the Start method.

To disassociate the object from the queue, and return the object to a non-initialized state call the Kill method.


Return Value

Nothing

Example

DeptQ  MaxQueueClass
  code
  DeptQ.Start()

See Also



Classes

Subtract

Subtract()

Description

Subtracts the rows from one queue, if the data appears in another queue.

NOT YET RELEASED

Parameters

Parameter Description



Return Value

Nothing

Example

DeptQ MaxQueueClass


See Also

AddFrom, AddTo, CopyFrom, CopyTo, Merge, Subtract .

Classes

Trace

Trace(String pStr)
Trace()

Description

A debugging method which writes information out to DebugView (ie using the Windows OutputDebugString API call.)
If no parameter is set, then the whole contents of the queue are sent to debugview.

Parameters

Parameter Description
pStr
The string to send to Debugview.
If this parameter is omitted then the contents of the queue are sent to Debugview.

Return Value

Nothing

Example

DeptQ MaxQueueClass
  code
  DeptQ.Trace('Bruce was here')

See Also

Trace, TraceRecord, ErrorTrap .

Classes

TraceRecord

TraceRecord()

Description

A debugging method which writes information out to DebugView (ie using the Windows OutputDebugString API call.)
the current contents of the record are sent to debugview.

Return Value

Nothing

Example

DeptQ MaxQueueClass
code
DeptQ.TraceRecord()

See Also

Trace, TraceRecord, ErrorTrap .

MaxQueueGlobalClass

The MaxQueueGlobalClass is an extension to the MaxQueueClass, and so inherits all the properties and methods from that class. this class should be used when using Global Unthreaded Queues, as it makes the record buffer of those queue thread-safe. For more information see Global Unthreaded Queues.

Derivation

Properties

Property Type Description
crit &CriticalSection A reference to the CriticalSection used by this object. By default this references a shared CriticalSection, however if you wish your objects to use different critical sections then you can set this.
grp &Group A reference to the threaded Record group.

Methods

Classes

ClearHold

ClearHold()

Description

This method clears any hold placed by a Hold command. Call this method to explicitly clear any waiting, or current, hold.

Return Value

Nothing

Example

DepartmentQueue.ClearHold()

See Also

Global Unthreaded Queues , Global WritingHold, ClearHold.

Classes

Hold

Hold()

Description

This will block the queue on other threads for the duration of a single read, and a single write. In other words, on the first read the queue will be blocked. The block will be cleared after another read, or any write.

For a more indepth description of the use case for Hold, and how to use it, see Global Writing.

Return Value

Nothing

Example

DepartmentQueue.ClearHold()

See Also

Global Unthreaded Queues , Global Writing , Hold, ClearHold.

Classes

Init

Init(*Queue pQueue, *Group pGroup)

Description

This method binds the Global (threaded) MaxQueueGlobal object to a global (unthreaded) queue, and a global (threaded) record. This method needs to be called at the start of every thread[1] as the MaxQueueGlobal object is threaded. This is typically done in the global MaxQueue extension template, or it can be done in code.

[1] Note - A useful way of running code at the start of every thread, is to put it in the Construct method of a global unthreaded object.

Parameters

Parameter Description
pQueue The label of the unthreaded queue that will be attached to this object.
pGroup The label of the threaded record group that will be attached to this object.

Return Value

Nothing

Example

DepartmentQueue.Init(_DepartmentQueue,DepartmentQueueRecord)

See Also

Global Unthreaded Queues .

Classes

RestoreGroup

RestoreGroup()

Description

This method restores the record, and index, as stored with a previous call to SaveGroup.

Return Value

Nothing

Example

DepartmentQueue.RestoreGroup()

See Also

Global Unthreaded Queues , Global Writing , Hold, ClearHold, SaveGroup .

Classes

SaveGroup

SaveGroup()

Description

This method makes a copy of the current record and index value, and stores it internally. Using RestoreGroup, restores the buffer.

Return Value

Nothing

Example

DepartmentQueue.SaveGroup()

See Also

Global Unthreaded Queues , Global Writing , Hold, ClearHold, RestoreGroup .

Classes

Wait / Release

Wait(String pProc)
Release(String pProc)

Description

These are the Wait and release methods for the built-in critical section. All MaxQueueGlobal objects use the same critical section. You should not need to call these methods directly - they will be called internally by the class as needed. Note that errors in using these methods can lead to lockups or GPF's, so use of these methods directly is strongly discouraged. They should only be used in derived classes, and in other limited cases where all access to the global queue has to be blocked.

Parameters

Parameter Description
pProc The name of the procedure calling the critical section. This parameter is not used directly, however it can be enormously useful when debugging lockups caused by critical sections. 

Return Value

Nothing

Example

DepartmentQueue.Wait('ProcessCustomers')
! some code goes here

DepartmentQueue.Release('ProcessCustomers')

See Also

Global Unthreaded Queues .

Version History

TODO 1.07 -  11 January 2024
1.06 -  27 August 2023
1.05 -  25 August 2023
1.04 -  26 October 2022
1.03 -  25 October 2022
1.02 - beta - 8 February 2022
1.01 - beta - 23 December 2021

1.00 - beta - 5 November 2021