Beside classical “position indicator” meaning, in database jargon CURSOR means CURrent Set Of Records; or Current Selected set of records.
If a whole table is in use with all records, this table may be considered as a cursor. But when talking about a cursor, this means in general, “selected” records. A CURSOR may be real a table as a disk file, or a temporary table in memory.
Since “current” means temporary usage, for this purpose, for a temporary table in memory, using a uniform array may be a god way. Of course this way is limited by size (record count) of table. When conditions are available, using CURSOR may be more usable than direct using of a table.
In real life conditions building a cursor requires some “selection” process and may be quite complex, such as compiling data various sources, applying some selection criteria, and building a table (data set) with totally new structure may be required. These details are out of this article. We will work here only using an array as cursor, or simply using an array as a table.
So, first step is transfer data from a table to an array. Again, size (record count) of table is critical in this process.
Let’s look the sample .prg :
/* CURSORs */ PROCEDURE Main() SET DATE GERM SET CENT ON USE CUSTOMER aCustomers := {} // Declare / define an empty cursor: an uniform array WHILE .NOT. EOF() a1Record := ARRAY( FCOUNT() ) AEVAL( a1Record, { | x1, nI1 | a1Record[ nI1 ] := FIELDGET( nI1 ) } ) AADD( aCustomers, a1Record ) DBSKIP() ENDDO ? ? "Traversing cursor :" ? a1Record := {} FOR EACH a1Record IN aCustomers ? AEVAL( a1Record, { | x1 | QQOUT( x1, '' ) } ) NEXT ? ? "Locating a specific record in an array by key :" ? nRecord := ASCAN( aCustomers, { | a1Record | a1Record[ 1 ] == "CC003" } ) ? AEVAL( aCustomers[ nRecord ], { | x1 | QQOUT( x1, '' ) } ) /* At this point, data in the cursor may be edited via forms ( one form for each row of cursor) or via a TBRowse. After getting user confirmation ( do you save all modifications you made ? ) the cursor may require write back to the orijinal source, that is the table. */ ? ? "Write back the cursor to table :" ? DBGOTOP() FOR EACH a1Record IN aCustomers ? RECN() AEVAL( a1Record, { | x1, nI1 | FIELDPUT( nI1, x1 ), QQOUT( nI1 ) } ) DBSKIP() NEXT ? "That's all ! ... " @ MAXROW(), 0 WAIT "EOF Cursors.prg" RETURN // Cursors.Main()