
In v2.2, a major, major change was made in the Database Browser Collection.  
What used to be known as ADdb_columns() is now ADdb_fields().  The meaning
of ADdb_columns() was also changed.  The meanings of the various APIs (listed
below) that are tied to the old meaning of ADdb_columns() were also changed.

Make sure you change all your ADdb_columns() calls to ADdb_fields() before
relinking with v2.2.  If you do not, your linked app will display an error
message like this:


and will stop.

Moreover, if the new ADdb_columns() is actually used to define the
browse columns, the following APIs need to be changed as well:

ADdb_fldread() to ADdb_colread()
ADdb_adget() to ADdb_colget()
ADdb_fldget() to ADdb_colvalue()
ADdb_fldput() to ADdb_colchange()
ADdbget_color() to ADdbcg_color()
ADdbget_dict() to ADdbcg_dict()
ADdbget_extra() to ADdbcg_extra()
ADdbget_lock() to ADdbcg_lock()
ADdbget_stay() to ADdbcg_stay()

Error messages will be displayed if ADdb_fldread(), ADdb_adget(),
ADdb_fldget() and ADdb_fldput() are used in conjunction with
ADdb_columns().

These APIs will be irrelevant in the ADdb_columns() context:
------------------------------------------------------------
ADdb_fldtype() 
ADdb_fldname()
ADdb_fldpos()

This new API will return the expression type of current column
---------------------------------------------------------------
ADdb_coltype().

Example
ADdb_columns( {;
                { "Field Pos",  1 },;
                { "Field Name", "COUNTRY" },;
                { "{|x|fieldget()}", {|x|if( x == NIL, fieldget(1), fieldput(1,x) )} },;
                { "{|x|field name}", {|x|field->country} };
              };
            )

if current column in browse is column #1, ADdb_coltype() returns "N".
if current column in browse is column #2, ADdb_coltype() returns "C".
if current column in browse is column #3, ADdb_coltype() returns "B".
if current column in browse is column #4, ADdb_coltype() returns "B".



Rationale behind this _drastic_ change
--------------------------------------
The old ADdb_columns() which has been changed to ADdb_fields() in v2.2 was
field-oriented as opposed to column-oriented.  The parameter that it
accepted was an array of field positions, rather than column definitions.
Moreover, these field positions were limited to one database.  To
accommodate columns that do not correspond to fields from the sole
database, one had to resort to ADdb_defcolumn().

The new ADdb_columns() aceepts an array of column definitions, which may
take the form of field positions, field names and even codeblocks. 
Furthermore, they can be aliased.  Clearly this ADdb_columns() in v2.2 is
more powerful, more flexible and more configurable than in v2.1.  Browsing
related databases in one browse engine is much more straightforward now.

Why did I have to change the meaning of ADdb_columns() instead of simply
creating another API for the new functionality and leaving ADdb_columns()
alone?  Very good question!  And very valid too!  I had to think hard
before I made the change.  To cut the explanation short, I concluded that
the old meaning of ADdb_columns() was misleading.  It just had to be
changed.  ADdb_fields() seemed to be much more appropriate.

Code Modification Example 1
---------------------------
   func example1()
   local bConfig := {||ADdb_columns( { 1, 2, 3 } ),;
                       ADdb_colheadings( { "Col 1", "Col 2", "Col 3" } );
                    }

   use mydbf
   ADdbview( ,,,, bConfig )
   use
   return NIL

becomes

   func example1()
   local aColumns := {;
                        { "Col 1", 1 },;
                        { "Col 2", 2 },;
                        { "Col 3", 3 };
                     }
   local bConfig := {||ADdb_columns( aColumns )}

   use mydbf
   ADdbview( ,,,, bConfig )
   use
   return NIL


Code Modification Example 2
---------------------------
   func example1()
   local bConfig := {||ADdb_columns( { 1, 2, 3 } ),;
                       ADdb_colheadings( { "Col 1", "Col 2", "Col 3" } ),;
                       ADdb_fldread();
                    }

   use mydbf
   ADdbview( ,,,, bConfig )
   use
   return NIL

becomes

   func example1()
   local aColumns := {;
                        { "Col 1", 1 },;
                        { "Col 2", 2 },;
                        { "Col 3", 3 };
                     }
   local bConfig := {||ADdb_columns( aColumns ),;
                       ADdb_colread(); 
                    }

   use mydbf
   ADdbview( ,,,, bConfig )
   use
   return NIL


Code Modification Example 3
---------------------------
   func example1()
   local bConfig := {||ADdb_columns( { 1, 2, 3 } ),;
                       ADdb_colheadings( { "Col 1", "Col 2", "Col 3" } ),;
                       ADdb_keys( { K_F10 }, {||ADdb_adget()} );
                    }

   use mydbf
   ADdbview( ,,,, bConfig )
   use
   return NIL

becomes

   func example1()
   local aColumns := {;
                        { "Col 1", 1 },;
                        { "Col 2", 2 },;
                        { "Col 3", 3 };
                     }
   local bConfig := {||ADdb_columns( aColumns ),;
                       ADdb_keys( { K_F10 }, {||ADdb_colget()} ); 
                    }

   use mydbf
   ADdbview( ,,,, bConfig )
   use
   return NIL
