|
Integrated Database Details |
current record, the
special variable _extracted is set to zero, otherwise it is the number of records
that the operation produced.
sort by or sort descending by
clauses.FOR EACH statement begins execution.When a table is opened for input, records are implicitly unlocked as they become current.
When a table is opened for update or output, records are implicitly locked whenever a field value is modified.
In cases where a field is being incremented or otherwise read and
written in the same operation, it is recommended to explicitly lock
the table first using lock table. This ensures correct
behavior in concurrent environments.
Whenever a new record is made current, any previously locked records are virtually written to storage and unlocked.
Modified records are physically written to storage using lazy writes, allowing updates to be batched efficiently.
To explicitly unlock a table, use:
To unlock all tables, use:
To flush all virtual writes for a table and commit them to storage, use:
To commit all writes for all tables, use:
Sheerpower provides four main methods for key lookups in tables:
After any key lookup or extract operation, _extracted
contains the number of matching records found.
_extracted will be zero if no record
was found; otherwise it will be one.
set table is intended for lookups that expect at most
one matching record.
The exclude statement is used to exclude records from the
extract block that match the logical expression nn.
Example:
This example excludes employees who are under 18 years old and those who have an inactive status from the extract block.
The include statement is used to include only
those records that match the logical expression nn.
Example:
This example includes only sales records from the North region with an amount greater than $1000.
The exit extract statement is used to exit the extract block and with the collected records up to that point.
Example:
This example exits the extract block if an order date is before January 1, 2023, and processes the collected records.
The cancel extract statement is used to cancel the entire extract block without collecting any records.
Example:
This example cancels the extract block if any item has a quantity of 0, resulting in no records being processed.
The sort by xxx statement is used to sort the records in ascending order based on the expression xxx.
Example:
This example sorts the customer records by their last names in ascending order.
The sort descending by xxx statement is used to sort the records in descending order based on the expression xxx.
Example:
This example sorts the product records by their prices in descending order.
The extract table block creates a collection of table records. When the
EXTRACT BLOCK is exited, the special variable _extracted contains the
number of records in the most recent extract. Typically after an extract
block is a FOR EACH block that iterates through the collection.
If the EXTRACT BLOCK contained any SORT statements,
the sorting is deferred until the FOR EACH block is executed.
This enables dramatic performance improvements if later using the reextract or
append options.
Code Explanation:
1. Open Tables:
These lines open two tables named client and detail from the specified file paths (@..\safe\client and @..\safe\detail). The tables are made available for further operations like extracting records, querying, and sorting.
2. Extract All Records:
This block extracts all records from the client table. The _extracted variable holds the number of records extracted, which is then printed to inform the user how many records were found.
3. Set ID Based on Input:
This conditional block checks if the string a$ has a length greater than 0 (i.e., it is not empty). If a$ is not empty, my_id$ is set to the value of a$; otherwise, my_id$ is set to the default ID '80522'.
4. Lookup Record by ID:
This block sets the client table to look for a record with an id matching my_id$. The _extracted variable will hold the number of matching records (either 0 or 1).
5. Print Client Information:
If no record was found (_extracted = 0), the program prints "Unknown ID". Otherwise, it prints the client's last and first names.
6. Extract Clients from California (Excluding Area Code 619):
This block extracts records from the client table where the state is 'CA', excluding those whose phone number starts with '619'. The results are sorted in ascending order by the last name.
7. Print Extracted Clients:
This loop iterates over each extracted client and prints their ID, first name, last name, and phone number.
8. Extract Clients Excluding Area Code 619:
This block extracts records from the client table, excluding those whose phone number starts with '619'. No sorting is specified.
9. Print Extracted Clients:
This loop iterates over each extracted client and prints their first name, last name, and phone number.
10. Sort Clients by State and Last Name:
This block extracts and sorts clients first by state (major sort) and then by last name (minor sort).
11. Print Sorted Clients:
This loop iterates over each sorted client and prints their last name, first name, and state.
12. Extract Clients with Last Name Starting with 'R':
This block extracts records from the client table where the last name starts with the letter 'R'.
13. Print Clients with Last Name Starting with 'R':
This loop iterates over each client whose last name starts with 'R' and prints their first and last names.
14. Re-extract Clients from California:
This block extracts records from the client table where the state is 'CA'. The records are held for further re-extraction.
15. Re-extract and Sort Clients in Area Code 619:
This block further filters the already extracted records, keeping only those whose phone number starts with '619', and sorts them by last name.
16. Print Sorted California Clients in Area Code 619:
This loop iterates over the re-extracted records and prints the first name, last name, and phone number of clients in California with the '619' area code.
17. Extract Details with Specific Line IDs (First Range):
This block clears previous extractions (extracted 0) and extracts records from the detail table with lineid between '10301001' and '10302000'. The results are sorted by prodnbr and invnbr.
18. Extract Details with Specific Line IDs (Second Range):
This block appends to the previous extraction, extracting records with lineid between '10311001' and '10312000'. The results are sorted similarly by prodnbr and invnbr.
19. Print Header for Details:
Prints a header for the detail records, aligning columns for Prod, Line ID, and Quantity using tab() for spacing.
20. Print Extracted Details:
This loop iterates over each extracted detail record and prints the product number, line ID, and quantity, aligned under the header.
In Sheerpower, after you've finished working with a table, it's important to properly close it to free up system resources and ensure that all data operations are completed correctly. The correct syntax for closing a table is:
First, you open the table using the open table
command.
You can perform various operations like extracting, filtering, sorting, and iterating over records.
Once you've completed your operations, use the close
table statement to close the table.
Closing tables ensures that:
Using close table tablename is the recommended
practice to maintain the integrity and efficiency of your Sheerpower
applications.
Sheerpower's integrated database delivers table scanning speeds exceeding 1.5 million records per second with 1000 byte records on modern consumer PCs. This performance is achieved through:
extract then for each)Sheerpower provides record-level concurrency, enabling multiple users to safely access and modify data simultaneously without blocking entire tables. This means:
On a typical modern PC, this operation completes in well under one second, even with concurrent users accessing the same table.
Understanding the physical layout of the ARS database engine helps explain why Sheerpower's database behaves the way it does—why sequential scans are so fast, why multiple keys have no performance hierarchy, and why there is no concept of a primary key.
ARS stores records in a linked list of large data buckets. Each bucket holds many records packed together, and the buckets are chained in sequence. This is the physical home of all record data—field values live here, and only here.
Keys are stored separately, in key buckets. Each key bucket holds key values together with pointers back into the data buckets. When you look up a record by key, ARS navigates the key bucket to find the pointer, then follows that pointer directly to the data record.
This separation—data in one structure, keys in another—is the foundation of every performance and concurrency property the engine provides.
Why this matters: In many traditional database engines, records are physically organized around a single "clustering key." Changing that key means moving the record. In ARS, the data record never moves—only the key bucket entry changes. This makes all key updates equally inexpensive, regardless of which key is being changed.
Solution: By decoupling key storage from data storage, ARS treats every key as an equal citizen. There is no primary key that owns the physical layout, and no secondary keys that pay a performance penalty for that reason.
Efficiency: Adding a new key to a table creates a new key record pointing into an existing data bucket. The data records themselves are untouched. Key lookups are fast regardless of how many keys the table carries.
Takeaway: All keys in ARS are changeable, all are equal, and none owns the data. The uniqueness of a record identifier is the application's responsibility—not a database constraint.
ARS has no concept of a primary key. Every key defined on a table is simply a key—a navigational path into the data buckets. Any key value can be changed at any time without reorganizing the underlying data.
When a Sheerpower application needs a stable, unique record identifier,
use _gid$—a 30-byte globally unique identifier
(YYYYMMDD + UUID) generated by the Sheerpower runtime.
Because _gid$ is generated locally within each process,
two instances of the same handler running simultaneously will never
produce the same value. No counters, no sequence generators, and no
inter-process coordination are required.
add table todos todos(id) = _gid$ // globally unique, generated locally todos(status) = 'open' todos(priority) = priority$ todos(description) = desc$ todos(last_datetime) = fulltime$ end add
Because all data records live in a linked list of large, packed data buckets, a full table scan is a straight sequential walk through those buckets—no index navigation, no random access, no page splits to work around. Modern CPUs and memory controllers are highly optimized for exactly this access pattern. This is why Sheerpower delivers over 1.5 million record scans per second on consumer hardware.
When you write an extract table block without a key clause, ARS
walks the data bucket chain from start to finish. The performance you see is
a direct consequence of the physical layout—not a tuning achievement.
Record-level locking in ARS is straightforward because of the physical separation between key buckets and data buckets. When a record is locked, the lock is on the data record—not on any key entry, not on a page, not on the table. Other processes can still navigate key buckets freely, and can read or write any other data record in the same table without interference.
Changing a key value on a locked record updates only the key bucket entry. The data record itself stays in place in its data bucket. This means a key change and a field value change both touch only the minimum necessary structures—and lock only what they actually modify.
Why this matters: Traditional page-level or table-level locking blocks all readers and writers on that page or table while any single operation is in progress. Under load, this becomes a bottleneck that scales poorly.
Solution: ARS locks individual data records. The lock scope is exactly as wide as the operation requires—one record—and no wider. Readers and writers on other records in the same table proceed without waiting.
Efficiency: The unlock all: commit pattern
at the top of a transaction loop releases all locks from the previous
request and forces dirty records to be written to storage.
As a result, no locks are held during idle time. Contention is bounded by the duration of actual computation—not by network or client delays.
Takeaway: Fine-grained record-level locking combined with disciplined commit boundaries means multiple handler instances can read and write the same table simultaneously with minimal contention.
Because the ARS database engine is integrated directly into the Sheerpower runtime, deadlock detection has access to information that an external database engine cannot see—the exact source lines executing in each process at the moment the deadlock occurs.
When a deadlock is detected, the Sheerpower diagnostic utility
arslockmon reports not just the process IDs involved, but the
precise source files and line numbers where each process is waiting.
An investigation that might take hours of log correlation in a traditional setup becomes immediate.
Many database systems accept queries as strings of text that are parsed and executed at runtime. A malicious user who can control part of that string can inject additional commands—altering the query's intent, bypassing access controls, or destroying data.
Sheerpower's database access works differently at a structural level. There is no query language. There is no string that gets parsed into a command. Key values, field values, and filter expressions are passed directly to the ARS engine as typed data—they are never interpreted as code.
set table customers, field customer_id: key id$
Whatever is in id$ is treated as data. It cannot alter execution.
There is no parser to subvert.
Why this matters: SQL injection is one of the most persistent vulnerabilities in web applications.
Solution: ARS separates data from operations at the architectural level.
Efficiency: No sanitization, no parameterization, no developer burden.
Takeaway: The vulnerability class does not exist in this architecture.
The 1.5 million records per second figure is a direct result of the physical storage layout.
Sequential scans are linear, cache-friendly, and efficient. Key lookups are shallow and consistent. Shared memory caching reduces disk access. Writes are batched at commit boundaries.
Why this matters: Traditional database performance requires tuning and monitoring.
Solution: ARS performance follows directly from its design.
Efficiency: Multiple handler instances scale naturally.
Takeaway: Development performance matches production.
open table allows access to persistent database files
with built-in concurrency and locking support.extract ... end extract to build a filtered and/or
sorted collection of records from a table.for each iterates through the extracted records;
records are current during iteration.set table or extract table ... key._extracted reflects how many records matched the
last extract or key lookup (0 means no match).include and exclude in
extract blocks to precisely define which records to process.sort by and sort descending by sort
extracted records by one or more fields.cancel extract aborts the current extract block;
exit extract exits early but keeps collected records.reextract applies new filters/sorts to an existing
extracted record set without re-accessing disk.close table tablename
after use to free system resources and ensure data integrity.print table(field) syntax to access individual
fields from a current record.|
Hide Description
|
|
|
Enter or modify the code below, and then click on RUN |
|
Looking for the full power of Sheerpower?
Check out the Sheerpower website. Free to download. Free to use. |