WL#9553: Upgrading the transactional data dictionary tables.

Affects: Server-8.0   —   Status: Complete

The MySQL server must support changing the definition of the data dictionary
tables between two mysqld server versions. At server restart, the server checks
if upgrade is needed (and possible), based on persistent version information. If
upgrade is not needed, the server continues with an ordinary restart. Otherwise:

1. Create a new set of DD tables with the desired table definitions.

2. For each dictionary object table, copy the persisted (meta) data from
   the old DD tables (which need to be upgraded) to the new ones (which
   have the desired definition).

3. Swap the old and new DD tables atomically, and perform DD initialization
   over again, this time using the desired table definitions.

It should be noted that binary downgrade (start the old binaries on an upgraded
data directory) is in general not possible for all DD upgrades, since the old
binaries know nothing about the changes that have been done during upgrade to a
newer version. This implies that upgrade of DD tables between minor versions is
officially *not* supported; however, the worklog will still try to provide some
support for this use case, since it is likely to happen some time anyway.

It should also be noted that this worklog is targeting the upgrade of the DD
tables only. Upgrade of the entire server, and coordination of the upgrade of
the individual server modules, is not the responsibility of this worklog.
1. Changes supported in an upgrade.
===================================
The definitions of the DD tables can change from a server version to the next,
but it is recommended to keep the amount of changes to a minimum, due to the
potential impact on server availability.

Deciding which kind of upgrade is supported in various situations is not only a
technical question, but also a political one. It is relevant to distinguish
between minor and major releases when discussing what DD changes may be 
supported.

1.1 Upgrades supported in minor releases.
-----------------------------------------
Officially, we do not support DD upgrades in minor releases. The motivation is
twofold: To avoid substantial changes in MRUs that may have an impact on system
critical components, and to enable binary upgrade/downgrade. However, for a
limited set of changes, some support may be provided (e.g., we will provide
support for binary downgrade in these cases):

i)   Addition of new attributes to a predefined general purpose
     option-like field.
ii)  Addition of a column at the end of the table definition.
iii) Addition of elements at the end of an enumeration column type.
iv)  Extension of a VARCHAR field.
v)   Addition of an index on a column.

In addition to the changes above, some support may be provided for the 
following changes, depending on the circumstances:

vi)  Addition of a unique index or FK  might be problematic (the older version
     will not know that it needs to enforce this constraints, i.e. constraints 
     will be enforced, but on the DD layer, not by the SQL-layer code.
vii) New tables might be problematic, depending on how isolated they are.

It is still technically possible to do other changes in a minor release of
course, but the price we pay is that binary downgrade will not be supported.

It should be noted that:

* Changes like iii) and iv) above may be allowed in the sense that we will be 
  able to open the more recent table definitions (which contain e.g. an 
  extended VARCHAR field) in the previous server version. However, the previous 
  server version may or may note be able to handle the data stored there in a 
  reasonable way. If there e.g. is buffer sizing that depends on the field
  definition, server may not be able to handle data stored in the newer server
  version. Thus, each case must be considered carefully to determine whether
  changes like these may be permitted in a minor upgrade.

* After an upgrade which adds e.g. a column, if the server is downgraded to a 
  previous version, and then re-upgraded, the new column will already be in 
  place. However, in this case, the data stored in that column may not be 
  consistent with the rest of the data (since the previous version did not
  know how to maintain the added column). In this case, the data must be re-
  initialized upon the second upgrade. This also applies to scenario i) above, 
  and this is relevant even with a fixed DD table schema, i.e., it is relevant
  even outside the context of DD upgrades.

* The added support for downgrades within a GA cycle has implications that
  must be handled, e.g. if the SQL DDL semantics change. This will be discussed 
  further below.

1.2 Upgrades supported in major releases.
-----------------------------------------
For a major release, we are not required to support binary downgrade, which 
gives us more freedom in what changes we can make. However, we cannot list
specific changes that are allowed or prohibited, because, the issue here is
not only about changing the DD table definitions and migrating the meta data
from the old to the new version, the problem is that to allow upgrade, we must
start the server using the old data dictionary, and support some subset of the
server functionality until upgrade is completed. If the changes in the DD 
tables are major, they will also affect the internal structure of the 
dictionary objects, and the server functions that rely on these objects. Hence, 
there will be server code that will need to make its execution conditional, 
depending on the dictionary version from which we upgrade.


2. Functional requirements.
===========================
FR1. There shall be a new command line option to prevent automatic upgrade of
     the DD tables: --no_dd_upgrade. The default behavior is that a 
     starting server will upgrade the DD tables if necessary, unless this 
     option is submitted.

FR2. There shall be a dedicated DD version number. We will use the version
     number of the mysqld server where the set of DD table definitions were 
     first introduced, as the DD version number. This is consistent with the 
     versioning scheme for performance schema and information schema.

FR3. Upon a server restart, if the DD version number stored in the DD is the
     same as the server's own DD version number, the restart will be carried
     out as usual without any change of the DD table definitions.

FR4. Upon a server restart, if the DD version numbers (as explained in FR2 and 
     FR3) differ, and if the command line option '--no_dd_upgrade' is
     submitted, the server will exit with an error message ER_DD_UPGRADE_OFF.

FR5. Upon a server restart, if the DD version numbers (as explained in FR2 and 
     FR3) differ, and if the command line option '--no_dd_upgrade' is NOT 
     submitted, the server will check to see if it is capable of upgrading from
     the actual DD version to the target DD version. If it's capable of doing
     so, the actual DD version is considered 'supported' as far as upgrade is 
     concerned.

     If the actual version is not in the list of supported versions, the server
     will check to see if this is minor downgrade. If it is not minor downgrade,
     then the server will exit with an error message 
     ER_DD_UPGRADE_VERSION_NOT_SUPPORTED.

     If this is an attempt at minor downgrade, but the newer version is not
     possible to donwgrade (because it is marked as a non-downgradable version),
     then the server will abort restart with the error message 
     ER_DD_MINOR_DOWNGRADE_VERSION_NOT_SUPPORTED

FR6. All DD tables that store DD entities (i.e.:

        catalogs,
        character_sets,
        collations,
        column_statistics,
        events,
        resource_groups,
        routines,
        schemata,
        st_spatial_reference_systems, 
       *tables,
       *tablespaces

     plus a selection of important non-entity tables:

       *columns,
       *indexes,
        foreign_keys,
        triggers,
       *parameters

     shall have a column which may be used to handle in-GA changes. Thus, 
     MRUs may add information to this column as they see fit. However, binary 
     downgrade must still be supported, so information in other columns, which 
     is relied upon by previous MRUs, must still be maintained.

     In the list above, tables prefixed by '*' already have a column named 
     'options' which can be used for this purpose. For the other tables in the
     list, such a column shall be added by this worklog.

FR7. The DD upgrade shall be atomic, meaning that the server shall not be left 
     in a state where some of the DD tables are upgraded, and some are not. If 
     upgrade completes, the server shall keep running, and it shall be using 
     the new DD version.

FR8. The DD upgrade shall be atomic. If upgrade fails, the server shall exit.
     If the old server binaries, supporting the old DD version, are used to 
     restart the server, it shall be using the old DD version. If the new 
     server binaries are used to restart the server, it shall retry DD upgrade.

FR9. After a successful DD upgrade, it is in the general case not possible to
     restart the server with the old server binaries, i.e., binary downgrade
     is not supported. This means that DD upgrade is not officially supported
     between minor server versions.

FR10. Upgrade will be supported for the following DD tables:

        catalogs,
        character_sets,
        collations,
        column_statistics,
        column_type_elements,
        columns,
        dd_properties,
        events,
        foreign_key_column_usage,
        foreign_keys,
        index_column_usage,
        index_partitions,
        index_stats,
        indexes,
        parameter_type_elements,
        parameters,
        resource_groups,
        routines,
        schemata,
        st_spatial_reference_systems, 
        table_partition_values,
        table_partitions,
        table_stats,
        tables, 
        tablespace_files,
        tablespaces,
        triggers,
        view_routine_usage,
        view_table_usage

FR11. There will also be infrastructure to support creating new definitions of
      the InnoDB specific tables:

        innodb_ddl_log,
        innodb_dynamic_metadata,
        innodb_index_stats,
        innodb_table_stats

      The actual migration of meta data from old to new versions of
      the InnoDB specific tables can be handled by InnoDB itself, or it
      can also be handled at the SQL layer for now.


3. New messages for errors and notes.
=====================================
ER_DD_UNEXPECTED_TABLE_DEFINITION
  eng "Unexpected definition of dictionary table '%s'."

ER_DD_INITIALIZE
  eng "Data dictionary initializing version '%u'."

ER_DD_RESTART
  eng "Data dictionary restarting version '%u'."

ER_DD_UPGRADE
  eng "Data dictionary upgrading from version '%u' to '%u'."

ER_DD_UPGRADE_OFF
  eng "Data dictionary upgrade prohibited by the command line option 
       '--no_dd_upgrade'."

ER_DD_UPGRADE_VERSION_NOT_SUPPORTED
  eng "Upgrading the data dictionary from dictionary version '%u' is not 
       supported."

ER_DD_MINOR_DOWNGRADE
  eng "Data dictionary minor downgrade from version '%u' to '%u'."

ER_DD_MINOR_DOWNGRADE_VERSION_NOT_SUPPORTED
  eng "Minor downgrade of the Data dictionary from dictionary version '%u' is 
       not supported."


4. New command line options.
============================
--no_dd_upgrade: If the server starts, and finds a data directory with a data 
    dictionary version different from the server's target version, the server 
    will exit.
1. Definitions.
===============
* Actual : The persistently stored DD version or
  DD table, i.e., what is reflected in the persistently stored mete data.
* Target : The DD version or table which the server
  is using during normal operation. If the actual DD version is different
  from the target DD version, upgrade is required. For the limited set of
  operations needed during upgrade, the server is able to use both the
  actual and the target version at the same time.


2. Prerequisites.
=================

2.1 Supporting lightweight in-GA "upgrades".
--------------------------------------------
We will support in-GA upgrades by adding a general purpose column which can be
used for storing additional meta data, unless such a column exists already. We
will also add support for server restarts using newer DD table definitions that
are pure extensions.

2.1.1 Adding a general purpose column.
---------------------------------------
The tables listed in FR6 shall have a column to store arbitrary key/value based
meta data to support lightweight upgrades within a GA lifecycle, i.e., between
minor versions. Thus, they will have a column like:

CREATE TABLE mysql. (..., options MEDIUMTEXT, ...);

This column will be treated as a dd::Properties object internally, i.e., a list
of key=value pairs. If MRUs need to store additional meta data, the column can
be used for this purpose, instead of doing a change of the table definition.
Thus, an MRU can e.g. add one or more key=value pairs to the 'options' column. 
The MRU adding a key should take absence of keys to mean some default value in 
order to avoid adding keys for all rows in the table.

For this to work, we must ensure that all changes extend the previous data, 
i.e.:

- Even if information is added to 'options', information may not be
  removed from other columns, because previous MRUs must be able to restart
  using the same data directory.
- If a new MRU extends the set of valid key=value pairs, it must still support 
  the already existing ones. Thus, if a previous MRU starts, using the same 
  data directory, it can safely assume that the key=value pairs it needs are 
  indeed present.
- If a new MRU extends the set of valid key=value pairs, starts storing these
  new keys, and the previous MRU is then restarted on the same data directory,
  the previous MRU will obviously not maintain the new keys. Thus, if we at a
  later stage upgrades to the new MRU, we will risk that there are key=value
  pairs stored that are not consistent with the rest of the meta data anymore.
  This means that on a repeated upgrade to a new server version (this is 
  relevant even outside the context of a DD upgrade, since we may add new keys
  to these columns without changing the DD version), we need to make sure the 
  new keys are re-initialized.

For each case, it must be considered whether downgrade is safe or not. If the 
added key/value pairs can safely be ignored in previous versions, downgrade may 
be supported. If the key/value pairs cannot be ignored, downgrade must be 
prohibited.

2.1.2 Supporting downgrade of pure DD table extensions.
-------------------------------------------------------
While the approach outlined above will solve some required changes for in-GA
upgrades, we still miss support for e.g. adding indexes. It is not unlikely 
that this will be needed. In order to still allow downgrade to previous MRUs, 
we will store the SQL DDL statements, and the SE private data of the DD tables, 
into the 'mysql.dd_properties' table; thus, an older version is able to restart 
using the upgraded DD tables. If the new table is a simple extension of the old
one (e.g. just adding columns at the end), then the old version should be able
to execute as usual, simply ignoring the additional extensions defined in the
upgrade.

This has the implication that if a new server version has changes in the SQL 
DDL semantics that affects the meta data created for the DD tables, there must 
be code to handle that without changing the SQL DDL which is stored 
persistently. I.e., for the stored SQL DDL statements, execution of the same 
statements must result in the same meta data for both the new server version, 
and for older versions to which binary downgrade is supported. The new server 
version may handle changes in SQL DDL semantics in two ways:

- Change the SQL DDL statements before it is executed, without changing the
  SQL DDL statement that is stored persistently.
- Change the generated dictionary objects after they are created, before they 
  are stored persistently.

So between MRUs, we will try to keep "canonical" SQL DDL statements stored in 
'mysql.dd_properties', in order to support minor upgrade/downgrade (the same 
canonical statement should result in the same low level meta data), while at 
the same time being able to support changes in DDL semantics (changes in DDL 
semantics can be countered by modifying the SQL statement before executing it, 
but without changing the canonical statement stored in 'mysql.dd_properties').

As an example, let us say that server version 8.0.4 creates the DD tables with 
the default compression table option ('none'). E.g. (as a simple example), 

DDL_804= CREATE TABLE catalogs (id BIGINT AUTO INCREMENT, name VARCHAR(255), 
         PRIMARY KEY (id)) ENGINE=InnoDB;

So when the 8.0.4 server is initialized, statement DDL_804 is stored in 
'mysql.dd_properties'.

Further, let us assume that server version 8.0.5 (an MRU) extends the table 
above by an additional column (which is by itself minor downgradable), while at 
the same time, the default compression table option is changed from 'none' to 
'zlib'. We could change all the target DD table DDL statements in 8.0.5 to 
explicitly specify 'COMPRESSION=none'. However, this would mean that all the 
DDL statements are changed, which is not desirable since a change in the DDL 
statements indicates that there is a new verison of the table (while in this 
case, that is true only for the catalogs table, which has an added column).

So a better alternative is to handle the changed default by keeping the target 
statements unchanged, and just modifying them in 8.0.5 before they are 
executed. So, in 8.0.5, we would have a canonical target table definition like:

DDL_805= CREATE TABLE catalogs (id BIGINT AUTO INCREMENT, name VARCHAR(255), 
         new_col INT, PRIMARY KEY (id)) ENGINE=InnoDB;

Then, before execution we would add ‘COMPRESSION=none’ to the statement above.
However, in the DD_properties table, we would store the unmodified canonical 
statement DDL_805, so when it is executed in a 8.0.4 context during a minor 
downgrade, we would use the default compression in 8.0.4, which was 'none'. 
Thus, we may in fact say that the canonical statements stored in 
'mysql.dd_properties' are on the old server version's format.

An alternative to changing the DDL statement before execution is to modify the 
meta data as part of DDL execution. This would also need to be done on the new 
MRU to make sure the semantics is the same as on the old MRU. It is probably 
better to modify the SQL statement before execution, though, in order to avoid 
polluting DDL execution with special code for handling DD tables.

2.2 Storing hard coded meta data.
---------------------------------
When restarting the server, we need to have certain SE private data available 
in order to open the DD tables, e.g. the table's se_private_id. However, we 
need a more flexible solution for persisting this hard coded meta data. 
Currently, for each DD table, the following is assigned by InnoDB based on hard 
coded values in source code:

* dd::Table::se_private_id
* dd::Table::tablespace_id
* dd::Index::se_private_data[root page number and space id]
* dd::Index::tablespace_id

This restricts the options we have regarding changing the DD tables. Thus, we
will use the values that are hard coded in source code only during initial
start. The hard coded meta data will then be stored in the 
'mysql.dd_properties' table, and during server restart, we will get the hard
coded meta data from 'mysql.dd_properties' instead of getting it from the SE,
(except for the meta data for the 'mysql.dd_properties' table itself; this meta
data must be retrieved from the SE even during restart, otherwise we will not 
be able to open it to get the meta data for the other DD tables).

The motivation for this is to allow SE private data to change during an 
upgrade. This means we can allow modifications that result in e.g. new SE
private ids, since we can update the 'mysql.dd_properties' table with the new
meta data.

2.3 DD version number format.
-----------------------------
We will not officially support DD upgrades between MRUs of a GA, unless 
critical issues require this to be done. If this is needed, and if we at the 
same time have more recent GA releases, it will be helpful to have a two-level 
DD version number, since otherwise, the version sequence will be quite awkward.

Thus, we will adopt the same versioning schema as employed by performance 
schema: The numbering to use is the MySQL version number of the first MySQL 
version that published a given database schema. The format is Mmmdd with 
M=Major, m=minor, d=dot, so that MySQL 8.0.4 is encoded as 80004. In case of -
dash version numbers, encode MySQL 8.12.34-56 as 8123456.


3.Upgrading the DD tables.
==========================
Throughout the upgrade procedure below, the server will be single threaded, so
we don't need to take e.g. concurrent DDL execution into account.

3.1 Upgrade procedure.
----------------------
1. Compare the actual DD version number (stored in the 'mysql.dd_properties'
   table) and the target DD version number (define in the binaries) to
   determine if upgrade is needed.

2. Check if the actual DD version number is supported (i.e., if the server is
   able to upgrade from that DD version). The list of supported DD versions is
   represented in source code within the DD module. If the actual DD version is 
   not supported, err out, unless this is a minor downgrade. If this is a minor
   downgrade, continue with an ordinary restart based on using the actual DD 
   table definitions.

3. Create the meta data for the tables of the actual DD version. This is done
   by retrieving the stored SQL DDL statements from the 'mysql.dd_properties'
   table and executing them. Further, add the generated meta data to the DD 
   cache, i.e., keep the meta data only in memory. The meta data is needed to 
   open the actual DD tables.

4. Look into the DD table 'mysql.dd_properties' to see if the two schema names
    and  are defined. If so, remove the two schemas and
   their contents if they exists (see below for an explanation). Also, remove 
   the two schema names from 'mysql.dd_properties'.

5. Generate two unique schema names  and . Update the 
   table 'mysql.dd_properties' with the two names and commit. These two 
   schemas are used as a sandbox while doing the upgrade.

6. Create a new empty schema , i.e., using the schema name we just
   created in the previous step. The new schema will only be used temporarily.
   Also create another temporary empty schema , to be used while
   swapping the DD tables (see below).

7. Create the target DD tables in schema  in the DD tablespace 
   (i.e., the same tablespace as the existing DD tables). Thus, swapping the
   new and old DD tables boils down updating meta data in the DD tables. The 
   meta data of the target DD tables is now represented in the actual DD 
   tables. The tables are created using the target SQL statements, which are 
   auto committed.

8. Copy the meta data from the actual DD tables to the target DD tables. This
   will include possible modification of values, e.g. if new columns are added,
   and values need to be filled in based on existing meta data. In this step, 
   we can also do analysis to catch invalid or deprecated meta data.

9. Finalize the target DD tables. At this point, they can still be considered
   ordinary user tables, and updates are done by means of DML statements.

   * Update the schema id of the actual DD table entries (i.e., the entries
     present in the target DD tables) to the  id.
   * Update the schema id of the target DD table entries to the id of the
     'mysql' schema.

   The target DD tables are now mostly ready for replacing the actual DD
   tables. Note that this step is not committed before the next step is
   completed, to ensure an atomic swap of tables. The remaining step is to
   make sure the target tables are used instead of the actual DD tables when 
   the server is restarted.

10. Update the persistent meta data in 'mysql.dd_properties' (i.e., replace the 
    SQL DDL statements and the SE dependent data from the actual DD tables by 
    the same meta data from the target DD tables). Also update the DD version 
    number to the target DD version. After commit, a restart will use the new 
    target DD tables.

11. Re-initialize the DD cache, and do a new DD initialization (without 
    restarting the server) i.e., start over from step 1 above.

The normal restart procedure must be extended to do the same as step 4 above
(i.e., clean up the sandbox after a successful upgrade).

3.2 Notes.
----------
N1) DD table meta data is located in a "lookaside buffer" in the storage 
    adapter. This is initialized when the DD is initialized, and is based on 
    the information stored in 'mysql.dd_properties'.

N2) Beyond storing the meta data for the new target DD tables, the actual DD 
    tables are not modified. Thus, if there is a failure before step 10, we can 
    restart the new binaries with the old, actual DD tables (i.e., upgrade will 
    be retried); or we can restart with the old binaries (which will find the 
    sandbox schemas in 'mysql.dd_properties' and remove them and their 
    contents).

N3) We need to upgrade into the same tablespace due to InnoDB constraints 
    regarding the DD tablespace id, file name etc., but also due to the 
    difficulty of ensuring atomicity when swapping tablespaces (because we need 
    to access the file system).


4. Version dependent source code.
=================================
A major issue in this context is to structure the upgrade related source code 
in a way that does not pollute the rest of the source code, and which allows
code needed to support a given DD version to be removed easily. We need to
maintain version dependent instances of at least the following:

* Code for storing/reading DD objects and their children.
* Code for storing/reading the DD_properties (if keys are added or removed).
* The object table definitions (including field enumerations).
* Key creation for retrieving objects from the DD tables.
* System table registry.
* Index numbers (currently hard coded in various object key related classes).

It is absolutely vital to write the version dependent code in a well organized
way to avoid chaos. It is also vital to organize the code in a way that lets us
easily identify and remove code that is dependent on a version which is not
supported anymore.
            
                                    
1. Compatibility issues.
========================
We are basing the approach on SQL DDL statements, and will therefore face
problems when DDL semantics change, e.g. an SQL level type is mapped to a
different internal type. There are three ways we can handle this.

a) Changes affecting the upgradability of old supported versions can be
   handled by checking for the actual version from which we upgrade, and 
   modify the dictionary objects that are generated after the CREATE TABLE 
   statement has been executed. Here, 'version' may mean both specific DD 
   and MySQL server versions. This approach can also be used to adjust meta
   data created for the target tables. This may be needed to preserve 
   downgrade support to previous MRUs.

b) We can patch up the CREATE TABLE statements internally in the server 
   before they are executed. This means that te statements must be stored in
   a structured way, both for the target definitions in the binary, and for 
   the actual definitions in the 'mysql.dd_properties' table, not as 
   complete statements. Thus, we can change e.g. the SQL level type of 
   specific fields before the statement is executed.

c) For changes that affect the execution of the target DDL statements, we
   can change the target table definitions and define a new DD version 
   number. This will be a problem in minor releases, though, if we execute 
   downgrade by creating the DD table definitions based on the contents of 
   the 'mysql.dd_properties' table, but execute the statements in the old 
   server environment. Thus, this alternative should probably be restricted
   to major releases.

During minor upgrades we will store the table definitions as SQL DDL which is 
fully compatible with the older MRUs, and will adjust their execution on newer 
MRUs, either by modifying the SQL before execution, or by modifying the 
resulting meta data, as explained in a) and b) above. So the SQL DDL defining 
the table is stored with the previous MRUs in mind, and if there is a change in 
the SQL DDL semantics, then the difference between the behavior of the old and 
MRU will be handled by patching up the SQL DDL, or adjusting the SQL DDL 
execution in the newer version.

2. Supporting in-GA DD upgrade.
===============================
a) Add a general purpose column to support new needs without schema changes:
   * Add a new MEDIUMTEXT column to the DD tables, intended to store
     a general purpose property string.
   * Add new member and access functions as needed when starting to
     use this.
   * Provide support for ensuring consistency of the new key values after a
     downgrade and repeated upgrade, even if skipping several MRUs.

b) Support schema changes that are pure extensions:
   * Store a structured representation of the SQL DDL statement for
     each DD table in 'mysql.dd_properties'.
   * Upon in-GA downgrade (restarting an older MRU using the DD from a newer
     MRU with a newer DD version), continue ordinary restart using 
     the actual DDL statements store in 'mysql.dd_properties'.
   * We should check version numbers to verify that this is indeed an
     in-GA downgrade to prohibit attempts at downgrading to another major 
     version. We should also store, in 'mysql.dd_properties', the lowest
     version number to which in-GA downgrade is possible.
   * If the schema changes are only extensions, then an older server
     binary should be able to start with a more recent DD version.
   * Compatibility issues handled by approach 1.a or 1.b should make sure
     the semantics of the SQL DDL execution stay the same (i.e., the newer MRU
     must handle differences in SQL DDL semantics by modifying the SQL DDL 
     after the statements has been stored, or by modifying the generated meta 
     data.
   * We must provide support for ensuring consistency of the new data which is
     stored after a downgrade and repeated upgrade, even if skipping several 
     MRUs.

c) Above, a 'structured representation' means that we must support storing
   enumerations of e.g. fields, indexes, options, etc:
   * Store explicit enumeration of fields.
   * Store explicit enumeration of indexes.
   * Store explicit enumeration of table options.
   * Store explicit enumeration of foreign keys.

3. Command line options.
========================
* Add new command line option '--no_dd_upgrade'.
* Default should be 'false' (i.e., DD upgrades will happen automatically by
  default).
* Setting it to 'true' shall have the effect that a restart will be aborted
  if upgrade is required (i.e., if the actual DD version is different from 
  the target DD version).

4. Store additional version information in 'mysql.dd_properties'.
=================================================================
* Add server version number: High, low, current.
  These are not DD version numbers, but the version of the server binary.
* Add SDI version number.
* Add LCTN (the value used during --initialize).
* Add MINOR_DOWNGRADE_THRESHOLD to represent how far back (in terms of the DD 
  version number) we can downgrade.
* Add list of target system tables with definitions.
* Update MYSQLD_VERSION if the stored value is different from the starting 
  server version.
* Update MYSQLD_VERSION_LO if the stored value is higher than the starting 
  server version.
* Update MYSQLD_VERSION_HI if the stored value is lower than the starting 
  server version.
* Update SDI_VERSION if the stored value is lower than the starting server SDI 
  version.
* Comparing version numbers is done by the standard comparison operator.

5. Store and retrieve hard coded meta data and SQL DDL statements.
==================================================================
* Change create_dd_system_table() to fetch SE private data from the
  SE only during --initialize.
* Store SE private data in 'mysql.dd_properties' during --initialize.
* Fetch SE private data from 'mysql.dd_properties' during restart and upgrade.
* Store SE private data also for columns.
* Store structured representation of the SQL DDL statements. Should separate 
  type from column name. Should store enumerations of fields and indexes.
* Must store this after the DD tables are created to avoid unexpected glitches
  in the root page numbers.
* Store the system table index, to be used for initializing the System_tables 
  singleton.
* We must keep in the source code all Object_table classes that are referenced 
  in any supported version. The System_tables registry should be populated with 
  all known Object_tables from all supported versions.

6. Handling SE private data during --initialize.
================================================
* InnoDB must add additional SE private data for columns and indexes, 
  e.g. the 'table_id' and 'space_id'.
* We must keep track of the set of SE private ids used by the DD tables,
  since this is needed by InnoDB. This must replace the current range-based
  comparison that are used in InnoDB, since we cannot rely on ids staying 
  within a certain range since the DD tables can be re-created.
* Change handlerton method to support upgrade (i.e., update SE private data
  for 'dd_properties' during the restart phase after upgrade).

7. Change the Object_table_definition.
======================================
* Clean up version number usage, should probably get rid of the '==0' special 
  handling for inert tables.
* Let the Object_table contain a target definition and an actual definition.
* Make enumerations of fields and indexes explicit.
* Define fragments of SQL DDL statement. Should separate type from column name.
* Have a mechanism to make a definition persistent, or to instantiate one 
  based on persistent data.

8. DD version number format.
============================
* Use the server version number which first published a given DD schema
  as the DD version number.
* Separate out the version information in a single .h file under sql/dd.
* Update version info at end of initialize and restart. Update server
  version numbers.

9. InnoDB recovery needed before allowing DD table upgrade.
===========================================================
* Discussed with Jimmmy, seems ok. At the time we plan to do the upgrade, 
  recovery is completed, and the purge threads are not started.

10. Supporting upgrade of InnoDB internal tables.
=================================================
* Can associate changes of these tables with the DD version and treat them in a 
  similar way to upgrade of the other DD tables for now.
* For server restart (with or without upgrade), the actual table definitions 
  are fetched from 'mysql.dd_properties'.
* For server restart with upgrade, we get the target table definitions from 
  'dict_init()'. The target tables are created and upgraded using the same
  scheme as for the other DD tables.
* We may use an additional handlerton call to let InnoDB take care of the 
  migration from the old to the new tables: 'dict_upgrade_predefined_tables()'.
  Otherwise, we may also handle this at the SQL layer for now.

11. Verification and consistency checking.
==========================================
* We may add verification to the DD bootstrapping when the DD 
  tables are being created during --initialize, restart or upgrade. This 
  verification can be based on comparing actual SQL DDL statements.
* We must prohibit accidental and unintentional changes of the DD table 
  definitions in minor versions.
* We must also catch changes in the DDL semantics affecting the execution of 
  the SQL DDL statements for the DD tables.
* We should probably modify the dd_schema_definition tests to mask platform 
  differences, making it easier to maintain. It should also store the actual
  SQL DDL statements to catch changes of the statements.
* Tests suggested in the QA notes section should take care of these needs.

12. SDI handling and cleanup.
=============================
* We must probably re-generate all SDI if there is a change of the SDI version 
  at the same time as there is a DD upgrade.
* There could in theory be a change of SDI version without a DD upgrade, e.g. 
  if there are major bugs in the SDI format.

13. Supporting multiple versions.
=================================
There are at least three different aspects of this issue that we must take into
account.

a) DD object APIs:
   * The public API of the DD object types should reflect the target DD
     version. If a field is removed (or is not being used by the server code, 
     yet still stored in the DD tables), it should not be available through
     the public API.
   * The internal API (the *_impl classes) should reflect the union of
     the supported DD versions. If a field is removed, its corresponding
     data member should remain present until the last DD version where
     it was still persisted is not supported anymore.

b) When detecting an upgrade, we must:
   * Create an Object_table_definition instance 'm_actual_version' within
     each Object_table.
   * Parametrize code that needs to use the field or index enumerations, or
     the system table names, e.g.:
     - register_tables().
     - Key creation and updating.
     - Storing/reading record.
   * Provide support for default value assignment for unknown fields while
     migrating data from the actual tables to the target tables.

c) In the source code, we must refer to version labels in a way that lets us 
   easily detect code referring to a version that is not supported anymore so 
   we can clean up the version handling. E.g. instead of:

   if (actual_version == 80004)
   { ... }

   we can add a constant:

   const int DD_VERISION_80004= 80004;

   and use a function to do this check:

   if (actual_DD_version_is(DD_VERSION_80004))
   {...}

   where

   bool actual_DD_version_is(uint version)
   {
     DBUG_ASSERT(is_supported_version(version));
     return actual_version == version;
   }

   We may also provide abstractions helping out here, allowing us to associate
   capabilities with versions, so we can check for e.g.:

   if (DD_supports(DD_capability_label::CATALOGS))

   instead of relying on checking specific version numbers.

14. Miscellaneous changes.
==========================
* Allow initialization/restart/upgrade if '--read_only' is set. Reject only
  if '--super_read_only' is set.
* Rewrite charset/collation re-population, check 'super_read_only' instead
  of '--read_only'.