From Br Wiki
Jump to: navigation, search

The prior version was 4.2

Note that the information release notes have been incorporated into the relevant wiki pages, but are left here in their original form.

Grid and List Changes

Arrays are automatically resized when receiving data from 2D INPUT operations. This also applies to grouped arrays. Automatic resizing only applies to one dimensional arrays and does not occur when INPUTing into two dimensional arrays.

Example where all arrays are one dimensional and may have the incorrect number of elements:

INPUT FIELDS "row,col,LIST rows/cols, ROW, ALL" : (MAT Array1$, MAT Array2$, MAT Array3, MAT Array4, MAT Array5$)

Three New Read Types

Notes: Auto Resizing applies

Selection Type must be ALL

The original 2D INPUT read types are:

 CNT	 - The number of cells specified.
 SUB	 - Read the Cell Subscript Values.
 CELL	 - Read each cell specified.
 ROWCNT - The number of rows specified.
 ROWSUB - The subscripts of the specified rows.
 ROW	 - Read all cells in each specified row.
HEADERS – The original PRINT FIELDS HEADER values.


 COLCNT - The number of columns established by the header arrays.

e.g. INPUT FIELDS "row,col,LIST rows/cols, COLCNT, ALL" : numeric-variable

These are for generalized library routines to inspect passed controls.

 SORT_ORDER - Provides a value of zero for each unsorted column and gives the ascending sequence of column sorts that have occurred. If a column has been reversed (double sorted) it's value will be negative.

e.g. INPUT FIELDS "row,col,LIST rows/cols, SORT_ORDER, ALL" : numeric-array Given the following history of sorting a four column GRID: • column 1 (descending most recent) • column 2 (ascending first sorted) • column 3 (not sorted) • column 4 (sorted ascending)

SORT_ORDER would return- array(1) -> -1 array(2) -> 3 array(3) -> 0 array(4) -> 2

Restoring a User Sorted 2D Control

The syntax for sorting an array is currently:

PRINT FIELDS "nn,nn,GRID 10/40,SORT": { column number }

This has been extended to allow a numeric array of instead of a scalar. If an array is given, it is assumed to be in the same format that SORT_ORDER returns. The new format is:

PRINT FIELDS "nn,nn,GRID 10/40,SORT": { column-number | numeric-array }

Where the numeric-array has one element for each column left to right. BR will resort the columns in the requested order.

The numeric array values indicating the order of column sorting to be performed do not need to exactly match the standard format. e.g Fractions are allowed, the values can fall within any range, and there does not need to be trailing zero elements for unsorted columns.

A new Read Qualifier is available.

 DISPLAYED_ORDER - indicates that the read operation is to not restore the data into it's original order before returning the results to the program.

e.g. INPUT FIELDS "row,col,LIST rows/cols, ROWSUB, ALL, DISPLAYED_ORDER, NOWAIT": numeric-array This reads the original row subscripts for all rows - in their present order. This qualifier works only with the ALL selection type. It may be used in conjunction with other qualifiers such as FKEY.

Range Selection Type

Valid current selection types are:

 SEL	- Read one or more selected items.
 SELONE - Select only one item.
 ALL	- Read all items in the control (except headings).
 CUR	- Current cell or row number.
 CHG	- All cells or rows who’s values have been changed by the operator.

BR now supports the following additional selection types:

 RANGE - Specifies which portion of a 2D control is to be input.
 CELL_RANGE – A special type of output range.

Range Input

In the folowing examples BR will redimension the receiving arrays as needed:

 INPUT FIELDS "row,col,LIST rows/cols, CELL, RANGE" :
            start, end, MAT Data$

This reads the specified range of cells. BR redimensions MAT Data$ as needed. Note that CELL may now be used with LIST. Previously, LISTs were only addressable by row.

 INPUT FIELDS "row,col,LIST rows/cols, ROW, RANGE" :
            (start:=7), (end:=11), ( MAT Array1$, MAT Array2, MAT Array3$ )

This reads the cells in rows 7 through 11. The recieving arrays are redimensioned as appropriate.

 INPUT FIELDS "row,col,GRID rows/cols, ROW, RANGE" :
            MAT start, MAT end, ( MAT Data1$, MAT Data2$, MAT Data3 )

This reads one or more ranges of rows.

A more detailed example of this is:

 100 -- create and populate a LIST control --
 200 MAT START(3) : MAT END(3)
 220 DATA 7,21,33
 230 DATA 11,21,38
 240 INPUT FIELDS "row,col,LIST rows/cols, ROW, RANGE" : MAT START,
           MAT END, ( MAT Array1$, MAT Array2, MAT Array3$ )

This reads 12 rows of data ( row 7-11, row 21 and rows 33-38 ).

Range Output

By default, RANGE output refers to rows. The special keyword CELL_RANGE is used to denote the specification of cell ranges. Additionally, the use of scalars versus arrays for start and end values determines important characteristics of the output process.

Using Scalars For Range Specification

 PRINT FIELDS "7,8,GRID 10/75, RANGE": start, end, MAT Data$

This replaces the values in rows numbered 'start' through 'end' with the data in MAT Data$. The size of MAT Data$ must be a multiple of the number of columns in the GRID or an error is generated.

 PRINT FIELDS "7,8,LIST 10/75, RANGE": start, end, (MAT NAME$,
                                         MAT CITY$, MAT AGE, MAT WEIGHT)

This replaces the values in ROWs numbered 'start' through 'end' with the data from MATs NAME$, CITY$, AGE and WEIGHT. The data arrays must all be dimensioned the same.

Insertion and Deletion

The number of rows being output do not need to match the number of rows being replaced. To delete a range of rows, output one or more grouped arrays with zero elements.

Examples- Using the following statement various scenarios are described.

 PRINT FIELDS "7,8,LIST 10/75, RANGE": start, end, (MAT NAME$,
                                         MAT CITY$, MAT AGE, MAT WEIGHT)
 start=7, end=11, and the arrays have been DIMed to nine elements
 Result- Nine rows replace five, and the total content of the control is
         expanded by 4 rows.

 start=7, end=11, and the arrays are DIMed to zero elements
 Result- Five rows are deleted, and the total size of the control is
         reduced by 5 rows.
 start=7, end=0 (anything less than 7), and the arrays are DIMed to
          support three rows
 Result- Three rows are inserted ahead of row seven and the total content
         of the control is expanded by three rows
 start=5000, end={any value}, the control only has 482 rows, and the source
         arrays are DIMed to support eleven rows
 Result- Eleven rows are appended to the end of the control and become
         rows 483 through 493.

Outputting Ranges of Cells

Ranges of cells may be output in conjunction with the CELL_RANGE keyword.

 PRINT FIELDS "7,8,LIST 10/75, CELL_RANGE": start, end, (MAT NAME$,
                                         MAT CITY$, MAT AGE, MAT WEIGHT)
                               - or -
 PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, end, MAT Data$

In this case, start and end specify cells instead of rows. If insertion or deletion is indicated by dimensioning the data arrays to greater or fewer elements than are being replaced, then the data must be a multiple of the number of columns. Insertion and deletion is only valid in terms of rows, even when cell subscripts are used to specify ranges. In such cases, if the cell subscripts are not on row boundaries, an error is generated.

 PRINT FIELDS "7,8,GRID 10/75, CELL_RANGE": start, start, Data$

In this example, the value in one cell is replaced with the content of a scalar.

Using Arrays For Range Specification

If the start and end specifications are arrays, denoting multiple ranges, there must be a one to one correspondence between the number of rows specified and those in the data. This method implies replacement only and insertion or deletion is not allowed.

The data flow that this feature was designed to support is one where the user is presented with a LIST or GRID where multiple rows have been either selected or changed before returning control to the program and the program is responding by updating something on those rows.

The program begins by presenting a 2D control to the user and reading the the control with type ROWSUB or SUB. Type SUB only works for GRIDs where all colmns have the same data type. Of course the subscripts are read into a numeric array which BR redimensions as appropriate. Then the program reads the changed or selected data with NOWAIT. (This resets the CHG flags in the control.) The program then changes either row (ROWSUB) or cell (SUB) data and outputs the results using the subscript array as both the start and end specification. Other scenarios are possible but this is the primary intended use.

An example of this is:

 100 -- create and populate a GRID --
 200 INPUT FIELDS "row,col,GRID rows/cols,ROWSUB,CHG": MAT Rowsubs
        (Reading subscripts does not reset the CHG flags in the control.)
 210 INPUT FIELDS "row,col,GRID rows/cols,ROW,CHG,NOWAIT": ( MAT Data1$,
                                 MAT Data2, MAT Data3$ )
         BR redimensions the receiving arrays as needed.
        (Reading the data also resets the CHG flags in the control.)
 220 -- process the changed rows now present in the data arrays --
 300 PRINT FIELDS "row,col,GRID rows/cols,RANGE": MAT Rowsubs,
                  MAT Rowsubs, ( MAT Data1$, MAT Data2, MAT Data3$ )

This outputs the updated rows.

Logging Enahncements

See Logging for details.

Fine Grain Field Positioning

ROW/COL and ROWS/COLS in FIELDS operations may be expressed as decimal fractions.

CSV and XML Parsing Enhancements

See Str2Mat for details.

New DLL Structure of Business Rules!

As of Release 4.3 Business Rules! is restructured into the following modules:

Client and Server User Interface Modules

Processor DLLs – Stored in the AppData\Local directory for each user and on each server.

Updates will pertain to Processor DLLs while the user interfaces will remain as installed. Client DLLs will be automatically uploaded when corresponding server DLLs are accessed in the event they are not already present on the client.

The client can be accesed from within a browser by initiating it with HTML which can specify an embedded window or a separate independent window. In all cases opening a window with PARENT=NONE creates a separate window.

Each user will have a copy of either brcombined.exe or brclient.exe, but there are no licensing concerns because clients are not licenced. Only BR Servers are licensed.

Client Server Reconnect Configuration Statement


The client will attempt to reconnect to the server after RECONNECT_AFTER seconds (default is 20 seconds).

ERROR_AFTER generates a BR error and awaits for reconnection (default is 120 seconds).

EXIT_AFTER generates a BR error and continues in unattended mode ( no client IO allowed - exit at next keyboard wait ). This is the normal exit from an unrecoverable disconnect (default is 240 seconds).

If both ERROR_AFTER and EXIT_AFTER are specified, EXIT_AFTER will terminate an ERROR_AFTER wait.

When a client is attempting to reconnect, it displays the session number it is using. The normal client login window will contain a check box that facilitates the entry of a reconnection session number. This allows reconnection from another workstation.

Autoit Support

Right now Autoit has trouble reading BR window content. We will correct that and see what other features we can provide to ease the integration of Autoit with BR, including possibly supporting Autoit DLL linkage.

ODBC Version 4.3

ODBC version 4.3 released.

SQL Support

BR will use a single SQL server module to perform all SQL database access. This ‘engine’ will communicate with multiple BR sessions via TCP/IP. Normally the engine resides in the same directory as BR, but may reside elsewhere on the network.

New World SQL Support

Config Database

CONFIG DATABASE may use one of 3 methods for connecting to SQL Sources

  • DSN


CONFIG DATABASE db-ref DSN=dsn-ref [, USER= department | LOGIN_NAME | ? ] [, {PASSWORD= dept-password | BR_PASSWORD | ?} | PASSWORDD=encrypted-passwd ]

    ? indicates prompt



CONFIG DATABASE db-ref CONNECTSTRING="Driver={Microsoft Access Driver (*.mdb)} DBQ=C:\inetpub\wwwroot\BegASP\Chapter.14\Contact.mdb"

Sample Connection Strings:

Using a SQL Server /w SQL Login:
CONFIG database db-ref connectstring="DRIVER=SQL Server;SERVER=server;Initial Catalog=database;UID=username;PWD=password"
db-ref is the database reference.
server is the SQL Server [FQDN] or IP Address
database is the [SQL Server Database] 
username is the [SQL Server User Name]
password is the [SQL Server Password]
Using a SQL Server /w Windows Authentication:
CONFIG database db-ref connectstring="DRIVER=SQL Server;Initial Catalog=database;Persist Security Info=True;MultipleBC_TableResultSets=True; Database=database;SERVER=server;Login Name=username;Password=BR_PASSWORD"
db-ref is the database reference.
server is the SQL Server [FQDN] or IP Address
database is the [SQL Server Database] 
username is the [SQL Server User Name]
Note that BR_PASSWORD will use the users Active Directory password to connect to the SQL Server.
Note that "SQL Server" is one of several choices for SQL Server, another choice would be SQL Server Native Client 11.0



Using ODBC Manager as the parameter will allow the end use to select the desired datasouce.

Open SQL

OPEN #20: "DATABASE= db-ref" , SQL "sql-statement", OUTIN


            - or -

OPEN #20: "DATABASE= db-ref, Name= filename" , SQL, OUTIN

    - filename refers to a DISPLAY file containing an SQL statement
      that gets executed when a WRITE statement is processed -

Begin processing with a WRITE statement. If the WRITE conatins an IO list of values then it is used to populate the

 'filename' SQL before it is executed.

This may or may not produce a result set. If it does, the result set may be

 processed like a BR file opened RELATIVE. Some operations that use file
 positioning may be slow since the whole result set may not be in memory
 immediately. Simple sequential access should be fairly quick.

Once SQL has been populated by an IOlist, it may be reused with the same values

 by issuing a WRITE with no IOlist.

READ IOlist variable associations are positional with each READ accessing one

 row of values.

New System Functions A$ = SQL_DATE("date-value" [,"value-format"]) ! format date for storage B$ = BR_DATE(vtring-var$ [,"format"])  ! upack DB date value

  • Note: SQL DATETIME fields are "Packed for Storage", but "DATE" fields are returned as a CCYY-MM-DD string in a SQL Query. DATE returns "BLANK" for "Empty or Null Date"

(Future) Legacy SQL Support

!!! This feature is a planned addition, and is not implemented yet!!!

If a file that is opened INTERNAL is really a DISPLAY file which has as the first four characters "#SQL" then the file will be regarded as an SQL Reference file which must be in the following format:

   DATABASE= -DB ref-  
   CONTEXT= dictionary-path

The file may then be processed as an INDEXED or RELATIVE BR file. If Indexing is specified, the Index file is used to identify the key elements to be used by BR for record selection. Split keys are broken into multiple values by field length.

When a READ or WRITE is issued, BR transfers data between variables in memory and data in the DB using its own internally generated SQL control statements. It uses the ODBC dictionary (CONTEXT) to translate BR FORM statement field positions and formats to dictionary field names. These names are then used to access the database during READ and WRITE operations.

Other Developments

Gary Hoff may get into the development cycle for some BR 4.4 features that will move BR into the world of mobile computing.