
(********************************************************************)
(*                                                                  *)
(*  chkdb.sd7     Checks the database interface.                    *)
(*  Copyright (C) 2014, 2017 - 2019  Thomas Mertes                  *)
(*                                                                  *)
(*  This program is free software; you can redistribute it and/or   *)
(*  modify it under the terms of the GNU General Public License as  *)
(*  published by the Free Software Foundation; either version 2 of  *)
(*  the License, or (at your option) any later version.             *)
(*                                                                  *)
(*  This program is distributed in the hope that it will be useful, *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of  *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *)
(*  GNU General Public License for more details.                    *)
(*                                                                  *)
(*  You should have received a copy of the GNU General Public       *)
(*  License along with this program; if not, write to the           *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


$ include "seed7_05.s7i";
  include "keybd.s7i";
  include "console.s7i";
  include "editline.s7i";
  include "sql_base.s7i";
  include "db_prop.s7i";
  include "bstring.s7i";
  include "time.s7i";
  include "duration.s7i";


const type: connectData is new struct
    var dbCategory: driver       is NO_DB;
    var string:     dbName       is "";
    var string:     user         is "";
    var string:     password     is "";
    var dbCategory: databaseKind is NO_DB;
  end struct;


const func connectData: connectData (in dbCategory: driver, in string: dbName,
    in string: user, in string: password, in dbCategory: databaseKind) is func
  result
    var connectData: connData is connectData.value;
  begin
    connData.driver       := driver;
    connData.dbName       := dbName;
    connData.user         := user;
    connData.password     := password;
    connData.databaseKind := databaseKind;
  end func;


const type: testState is new struct
    var string: tableName is "";
    var string: fieldName is "";
    var sqlStatement: statement is sqlStatement.value;
    var boolean: okay is TRUE;
    var boolean: details is FALSE;
  end struct;


const func testState: testState (in string: tableName,
    in string: fieldName, in boolean: details) is func
  result
    var testState: state is testState.value;
  begin
    state.tableName := tableName;
    state.fieldName := fieldName;
    state.details := details;
  end func;


const boolean: infiniteAllowed is FALSE;
const boolean: nanAllowed is FALSE;


const func boolean: raisesRangeError (ref proc: expression) is func
  result
    var boolean: raisesRangeError is FALSE;
  begin
    block
      expression;
    exception
      catch RANGE_ERROR: raisesRangeError := TRUE;
    end block;
  end func;


const func boolean: raisesDatabaseError (ref proc: expression) is func
  result
    var boolean: raisesDatabaseError is FALSE;
  begin
    block
      expression;
    exception
      catch DATABASE_ERROR: raisesDatabaseError := TRUE;
    end block;
  end func;


const proc: DECL_INSERT (in type: elemType) is func
  begin

    const proc: insert (inout sqlStatement: statement, in elemType: anElement,
        in proc: succeedAction) is func
      local
        var boolean: succeeded is TRUE;
      begin
        block
          bind(statement, 1, anElement);
          execute(statement);
        exception
          otherwise: succeeded := FALSE;
        end block;
        if succeeded then
          succeedAction;
        else
          writeln(" *** Cannot insert " <& literal(anElement));
        end if;
      end func;

    const proc: insert (inout testState: state, in elemType: anElement,
        in proc: succeedAction) is func
      local
        var boolean: succeeded is TRUE;
      begin
        block
          bind(state.statement, 1, anElement);
          execute(state.statement);
        exception
          otherwise: succeeded := FALSE;
        end block;
        if succeeded then
          succeedAction;
        else
          state.okay := FALSE;
          if state.details then
            writeln(" *** Cannot insert " <& literal(anElement));
          end if;
        end if;
      end func;

    const proc: insInf (inout testState: state, in elemType: num,
        in proc: succeedAction) is func
      local
        var boolean: succeeded is TRUE;
      begin
        block
          bind(state.statement, 1, num);
          execute(state.statement);
        exception
          otherwise: succeeded := FALSE;
        end block;
        if succeeded then
          succeedAction;
          if not infiniteAllowed then
            state.okay := FALSE;
            if state.details then
              writeln(" *** Insert " <& num <& " succeeded, but it is not allowed");
            end if;
          end if
        elsif infiniteAllowed then
          state.okay := FALSE;
          if state.details then
            writeln(" *** Cannot insert " <& num);
          end if;
        end if;
      end func;

    const proc: insNaN (inout testState: state, in elemType: num,
        in proc: succeedAction) is func
      local
        var boolean: succeeded is TRUE;
      begin
        block
          bind(state.statement, 1, num);
          execute(state.statement);
        exception
          otherwise: succeeded := FALSE;
        end block;
        if succeeded then
          succeedAction;
          if not nanAllowed then
            state.okay := FALSE;
            if state.details then
              writeln(" *** Insert " <& num <& " succeeded, but it is not allowed");
            end if;
          end if
        elsif nanAllowed then
          state.okay := FALSE;
          if state.details then
            writeln(" *** Cannot insert " <& num);
          end if;
        end if;
      end func;

    const proc: insert (inout testState: state, in elemType: anElement,
        in proc: succeedAction, RANGE_CHECK) is func
      local
        var boolean: succeeded is TRUE;
      begin
        block
          bind(state.statement, 1, anElement);
          execute(state.statement);
        exception
          otherwise: succeeded := FALSE;
        end block;
        if succeeded then
          succeedAction;
          state.okay := FALSE;
          if state.details then
            writeln(" *** Insert " <& anElement <& " did not trigger an exception.");
          end if;
        end if;
      end func;

   end func;


DECL_INSERT(boolean);
DECL_INSERT(integer);
DECL_INSERT(bigInteger);
DECL_INSERT(float);
DECL_INSERT(bigRational);
DECL_INSERT(string);
DECL_INSERT(bstring);
DECL_INSERT(time);
DECL_INSERT(duration);


const proc: insert (inout sqlStatement: statement, NULL,
    in proc: succeedAction) is func
  local
    var boolean: succeeded is TRUE;
  begin
    block
      bind(statement, 1, NULL);
      execute(statement);
    exception
      otherwise: succeeded := FALSE;
    end block;
    if succeeded then
      succeedAction;
    else
      writeln(" *** Cannot insert NULL");
    end if;
  end func;


const proc: insert (inout testState: state, NULL, in proc: succeedAction) is func
  local
    var boolean: succeeded is TRUE;
  begin
    block
      bind(state.statement, 1, NULL);
      execute(state.statement);
    exception
      otherwise: succeeded := FALSE;
    end block;
    if succeeded then
      succeedAction;
    else
      state.okay := FALSE;
      if state.details then
        writeln(" *** Cannot insert NULL");
      end if;
    end if;
  end func;


const proc: insert (in database: testDb, inout testState: state,
    in string: aValue, in proc: succeedAction) is func
  local
    var sqlStatement: statement is sqlStatement.value;
  begin
    if succeeds(statement :=
          prepare(testDb, "INSERT INTO " & state.tableName &
                  " (" & state.fieldName & ") VALUES (" & aValue & ")")) and
        succeeds(execute(statement)) then
      succeedAction;
    else
      state.okay := FALSE;
      if state.details then
        writeln(" *** Cannot insert " <& literal(aValue));
      end if;
    end if;
  end func;


const proc: create (in database: testDb, inout testState: state,
    in string: fieldDeclarationName, in string: fieldName) is func
  begin
    if succeeds(state.statement :=
          prepare(testDb, "CREATE TABLE " & state.tableName &
                  " (" & fieldDeclarationName & " CHAR)")) and
        succeeds(execute(state.statement)) then
      block
        state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
        execute(state.statement);
        if columnName(state.statement, 1) <> fieldName then
          state.okay := FALSE;
          if state.details then
            writeln(" *** Column name expected: " <& fieldName <& " found: " <&
                    columnName(state.statement, 1));
          end if;
        end if;
      exception
        catch RANGE_ERROR:
          state.okay := FALSE;
          writeln(" *** RANGE_ERROR was raised");
        catch FILE_ERROR:
          state.okay := FALSE;
          writeln(" *** FILE_ERROR was raised");
        catch DATABASE_ERROR:
          state.okay := FALSE;
          writeln(" *** DATABASE_ERROR was raised");
      end block;
      state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
      execute(state.statement);
    else
      state.okay := FALSE;
      if state.details then
        writeln(" *** Cannot create table with field " <& literal(fieldName));
      end if;
    end if;
  end func;


const proc: testPrepareAndExecute (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("testPrepAndExecTable", "charField", FALSE);
    var database: emptyDb is database.value;
  begin
    if state.details then
      writeln("testPrepareAndExecute");
    end if;
    block
      execute(state.statement); # Executing an empty statement does nothing.
      if  not raisesRangeError(bind(state.statement, 1, 1_)) or
          not raisesRangeError(bind(state.statement, 1, 1_ / 1_)) or
          not raisesRangeError(bind(state.statement, 1, TRUE)) or
          not raisesRangeError(bind(state.statement, 1, bstring("x"))) or
          not raisesRangeError(bind(state.statement, 1, duration("P1D"))) or
          not raisesRangeError(bind(state.statement, 1, 1.0)) or
          not raisesRangeError(bind(state.statement, 1, 1)) or
          not raisesRangeError(bind(state.statement, 1, NULL)) or
          not raisesRangeError(bind(state.statement, 1, "x")) or
          not raisesRangeError(bind(state.statement, 1, time("2010-11-12 13:14:15.16"))) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Binding an empty statement succeeds.");
        end if;
      end if;
      if not raisesRangeError(state.statement := prepare(emptyDb,
                                  "CREATE TABLE " & state.tableName &
                                  " (" & state.fieldName & " CHAR)")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Preparing with empty database succeeds.");
        end if;
      end if;

      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR)");
      execute(state.statement);

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                     " WHERE " & state.fieldName & " = 'x' /* ? */")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Question mark in comment interpreted as parameter placeholder.");
        end if;
      elsif raisesDatabaseError(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Question mark in comment interpreted as parameter placeholder.");
        end if;
      end if;
      # Reset statement before a fetch is done to make sure that the next prepare works.
      state.statement := sqlStatement.value;

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                     " WHERE " & state.fieldName & " = 'x' -- ? \n")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Question mark in line comment interpreted as parameter placeholder.");
        end if;
      elsif raisesDatabaseError(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Question mark in line comment interpreted as parameter placeholder.");
        end if;
      end if;
      # Reset statement before a fetch is done to make sure that the next prepare works.
      state.statement := sqlStatement.value;

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM/* */" & state.tableName &
                                     "/* */WHERE " & state.fieldName & " = 'x'")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Comments to not separate words from each other.");
        end if;
      elsif raisesDatabaseError(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Comments to not separate words from each other.");
        end if;
      end if;
      # Reset statement before a fetch is done to make sure that the next prepare works.
      state.statement := sqlStatement.value;

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM-- \n" & state.tableName &
                                     "-- \nWHERE " & state.fieldName & " = 'x'")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Line comments to not separate words from each other.");
        end if;
      elsif raisesDatabaseError(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Line comments to not separate words from each other.");
        end if;
      end if;
      # Reset statement before a fetch is done to make sure that the next prepare works.
      state.statement := sqlStatement.value;

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                     " WHERE " & state.fieldName & " = /*'*/?/*'*/")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Quotation characters in comments are interpreted as literal. (1)");
        end if;
      elsif raisesRangeError(bind(state.statement, 1, "x")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Bind: Quotation characters in comments are interpreted as literal. (1)");
        end if;
      end if;

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                     " WHERE " & state.fieldName & " = /*'*/'x'/*'*/")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Quotation characters in comments are interpreted as literal. (2)");
        end if;
      end if;

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                     " WHERE " & state.fieldName & " = /*'*/'\\'/*'*/")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Quotation characters in comments are interpreted as literal. (3)");
        end if;
      end if;

      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                     " WHERE " & state.fieldName & " = '/*'")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Prepare: Comment sequence in literal triggers error.");
        end if;
      elsif raisesDatabaseError(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Comment sequence in literal triggers error.");
        end if;
      end if;
      # Reset statement before a fetch is done to make sure that the next prepare works.
      state.statement := sqlStatement.value;

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                 " WHERE " & state.fieldName & " = ?");
      if not raisesDatabaseError(execute(state.statement)) then
        # Reset statement to make sure that the next prepare works:
        state.statement := sqlStatement.value;
        state.okay := FALSE;
        if state.details then
          writeln(" *** Omitted binding did not raise DATABASE_ERROR.");
        end if;
      end if;
      if not raisesRangeError(bind(state.statement, 0, "x")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Binding of parameter 0 did not raise RANGE_ERROR.");
        end if;
      end if;
      if not raisesRangeError(bind(state.statement, 2, "x")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Binding of non-existing parameter did not raise RANGE_ERROR.");
        end if;
      end if;
      if raisesRangeError(bind(state.statement, 1, "x")) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Binding of existing parameter raises RANGE_ERROR.");
        end if;
      end if;
      if raisesDatabaseError(execute(state.statement)) then
        # Reset statement to make sure that the next prepare works:
        state.statement := sqlStatement.value;
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute select statement with bind variable raises DATABASE_ERROR.");
        end if;
      elsif fetch(state.statement) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Fetching data from an empty table succeeds.");
        end if;
      end if;

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                 " WHERE " & state.fieldName & " = 'x'");
      execute(state.statement);
      # Prepare next statement before the result of executed statement is fetched.
      if raisesDatabaseError(
          state.statement := prepare(testDb, "SELECT * FROM " & state.tableName & " WHERE " & state.fieldName & " = ?")) then
        # Reset statement to make sure that the next prepare works:
        state.statement := sqlStatement.value;
        state.okay := FALSE;
        if state.details then
          writeln(" *** Preparing a statement before a fetch of a previous statement is done raises DATABASE_ERROR. (empty table)");
        end if;
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES ('x')");
      execute(state.statement);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                 " WHERE " & state.fieldName & " = ?");
      bind(state.statement, 1, "x");
      execute(state.statement);
      if not fetch(state.statement) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Cannot fetch data from table with one entry.");
        end if;
      elsif fetch(state.statement) then
        # Reset statement to make sure that the next prepare works:
        state.statement := sqlStatement.value;
        state.okay := FALSE;
        if state.details then
          writeln(" *** Can fetch two entries from table with one entry.)");
        end if;
      end if;

      execute(state.statement);
      # Execute a second time before fetching data from the first execute.
      if raisesDatabaseError(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Cannot execute a second time before fetching data from the first execute.");
        end if;
      elsif not fetch(state.statement) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Cannot fetch data from table with one entry, when executing again.");
        end if;
      elsif fetch(state.statement) then
        # Reset statement to make sure that the next prepare works:
        state.statement := sqlStatement.value;
        state.okay := FALSE;
        if state.details then
          writeln(" *** Can fetch two entries from table with one entry, when executing again.)");
        end if;
      end if;

      if state.okay then
        # Bind and execute again.
        bind(state.statement, 1, "x");
        execute(state.statement);
        if not fetch(state.statement) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** Cannot fetch data from table with one entry.");
          end if;
        elsif fetch(state.statement) then
          # Reset statement to make sure that the next prepare works:
          state.statement := sqlStatement.value;
          state.okay := FALSE;
          if state.details then
            writeln(" *** Can fetch two entries from table with one entry.)");
          end if;
        end if;
      end if;

      if state.okay then
        execute(state.statement);
        # Bind and execute again although a previous execute is not fetched.
        bind(state.statement, 1, "x");
        execute(state.statement);
        if not fetch(state.statement) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** Cannot fetch data from table with one entry.");
          end if;
        elsif fetch(state.statement) then
          # Reset statement to make sure that the next prepare works:
          state.statement := sqlStatement.value;
          state.okay := FALSE;
          if state.details then
            writeln(" *** Can fetch two entries from table with one entry.)");
          end if;
        end if;
      end if;

      if state.okay then
        # Prepare next statement before the result of executed statement is fetched.
        execute(state.statement);
        if raisesDatabaseError(
            state.statement := prepare(testDb, "SELECT * FROM " & state.tableName &
                                       " WHERE " & state.fieldName & " = ?")) then
          # Reset statement to make sure that the next prepare works:
          state.statement := sqlStatement.value;
          state.okay := FALSE;
          if state.details then
            writeln(" *** Preparing a statement before a fetch of a previous statement is done raises DATABASE_ERROR. (non-empty table)");
          end if;
        end if;
      end if;

    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    if not succeeds(execute(state.statement)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Cannot drop table.");
      end if;
    end if;

    if state.okay then
      writeln("Preparing and executing prepared statements works okay.");
    else
      writeln(" *** Preparing and executing prepared statements does not work okay.");
    end if;
  end func;


const proc: testFieldNames (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("testTable", "unused", FALSE);
  begin
    if state.details then
      writeln("testFieldNames");
    end if;
    create(testDb, state, "\"ch a\"",    "ch a");   # Space in name
    if allowedInFieldName(databaseKind, '\"') then
      create(testDb, state, "\"ch\"\"a\"", "ch\"a");  # Double quote in name
    end if;
    create(testDb, state, "\"ch'a\"",    "ch'a");   # Single quote in name
    create(testDb, state, "\"ch`a\"",    "ch`a");   # Backtick in name
    create(testDb, state, "\"ch\\a\"",   "ch\\a");  # Backslash in name
    create(testDb, state, "\"ch\ta\"",   "ch\ta");
    create(testDb, state, "\"ch\na\"",   "ch\na");
    create(testDb, state, "\"ch€a\"",    "ch€a");
    create(testDb, state, "\"chµa\"",    "chµa");

    if allowedInFieldName(databaseKind, '\0;') then
      create(testDb, state, "\"\0;\"",         "\0;");
    end if;
    create(testDb, state, "\"\1;\"",         "\1;");
    create(testDb, state, "\"\2;\"",         "\2;");
    create(testDb, state, "\"\3;\"",         "\3;");
    create(testDb, state, "\"\4;\"",         "\4;");
    create(testDb, state, "\"\5;\"",         "\5;");
    create(testDb, state, "\"\6;\"",         "\6;");
    create(testDb, state, "\"\7;\"",         "\7;");
    create(testDb, state, "\"\8;\"",         "\8;");
    if allowedInFieldName(databaseKind, '\9;') then
      create(testDb, state, "\"\9;\"",         "\9;");
    end if;
    if allowedInFieldName(databaseKind, '\10;') then
      create(testDb, state, "\"\10;\"",        "\10;");
    end if;
    if allowedInFieldName(databaseKind, '\9;') and
        allowedInFieldName(databaseKind, '\10;') then
      create(testDb, state, "\"\1;\2;\3;\4;\5;\6;\7;\8;\9;\10;\"",
                              "\1;\2;\3;\4;\5;\6;\7;\8;\9;\10;");
    else
      create(testDb, state, "\"\1;\2;\3;\4;\5;\6;\7;\8;\"",
                              "\1;\2;\3;\4;\5;\6;\7;\8;");
    end if;
    create(testDb, state, "\"\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\"",
                            "\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;");
    create(testDb, state, "\"\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;\"",
                            "\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;");

    if allowedInFieldName(databaseKind, ' ') then
      create(testDb, state, "\" \"",                   " ");
    end if;
    if allowedInFieldName(databaseKind, '\"') then
      create(testDb, state, "\"!\"\"#$%&'()*+,-./\"",  "!\"#$%&'()*+,-./");
    else
      create(testDb, state, "\"!#$%&'()*+,-./\"",      "!#$%&'()*+,-./");
    end if;
    create(testDb, state, "\"0123456789\"",          "0123456789");
    create(testDb, state, "\":;<=>?@\"",             ":;<=>?@");
    create(testDb, state, "\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"",
                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    create(testDb, state, "\"[\\^_`\"",              "[\\^_`");
    create(testDb, state, "\"abcdefghijklmnopqrstuvwxyz\"",
                            "abcdefghijklmnopqrstuvwxyz");
    create(testDb, state, "\"{|}~\"",                "{|}~");
    create(testDb, state, "\"\127;\"",               "\127;");

    create(testDb, state, "\"\128;\129;\130;\131;\132;\133;\134;\135;\"",
                            "\128;\129;\130;\131;\132;\133;\134;\135;");
    create(testDb, state, "\"\136;\137;\138;\139;\140;\141;\142;\143;\"",
                            "\136;\137;\138;\139;\140;\141;\142;\143;");
    create(testDb, state, "\"\144;\145;\146;\147;\148;\149;\150;\151;\"",
                            "\144;\145;\146;\147;\148;\149;\150;\151;");
    create(testDb, state, "\"\152;\153;\154;\155;\156;\157;\158;\159;\"",
                            "\152;\153;\154;\155;\156;\157;\158;\159;");
    create(testDb, state, "\"\160;\"",               "\160;");

    create(testDb, state, "\"¡¢£¤¥¦§¨©ª«¬­®¯\"",     "¡¢£¤¥¦§¨©ª«¬­®¯");
    create(testDb, state, "\"°±²³´µ¶·\"",            "°±²³´µ¶·");
    create(testDb, state, "\"¸¹º»¼½¾¿\"",            "¸¹º»¼½¾¿");
    create(testDb, state, "\"ÀÁÂÃÄÅÆÇ\"",            "ÀÁÂÃÄÅÆÇ");
    create(testDb, state, "\"ÈÉÊËÌÍÎÏ\"",            "ÈÉÊËÌÍÎÏ");
    create(testDb, state, "\"ÐÑÒÓÔÕÖ×\"",            "ÐÑÒÓÔÕÖ×");
    create(testDb, state, "\"ØÙÚÛÜÝÞß\"",            "ØÙÚÛÜÝÞß");
    create(testDb, state, "\"àáâãäåæç\"",            "àáâãäåæç");
    create(testDb, state, "\"èéêëìíîï\"",            "èéêëìíîï");
    create(testDb, state, "\"ðñòóôõö÷\"",            "ðñòóôõö÷");
    create(testDb, state, "\"øùúûüýþÿ\"",            "øùúûüýþÿ");

    if state.okay then
      writeln("Creating tables with allowed characters in field names works okay.");
    else
      writeln(" *** Creating tables with allowed characters in field names does not work okay.");
    end if;
  end func;



const proc: testWithAutoCommit (in database: testDb, inout testState: state,
    in database: secondDbConnection) is func
  local
    var sqlStatement: secondStmt is sqlStatement.value;
  begin
    secondStmt := prepare(secondDbConnection, "CREATE TABLE " & state.tableName &
                                              " (" & state.fieldName & " CHAR(32))");
    execute(secondStmt);

    state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
    if not succeeds(execute(state.statement)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Table created by other connection does not exist. (1)");
      end if;
    elsif fetch(state.statement) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Fetch: Fetch succeeds for table created by other connection. (1)");
      end if;
    end if;

    secondStmt := prepare(secondDbConnection, "INSERT INTO " & state.tableName &
                                              " (" & state.fieldName & ") VALUES (NULL)");
    execute(secondStmt);

    if not succeeds(execute(state.statement)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Table created by other connection does not exist. (2)");
      end if;
    elsif not fetch(state.statement) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Fetch: Fetch fails for table created by other connection. (1)");
      end if;
    end if;

    secondStmt := prepare(secondDbConnection, "DELETE FROM " & state.tableName);
    if not succeeds(execute(secondStmt)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Cannot delete from table while another database connection is open.");
      end if;
    end if;

    state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
    if not succeeds(execute(state.statement)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Table created by other connection does not exist. (3)");
      end if;
    elsif fetch(state.statement) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Fetch: Fetch succeeds for table created by other connection. (2)");
      end if;
    end if;

    secondStmt := prepare(secondDbConnection, "DROP TABLE " & state.tableName);
    if not succeeds(execute(secondStmt)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Cannot drop table while another database connection is open.");
      end if;
    end if;

    if succeeds(execute(state.statement)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Table dropped by other connection still does exist. (1)");
      end if;
    end if;
  end func;


const proc: testAutoCommit (in database: testDb, in connectData: dbConnectData) is func
  local
    var testState: state is testState("testTable", "charField", FALSE);
    var database: secondDbConnection is database.value;
    var sqlStatement: secondStmt is sqlStatement.value;
  begin
    if state.details then
      writeln("testAutoCommit");
    end if;
    block
      secondDbConnection := openDatabase(dbConnectData.driver,
                                         dbConnectData.dbName,
                                         dbConnectData.user,
                                         dbConnectData.password);
    exception
      catch DATABASE_ERROR:
        state.okay := FALSE;
        if state.details then
          writeln(" *** Cannot open database " <& dbConnectData.dbName <&
                  " with driver " <& dbConnectData.driver);
          writeln(" *** Database error: " <& errMessage(DATABASE_ERROR));
        end if;
      otherwise:
        state.okay := FALSE;
        if state.details then
          writeln(" *** Cannot open database " <& dbConnectData.dbName <&
                  " with driver " <& dbConnectData.driver);
        end if;
    end block;
    if secondDbConnection <> database.value then
      block
        if not getAutoCommit(secondDbConnection) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** AutoCommit is off on a new created connection.");
          end if;
        else
          testWithAutoCommit(testDb, state, secondDbConnection);
        end if;
      exception
        catch RANGE_ERROR:
          state.okay := FALSE;
          writeln(" *** RANGE_ERROR was raised");
        catch FILE_ERROR:
          state.okay := FALSE;
          writeln(" *** FILE_ERROR was raised");
        catch DATABASE_ERROR:
          state.okay := FALSE;
          writeln(" *** DATABASE_ERROR was raised");
      end block;
      close(secondDbConnection);
      if not state.okay then
        block
          state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
          execute(state.statement);
        exception
          otherwise:
            noop;
        end block;
      end if;
    end if;

    if state.okay then
      writeln("Autocommit works okay.");
    else
      writeln(" *** Autocommit does not work okay.");
    end if;
  end func;


const proc: testWithoutAutoCommit (in database: testDb, inout testState: state,
    in database: secondDbConnection) is func
  local
    var sqlStatement: secondStmt is sqlStatement.value;
  begin
    secondStmt := prepare(secondDbConnection, "CREATE TABLE " & state.tableName &
                                              " (" & state.fieldName & " CHAR(32))");
    execute(secondStmt);

    if not succeeds(
        state.statement := prepare(testDb, "SELECT * FROM " & state.tableName)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Prepare: Select from table created by other connection fails.");
      end if;
    elsif not succeeds(execute(state.statement)) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Execute: Table created by other connection does not exist. (1)");
      end if;
    elsif fetch(state.statement) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Fetch: Fetch succeeds for table created by other connection. (1)");
      end if;
    end if;

    secondStmt := prepare(secondDbConnection, "INSERT INTO " & state.tableName &
                                              " (" & state.fieldName & ") VALUES (NULL)");
    execute(secondStmt);

    if state.statement <> sqlStatement.value then
      if not succeeds(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Table created by other connection does not exist. (2)");
        end if;
      elsif fetch(state.statement) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Fetch: Fetch succeeds for table created by other connection. (2)");
        end if;
      end if;
    end if;

    commit(secondDbConnection);

    if state.statement <> sqlStatement.value then
      if not succeeds(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Table created by other connection does not exist. (3)");
        end if;
      elsif not fetch(state.statement) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Fetch: Fetch fails for table created by other connection. (1)");
        end if;
      end if;
    end if;

    secondStmt := prepare(secondDbConnection, "DELETE FROM " & state.tableName);
    execute(secondStmt);

    if state.statement <> sqlStatement.value then
      if not succeeds(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Table created by other connection does not exist. (4)");
        end if;
      elsif not fetch(state.statement) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Fetch: Fetch fails for table created by other connection. (2)");
        end if;
      end if;
    end if;

    rollback(secondDbConnection);

    if state.statement <> sqlStatement.value then
      if not succeeds(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Table created by other connection does not exist. (5)");
        end if;
      elsif not fetch(state.statement) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Fetch: Fetch fails for table created by other connection. (3)");
        end if;
      end if;
    end if;

    secondStmt := prepare(secondDbConnection, "DROP TABLE " & state.tableName);
    execute(secondStmt);

    if state.statement <> sqlStatement.value then
      if succeeds(execute(state.statement)) then
        state.okay := FALSE;
        if state.details then
          writeln(" *** Execute: Table dropped by other connection still does exist. (1)");
        end if;
      end if;
    end if;
  end func;


const proc: testTransactions (in database: testDb, in connectData: dbConnectData) is func
  local
    var testState: state is testState("testTable", "charField", FALSE);
    var database: secondDbConnection is database.value;
    var sqlStatement: secondStmt is sqlStatement.value;
  begin
    if state.details then
      writeln("testTransactions");
    end if;
    if transactionLocks(dbConnectData.databaseKind) then
      state.okay := FALSE;
      if state.details then
        writeln(" *** Transaction locks database or column.");
      end if;
    else
      block
        secondDbConnection := openDatabase(dbConnectData.driver,
                                           dbConnectData.dbName,
                                           dbConnectData.user,
                                           dbConnectData.password);
      exception
        catch DATABASE_ERROR:
          state.okay := FALSE;
          if state.details then
            writeln(" *** Cannot open database " <& dbConnectData.dbName <&
                    " with driver " <& dbConnectData.driver);
            writeln(" *** Database error: " <& errMessage(DATABASE_ERROR));
          end if;
        otherwise:
          state.okay := FALSE;
          if state.details then
            writeln(" *** Cannot open database " <& dbConnectData.dbName <&
                    " with driver " <& dbConnectData.driver);
          end if;
      end block;
    end if;
    if secondDbConnection <> database.value then
      block
        setAutoCommit(secondDbConnection, FALSE);
        if getAutoCommit(secondDbConnection) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** AutoCommit is still on after switching it off.");
          end if;
        else
          testWithoutAutoCommit(testDb, state, secondDbConnection);
        end if;
      exception
        catch RANGE_ERROR:
          state.okay := FALSE;
          writeln(" *** RANGE_ERROR was raised");
        catch FILE_ERROR:
          state.okay := FALSE;
          writeln(" *** FILE_ERROR was raised");
        catch DATABASE_ERROR:
          state.okay := FALSE;
          writeln(" *** DATABASE_ERROR was raised");
      end block;
      close(secondDbConnection);
      if not state.okay then
        block
          state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
          execute(state.statement);
        exception
          otherwise:
            noop;
        end block;
      end if;
    end if;

    if state.okay then
      writeln("Database transactions work okay.");
    else
      writeln(" *** Database transactions do not work okay.");
    end if;
  end func;


const proc: testBooleanField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("booleanTest", "booleanField", FALSE);
    var array boolean: expect is 0 times FALSE;
    var boolean: booleanColumn is FALSE;
    var integer: integerColumn is 0;
    var bigInteger: bigIntColumn is 0_;
    var bigRational: bigRatColumn is 0_/1_;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testBooleanField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= FALSE);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,  NULL,  expect &:= FALSE);

      insert(testDb, state,    "0", expect &:= FALSE);
      insert(testDb, state,    "1", expect &:=  TRUE);

      insert(state, FALSE,  expect &:= FALSE);
      insert(state,  TRUE,  expect &:=  TRUE);

      insert(state,     0,  expect &:= FALSE);
      insert(state,     1,  expect &:=  TRUE);

      insert(state,     0_, expect &:= FALSE);
      insert(state,     1_, expect &:=  TRUE);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        booleanColumn := column(state.statement, 1, boolean);
        if booleanColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found boolean " <& booleanColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected NULL found boolean " <& booleanColumn);
          end if;
        end if;
(*
        integerColumn := column(state.statement, 1, integer);
        if integerColumn <> ord(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found integer " <& integerColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected NULL found integer " <& integerColumn);
          end if;
        end if;
        bigIntColumn := column(state.statement, 1, bigInteger);
        if bigIntColumn <> bigInteger(ord(expect[row])) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected NULL found bigInteger " <& bigIntColumn);
          end if;
        end if;
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> bigRational(ord(expect[row])) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigRational " <& bigRatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected NULL found bigRational " <& bigRatColumn);
          end if;
        end if;
*)
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBooleanField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching booleanFields works okay.");
    else
      writeln(" *** Inserting and fetching booleanFields does not work okay.");
    end if;
  end func;


const proc: testInt8Field (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("int8Test", "int8Field", FALSE);
    var array integer: expect is 0 times 0;
    var integer: integerColumn is 0;
    var bigInteger: bigIntColumn is 0_;
    var bigRational: bigRatColumn is 0_/1_;
    var float: floatColumn is 0.0;
    var boolean: booleanColumn is FALSE;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testInt8Field: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & int8Type(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,  expect &:=    0);

      insert(testDb, state,   "0", expect &:=   0);
      insert(testDb, state,   "1", expect &:=   1);
      insert(testDb, state, "127", expect &:= 127);
      if maxInt8Value(databaseKind) = 255 then
        insert(testDb, state,  "128", expect &:=  128);
        insert(testDb, state,  "255", expect &:=  255);
      else
        insert(testDb, state,   "-1", expect &:=   -1);
        insert(testDb, state, "-128", expect &:= -128);
      end if;

      insert(state,   0, expect &:=   0);
      insert(state,   1, expect &:=   1);
      insert(state, 127, expect &:= 127);
      if maxInt8Value(databaseKind) = 255 then
        insert(state,  128, expect &:=  128);
        insert(state,  255, expect &:=  255);
        if int8Type(databaseKind) = "TINYINT" and withRangeCheck(databaseKind) then
          insert(state, 256, expect &:= 256, RANGE_CHECK);
          insert(state,  -1, expect &:=  -1, RANGE_CHECK);
        end if;
      else
        insert(state,   -1, expect &:=   -1);
        insert(state, -128, expect &:= -128);
        if int8Type(databaseKind) = "TINYINT" and withRangeCheck(databaseKind) then
          insert(state,  128, expect &:=  128, RANGE_CHECK);
          insert(state, -129, expect &:= -129, RANGE_CHECK);
        end if;
      end if;

      insert(state,   0_, expect &:=   0);
      insert(state,   1_, expect &:=   1);
      insert(state, 127_, expect &:= 127);
      if maxInt8Value(databaseKind) = 255 then
        insert(state,  128_, expect &:=  128);
        insert(state,  255_, expect &:=  255);
        if int8Type(databaseKind) = "TINYINT" and withRangeCheck(databaseKind) then
          insert(state, 256_, expect &:= 256, RANGE_CHECK);
          insert(state,  -1_, expect &:=  -1, RANGE_CHECK);
        end if;
      else
        insert(state,   -1_, expect &:=   -1);
        insert(state, -128_, expect &:= -128);
        if int8Type(databaseKind) = "TINYINT" and withRangeCheck(databaseKind) then
          insert(state,  128_, expect &:=  128, RANGE_CHECK);
          insert(state, -129_, expect &:= -129, RANGE_CHECK);
        end if;
      end if;

      insert(state, FALSE, expect &:= 0);
      insert(state,  TRUE, expect &:= 1);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        integerColumn := column(state.statement, 1, integer);
        if integerColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found integer " <& integerColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected NULL found integer " <& integerColumn);
          end if;
        end if;
        bigIntColumn := column(state.statement, 1, bigInteger);
        if bigIntColumn <> bigInteger(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected NULL found bigInteger " <& bigIntColumn);
          end if;
        end if;
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> bigRational(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigRational " <& bigRatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected NULL found bigRational " <& bigRatColumn);
          end if;
        end if;
        floatColumn := column(state.statement, 1, float);
        if floatColumn <> float(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found float " <& floatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected NULL found float " <& floatColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt8Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        if expect[row] in {0, 1} then
          booleanColumn := column(state.statement, 1, boolean);
          if booleanColumn <> boolean(expect[row]) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt8Field: Row: " <& row <&
                      " Expected " <& expect[row] <& " found boolean " <& booleanColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt8Field: Row: " <& row <&
                      " Expected NULL found boolean " <& booleanColumn);
            end if;
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching int8Fields works okay.");
    else
      writeln(" *** Inserting and fetching int8Fields does not work okay.");
    end if;
  end func;


const proc: testInt16Field (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("int16Test", "int16Field", FALSE);
    var array integer: expect is 0 times 0;
    var integer: integerColumn is 0;
    var bigInteger: bigIntColumn is 0_;
    var bigRational: bigRatColumn is 0_/1_;
    var float: floatColumn is 0.0;
    var boolean: booleanColumn is FALSE;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testInt16Field: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " SMALLINT)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL, expect &:= 0);

      insert(testDb, state,      "0", expect &:=      0);
      insert(testDb, state,      "1", expect &:=      1);
      insert(testDb, state,  "32767", expect &:=  32767);
      insert(testDb, state,     "-1", expect &:=     -1);
      insert(testDb, state, "-32768", expect &:= -32768);

      insert(state,      0, expect &:=      0);
      insert(state,      1, expect &:=      1);
      insert(state,  32767, expect &:=  32767);
      insert(state,     -1, expect &:=     -1);
      insert(state, -32768, expect &:= -32768);
      if withRangeCheck(databaseKind) then
        insert(state,  32768, expect &:=  32768, RANGE_CHECK);
        insert(state, -32769, expect &:= -32769, RANGE_CHECK);
      end if;

      insert(state,      0_, expect &:=      0);
      insert(state,      1_, expect &:=      1);
      insert(state,  32767_, expect &:=  32767);
      insert(state,     -1_, expect &:=     -1);
      insert(state, -32768_, expect &:= -32768);
      if withRangeCheck(databaseKind) then
        insert(state,  32768_, expect &:=  32768, RANGE_CHECK);
        insert(state, -32769_, expect &:=  32769, RANGE_CHECK);
      end if;

      insert(state, FALSE, expect &:= 0);
      insert(state,  TRUE, expect &:= 1);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        integerColumn := column(state.statement, 1, integer);
        if integerColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found integer " <& integerColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected NULL found integer " <& integerColumn);
          end if;
        end if;
        bigIntColumn := column(state.statement, 1, bigInteger);
        if bigIntColumn <> bigInteger(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected NULL found bigInteger " <& bigIntColumn);
          end if;
        end if;
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> bigRational(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigRational " <& bigRatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected NULL found bigRational " <& bigRatColumn);
          end if;
        end if;
        floatColumn := column(state.statement, 1, float);
        if floatColumn <> float(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found float " <& floatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected NULL found float " <& floatColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt16Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        if expect[row] in {0, 1} then
          booleanColumn := column(state.statement, 1, boolean);
          if booleanColumn <> boolean(expect[row]) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt16Field: Row: " <& row <&
                      " Expected " <& expect[row] <& " found boolean " <& booleanColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt16Field: Row: " <& row <&
                      " Expected NULL found boolean " <& booleanColumn);
            end if;
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching int16Fields works okay.");
    else
      writeln(" *** Inserting and fetching int16Fields does not work okay.");
    end if;
  end func;


const proc: testInt32Field (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("int32Test", "int32Field", FALSE);
    var array integer: expect is 0 times 0;
    var integer: integerColumn is 0;
    var bigInteger: bigIntColumn is 0_;
    var bigRational: bigRatColumn is 0_/1_;
    var float: floatColumn is 0.0;
    var boolean: booleanColumn is FALSE;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testInt32Field: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " INTEGER)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL, expect &:= 0);

      insert(testDb, state,           "0", expect &:=           0);
      insert(testDb, state,           "1", expect &:=           1);
      insert(testDb, state,  "2147483647", expect &:=  2147483647);
      insert(testDb, state,          "-1", expect &:=          -1);
      insert(testDb, state, "-2147483648", expect &:= -2147483648);

      insert(state,           0, expect &:=           0);
      insert(state,           1, expect &:=           1);
      insert(state,     1048578, expect &:=     1048578); # Zero bytes in binary representation.
      insert(state,  2147483647, expect &:=  2147483647);
      insert(state,          -1, expect &:=          -1);
      insert(state, -2147483648, expect &:= -2147483648);
      if withRangeCheck(databaseKind) then
        insert(state,  2147483648, expect &:=  2147483648, RANGE_CHECK);
        insert(state, -2147483649, expect &:= -2147483649, RANGE_CHECK);
      end if;

      insert(state,           0_, expect &:=           0);
      insert(state,           1_, expect &:=           1);
      insert(state,     1048578_, expect &:=     1048578); # Zero bytes in binary representation.
      insert(state,  2147483647_, expect &:=  2147483647);
      insert(state,          -1_, expect &:=          -1);
      insert(state, -2147483648_, expect &:= -2147483648);
      if withRangeCheck(databaseKind) then
        insert(state,  2147483648_, expect &:=  2147483648, RANGE_CHECK);
        insert(state, -2147483649_, expect &:= -2147483649, RANGE_CHECK);
      end if;

      insert(state, FALSE, expect &:= 0);
      insert(state,  TRUE, expect &:= 1);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        integerColumn := column(state.statement, 1, integer);
        if integerColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found integer " <& integerColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected NULL found integer " <& integerColumn);
          end if;
        end if;
        bigIntColumn := column(state.statement, 1, bigInteger);
        if bigIntColumn <> bigInteger(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected NULL found bigInteger " <& bigIntColumn);
          end if;
        end if;
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> bigRational(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigRational " <& bigRatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected NULL found bigRational " <& bigRatColumn);
          end if;
        end if;
        floatColumn := column(state.statement, 1, float);
        if floatColumn <> float(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found float " <& floatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected NULL found float " <& floatColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt32Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        if expect[row] in {0, 1} then
          booleanColumn := column(state.statement, 1, boolean);
          if booleanColumn <> boolean(expect[row]) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt32Field: Row: " <& row <&
                      " Expected " <& expect[row] <& " found boolean " <& booleanColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt32Field: Row: " <& row <&
                      " Expected NULL found boolean " <& booleanColumn);
            end if;
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching int32Fields works okay.");
    else
      writeln(" *** Inserting and fetching int32Fields does not work okay.");
    end if;
  end func;


const proc: testInt64Field (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("int64Test", "int64Field", FALSE);
    var array integer: expect is 0 times 0;
    var integer: integerColumn is 0;
    var bigInteger: bigIntColumn is 0_;
    var bigRational: bigRatColumn is 0_/1_;
    var float: floatColumn is 0.0;
    var string: floatAsString is "";
    var boolean: booleanColumn is FALSE;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testInt64Field: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & int64Type(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL, expect &:= 0);

      insert(testDb, state,                    "0", expect &:=                         0);
      insert(testDb, state,                    "1", expect &:=                         1);
      insert(testDb, state,             "16777215", expect &:=                  16777215); # Maximum odd float
      insert(testDb, state,             "16777216", expect &:=                  16777216);
      insert(testDb, state,             "16777217", expect &:=                  16777217);
      insert(testDb, state,     "9007199254740991", expect &:=          9007199254740991); # Maximum odd double
      insert(testDb, state,     "9007199254740992", expect &:=          9007199254740992);
      insert(testDb, state,     "9007199254740993", expect &:=          9007199254740993);
      insert(testDb, state,  "9223372036854775807", expect &:=       9223372036854775807);
      insert(testDb, state,                   "-1", expect &:=                        -1);
      insert(testDb, state,            "-16777215", expect &:=                 -16777215); # Minimum odd float
      insert(testDb, state,            "-16777216", expect &:=                 -16777216);
      insert(testDb, state,            "-16777217", expect &:=                 -16777217);
      insert(testDb, state,    "-9007199254740991", expect &:=         -9007199254740991); # Minimum odd double
      insert(testDb, state,    "-9007199254740992", expect &:=         -9007199254740992);
      insert(testDb, state,    "-9007199254740993", expect &:=         -9007199254740993);
      insert(testDb, state, "-9223372036854775808", expect &:= pred(-9223372036854775807));

      insert(state,                         0,  expect &:=                         0);
      insert(state,                         1,  expect &:=                         1);
      insert(state,                  16777215,  expect &:=                  16777215); # Maximum odd float
      insert(state,                  16777216,  expect &:=                  16777216);
      insert(state,                  16777217,  expect &:=                  16777217);
      insert(state,                4297064452,  expect &:=                4297064452); # Zero bytes in binary representation.
      insert(state,          9007199254740991,  expect &:=          9007199254740991); # Maximum odd double
      insert(state,          9007199254740992,  expect &:=          9007199254740992);
      insert(state,          9007199254740993,  expect &:=          9007199254740993);
      insert(state,       9223372036854775807,  expect &:=       9223372036854775807);
      insert(state,                        -1,  expect &:=                        -1);
      insert(state,                 -16777215,  expect &:=                 -16777215); # Maximum odd float
      insert(state,                 -16777216,  expect &:=                 -16777216);
      insert(state,                 -16777217,  expect &:=                 -16777217);
      insert(state,         -9007199254740991,  expect &:=         -9007199254740991); # Maximum odd double
      insert(state,         -9007199254740992,  expect &:=         -9007199254740992);
      insert(state,         -9007199254740993,  expect &:=         -9007199254740993);
      insert(state, pred(-9223372036854775807), expect &:= pred(-9223372036854775807));

      insert(state,                    0_, expect &:=                         0);
      insert(state,                    1_, expect &:=                         1);
      insert(state,             16777215_, expect &:=                  16777215); # Maximum odd float
      insert(state,             16777216_, expect &:=                  16777216);
      insert(state,             16777217_, expect &:=                  16777217);
      insert(state,           4297064452_, expect &:=                4297064452); # Zero bytes in binary representation.
      insert(state,     9007199254740991_, expect &:=          9007199254740991); # Maximum odd double
      insert(state,     9007199254740992_, expect &:=          9007199254740992);
      insert(state,     9007199254740993_, expect &:=          9007199254740993);
      insert(state,  9223372036854775807_, expect &:=       9223372036854775807);
      insert(state,                   -1_, expect &:=                        -1);
      insert(state,            -16777215_, expect &:=                 -16777215); # Maximum odd float
      insert(state,            -16777216_, expect &:=                 -16777216);
      insert(state,            -16777217_, expect &:=                 -16777217);
      insert(state,    -9007199254740991_, expect &:=         -9007199254740991); # Maximum odd double
      insert(state,    -9007199254740992_, expect &:=         -9007199254740992);
      insert(state,    -9007199254740993_, expect &:=         -9007199254740993);
      insert(state, -9223372036854775808_, expect &:= pred(-9223372036854775807));
      if withRangeCheck(databaseKind) then
        insert(state,  9223372036854775808_, expect &:= 0, RANGE_CHECK); # No valid value to expect.
        insert(state, -9223372036854775809_, expect &:= 0, RANGE_CHECK); # No valid value to expect.
      end if;

      insert(state, FALSE, expect &:= 0);
      insert(state,  TRUE, expect &:= 1);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        integerColumn := column(state.statement, 1, integer);
        if integerColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt64Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found integer " <& integerColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt64Field: Row: " <& row <&
                    " Expected NULL found integer " <& integerColumn);
          end if;
        end if;
        bigIntColumn := column(state.statement, 1, bigInteger);
        if bigIntColumn <> bigInteger(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt64Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt64Field: Row: " <& row <&
                    " Expected NULL found bigInteger " <& bigIntColumn);
          end if;
        end if;
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> bigRational(expect[row]) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt64Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found " <& bigRatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt64Field: Row: " <& row <&
                    " Expected NULL found bigRational " <& bigRatColumn);
          end if;
        end if;
        floatAsString := str(float(str(expect[row])));
        if endsWith(floatAsString, ".0") and
            str(expect[row]) = floatAsString[.. length(floatAsString) - 2] then
          # The expected value is representable as float.
          floatColumn := column(state.statement, 1, float);
          if floatColumn <> float(str(expect[row])) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt64Field 2: Row: " <& row <&
                      " Expected " <& expect[row] <& " found float " <& floatColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt64Field: Row: " <& row <&
                      " Expected NULL found float " <& floatColumn);
            end if;
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testInt64Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        if expect[row] in {0, 1} then
          booleanColumn := column(state.statement, 1, boolean);
          if booleanColumn <> boolean(expect[row]) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt64Field: Row: " <& row <&
                      " Expected " <& expect[row] <& " found boolean " <& booleanColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testInt64Field: Row: " <& row <&
                      " Expected NULL found boolean " <& booleanColumn);
            end if;
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching int64Fields works okay.");
    else
      writeln(" *** Inserting and fetching int64Fields does not work okay.");
    end if;
  end func;


const proc: testBigIntField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("bigIntTest", "bigIntField", FALSE);
    var array bigInteger: expect is 0 times 0_;
    var sqlStatement: statement is sqlStatement.value;
    var bigInteger: bigIntColumn is 0_;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testBigIntField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & bigIntType(databaseKind) & ")");
      execute(state.statement);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,                      NULL,  expect &:=                    0_);
      insert(state,                         1,  expect &:=                    1_);
      insert(state,                         2,  expect &:=                    2_);
      insert(state,       -999999999999999999,  expect &:=  -999999999999999999_);
      insert(state,        999999999999999999,  expect &:=   999999999999999999_);
      insert(state,      -1000000000000000000,  expect &:= -1000000000000000000_);
      insert(state,       1000000000000000000,  expect &:=  1000000000000000000_);
      insert(state,      -1234567890123456789,  expect &:= -1234567890123456789_);
      insert(state,       1234567890123456789,  expect &:=  1234567890123456789_);
      insert(state, pred(-9223372036854775807), expect &:= -9223372036854775808_);
      insert(state,       9223372036854775807,  expect &:=  9223372036854775807_);

      insert(state,                    1_, expect &:=                    1_);
      insert(state,                    2_, expect &:=                    2_);
      insert(state,  -999999999999999999_, expect &:=  -999999999999999999_);
      insert(state,   999999999999999999_, expect &:=   999999999999999999_);
      insert(state, -1000000000000000000_, expect &:= -1000000000000000000_);
      insert(state,  1000000000000000000_, expect &:=  1000000000000000000_);
      insert(state, -1234567890123456789_, expect &:= -1234567890123456789_);
      insert(state,  1234567890123456789_, expect &:=  1234567890123456789_);
      insert(state, -9223372036854775808_, expect &:= -9223372036854775808_);
      insert(state,  9223372036854775807_, expect &:=  9223372036854775807_);
      if bigIntTypeBits(databaseKind) >= 127 then
        insert(state,  -9223372036854775809_, expect &:=  -9223372036854775809_);
        insert(state,   9223372036854775808_, expect &:=   9223372036854775808_);
        insert(state,  -9999999999999999999_, expect &:=  -9999999999999999999_);
        insert(state,   9999999999999999999_, expect &:=   9999999999999999999_);
        insert(state, -10000000000000000000_, expect &:= -10000000000000000000_);
        insert(state,  10000000000000000000_, expect &:=  10000000000000000000_);
        insert(state,  -9999999999999999999999999999999999999_, expect &:=  -9999999999999999999999999999999999999_);
        insert(state,   9999999999999999999999999999999999999_, expect &:=   9999999999999999999999999999999999999_);
        insert(state, -10000000000000000000000000000000000000_, expect &:= -10000000000000000000000000000000000000_);
        insert(state,  10000000000000000000000000000000000000_, expect &:=  10000000000000000000000000000000000000_);
        insert(state, -85070591730234615865843651857942052864_, expect &:= -85070591730234615865843651857942052864_);
        insert(state,  85070591730234615865843651857942052863_, expect &:=  85070591730234615865843651857942052863_);
      end if;
      if bigIntTypeBits(databaseKind) >= 216 then
        insert(state,   -85070591730234615865843651857942052864_, expect &:=   -85070591730234615865843651857942052864_);
        insert(state,    85070591730234615865843651857942052863_, expect &:=    85070591730234615865843651857942052863_);
        insert(state,   -99999999999999999999999999999999999999_, expect &:=   -99999999999999999999999999999999999999_);
        insert(state,    99999999999999999999999999999999999999_, expect &:=    99999999999999999999999999999999999999_);
        insert(state,  -100000000000000000000000000000000000000_, expect &:=  -100000000000000000000000000000000000000_);
        insert(state,   100000000000000000000000000000000000000_, expect &:=   100000000000000000000000000000000000000_);
        insert(state,  -170141183460469231731687303715884105728_, expect &:=  -170141183460469231731687303715884105728_);
        insert(state,   170141183460469231731687303715884105727_, expect &:=   170141183460469231731687303715884105727_);
        insert(state,  -340282366920938463463374607431768211455_, expect &:=  -340282366920938463463374607431768211455_);
        insert(state,   340282366920938463463374607431768211455_, expect &:=   340282366920938463463374607431768211455_);
        insert(state, -1000000000000000000000000000000000000000_, expect &:= -1000000000000000000000000000000000000000_);
        insert(state,  1000000000000000000000000000000000000000_, expect &:=  1000000000000000000000000000000000000000_);
      end if;

      insert(state, FALSE, expect &:= 0_);
      insert(state,  TRUE, expect &:= 1_);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        bigIntColumn := column(state.statement, 1, bigInteger);
        if bigIntColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigIntField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row = 1 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigIntField: Row: " <& row <&
                    " Expected NULL found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row > 1 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigIntField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching bigInteger fields works okay.");
    else
      writeln(" *** Inserting and fetching bigInteger fields does not work okay.");
    end if;
  end func;


const proc: testFloatField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("floatTest", "floatField", FALSE);
    var array float: expect is 0 times 0.0;
    var float: floatColumn is 0.0;
    var boolean: isEqual is FALSE;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testFloatField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & floatType(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0.0);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL, expect &:= 0.0);

      insert(testDb, state,            "-16777215",     expect &:=            -16777215.0);
      insert(testDb, state,                   "-1",     expect &:=                   -1.0);
      insert(testDb, state,                    "0",     expect &:=                    0.0);
      insert(testDb, state,                    "1",     expect &:=                    1.0);
      insert(testDb, state,             "16777215",     expect &:=             16777215.0);

      insert(testDb, state, "-9223372036854775809.0",   expect &:= -9223372036854775809.0);
      insert(testDb, state, "-9223372036854775808.0",   expect &:= -9223372036854775808.0);
      insert(testDb, state,    "0.0",                   expect &:=    0.0);
      insert(testDb, state,    "5.9604644775390625e-8", expect &:=    5.9604644775390625e-8);
      insert(testDb, state,    "2.384185791015625e-7",  expect &:=    2.384185791015625e-7);
      insert(testDb, state,    "4.76837158203125e-7",   expect &:=    4.76837158203125e-7);
      insert(testDb, state,    "9.5367431640625e-7",    expect &:=    9.5367431640625e-7);
      insert(testDb, state,    "0.000244140625",        expect &:=    0.000244140625);
      insert(testDb, state,    "0.0009765625",          expect &:=    0.0009765625);
      insert(testDb, state,    "3.5",                   expect &:=    3.5);
      insert(testDb, state,    "4.125",                 expect &:=    4.125);
      insert(testDb, state, "4882.8125",                expect &:= 4882.8125);
      insert(testDb, state,  "9223372036854775807.0",   expect &:=  9223372036854775807.0);
      insert(testDb, state,  "9223372036854775808.0",   expect &:=  9223372036854775808.0);

      insert(state, 1,                          expect &:=                    1.0);
      insert(state, pred(-9223372036854775807), expect &:= -9223372036854775808.0);
      insert(state, 9223372036854775807,        expect &:=  9223372036854775807.0);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,                    2_,      expect &:=                    2.0);
      insert(state, -9223372036854775809_,      expect &:= -9223372036854775809.0);
      insert(state,  9223372036854775808_,      expect &:=  9223372036854775808.0);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,  7_/2_,                     expect &:=  3.5);
      insert(state,  5000000_ / 1024_,          expect &:=  4882.8125);
      insert(state, -9223372036854775808_/1_,   expect &:= -9223372036854775808.0);
      insert(state,  9223372036854775807_/1_,   expect &:=  9223372036854775807.0);
      insInf(state, -1_/0_,                     expect &:= -Infinity);
      insInf(state,  1_/0_,                     expect &:=  Infinity);
      insNaN(state,  0_/0_,                     expect &:=  NaN);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, -9223372036854775809.0,     expect &:= -9223372036854775809.0);
      insert(state, -9223372036854775808.0,     expect &:= -9223372036854775808.0);
      insert(state,    0.0,                     expect &:=    0.0);
      insert(state,    5.9604644775390625e-8,   expect &:=    5.9604644775390625e-8);
      insert(state,    2.384185791015625e-7,    expect &:=    2.384185791015625e-7);
      insert(state,    4.76837158203125e-7,     expect &:=    4.76837158203125e-7);
      insert(state,    9.5367431640625e-7,      expect &:=    9.5367431640625e-7);
      insert(state,    0.000244140625,          expect &:=    0.000244140625);
      insert(state,    0.0009765625,            expect &:=    0.0009765625);
      insert(state,    3.5,                     expect &:=    3.5);
      insert(state,    4.125,                   expect &:=    4.125);
      insert(state, 4882.8125,                  expect &:= 4882.8125);
      insert(state,  9223372036854775807.0,     expect &:=  9223372036854775807.0);
      insert(state,  9223372036854775808.0,     expect &:=  9223372036854775808.0);
      insInf(state, -Infinity,                  expect &:= -Infinity);
      insInf(state,  Infinity,                  expect &:=  Infinity);
      insNaN(state,  NaN,                       expect &:=  NaN);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        floatColumn := column(state.statement, 1, float);
        if compareFloatAsDecimalString(databaseKind) then
          isEqual := str(floatColumn) = str(expect[row]);
        else
          isEqual := floatColumn = expect[row];
        end if;
        if not isEqual and
            (not isNaN(floatColumn) or not isNaN(expect[row])) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testFloatField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found float " <& floatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testFloatField: Row: " <& row <&
                    " Expected NULL found float " <& floatColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testFloatField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching float fields works okay.");
    else
      writeln(" *** Inserting and fetching float fields does not work okay.");
    end if;
  end func;


const proc: testDoubleField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("doubleTest", "doubleField", FALSE);
    var array float: expect is 0 times 0.0;
    var float: doubleColumn is 0.0;
    var boolean: isEqual is FALSE;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testDoubleField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                           " (" & state.fieldName & " " & doubleType(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0.0);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL, expect &:= 0.0);

      insert(testDb, state,    "-9007199254740991",     expect &:=    -9007199254740991.0);
      insert(testDb, state,                   "-1",     expect &:=                   -1.0);
      insert(testDb, state,                    "0",     expect &:=                    0.0);
      insert(testDb, state,                    "1",     expect &:=                    1.0);
      insert(testDb, state,     "9007199254740991",     expect &:=     9007199254740991.0);

      insert(testDb, state, "-9223372036854775809.0",   expect &:= -9223372036854775809.0);
      insert(testDb, state, "-9223372036854775808.0",   expect &:= -9223372036854775808.0);
      insert(testDb, state,    "0.0",                   expect &:=    0.0);
      insert(testDb, state,    "5.9604644775390625e-8", expect &:=    5.9604644775390625e-8);
      insert(testDb, state,    "2.384185791015625e-7",  expect &:=    2.384185791015625e-7);
      insert(testDb, state,    "4.76837158203125e-7",   expect &:=    4.76837158203125e-7);
      insert(testDb, state,    "9.5367431640625e-7",    expect &:=    9.5367431640625e-7);
      insert(testDb, state,    "0.000244140625",        expect &:=    0.000244140625);
      insert(testDb, state,    "0.0009765625",          expect &:=    0.0009765625);
      insert(testDb, state,    "3.5",                   expect &:=    3.5);
      insert(testDb, state,    "4.125",                 expect &:=    4.125);
      insert(testDb, state, "4882.8125",                expect &:= 4882.8125);
      insert(testDb, state,  "9223372036854775807.0",   expect &:=  9223372036854775807.0);
      insert(testDb, state,  "9223372036854775808.0",   expect &:=  9223372036854775808.0);

      insert(state, 1,                          expect &:=                    1.0);
      insert(state, pred(-9223372036854775807), expect &:= -9223372036854775808.0);
      insert(state, 9223372036854775807,        expect &:=  9223372036854775807.0);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 2_,                         expect &:=                    2.0);
      insert(state, -9223372036854775809_,      expect &:= -9223372036854775809.0);
      insert(state, 9223372036854775808_,       expect &:=  9223372036854775808.0);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,  7_/2_,                     expect &:=  3.5);
      insert(state,  1234567654321_ / 781250_,  expect &:=  1580246.59753088);
      insert(state, -9223372036854775808_/1_,   expect &:= -9223372036854775808.0);
      insert(state,  9223372036854775807_/1_,   expect &:=  9223372036854775807.0);
      insInf(state, -1_/0_,                     expect &:= -Infinity);
      insInf(state,  1_/0_,                     expect &:=  Infinity);
      insNaN(state,  0_/0_,                     expect &:=  NaN);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, -9223372036854775809.0,     expect &:= -9223372036854775809.0);
      insert(state, -9223372036854775808.0,     expect &:= -9223372036854775808.0);
      insert(state,    0.0,                     expect &:=    0.0);
      insert(state,    5.9604644775390625e-8,   expect &:=    5.9604644775390625e-8);
      insert(state,    2.384185791015625e-7,    expect &:=    2.384185791015625e-7);
      insert(state,    4.76837158203125e-7,     expect &:=    4.76837158203125e-7);
      insert(state,    9.5367431640625e-7,      expect &:=    9.5367431640625e-7);
      insert(state,    0.000244140625,          expect &:=    0.000244140625);
      insert(state,    0.0009765625,            expect &:=    0.0009765625);
      insert(state,    3.5,                     expect &:=    3.5);
      insert(state,    4.125,                   expect &:=    4.125);
      insert(state, 4882.8125,                  expect &:= 4882.8125);
      insert(state,  9223372036854775807.0,     expect &:=  9223372036854775807.0);
      insert(state,  9223372036854775808.0,     expect &:=  9223372036854775808.0);
      insInf(state, -Infinity,                  expect &:= -Infinity);
      insInf(state,  Infinity,                  expect &:=  Infinity);
      insNaN(state,  NaN,                       expect &:=  NaN);

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        doubleColumn := column(state.statement, 1, float);
        if compareDoubleAsDecimalString(databaseKind) then
          isEqual := str(doubleColumn) = str(expect[row]);
        else
          isEqual := doubleColumn = expect[row];
        end if;
        if not isEqual and
            (not isNaN(doubleColumn) or not isNaN(expect[row])) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDoubleField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found double " <& doubleColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDoubleField: Row: " <& row <&
                    " Expected NULL found double " <& doubleColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDoubleField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching double fields works okay.");
    else
      writeln(" *** Inserting and fetching double fields does not work okay.");
    end if;
  end func;


const proc: testBigRatField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("bigRatTest", "bigRatField", FALSE);
    var array bigRational: expect is 0 times 0_/1_;
    var bigRational: bigRatColumn is bigRational.value;
    var float: floatColumn is 0.0;
    var integer: row is 1;
    var bigInteger: numerator is 0_;
  begin
    if state.details then
      writeln("testBigRatField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & bigRatType(databaseKind) & ")");
      execute(state.statement);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,                      NULL,  expect &:=                    0_/1_);
      insert(state,                         0,  expect &:=                    0_/1_);
      insert(state,                         1,  expect &:=                    1_/1_);
      insert(state, pred(-9223372036854775807), expect &:= -9223372036854775808_/1_);
      insert(state,       9223372036854775807,  expect &:=  9223372036854775807_/1_);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,                    2_,      expect &:=                    2_/1_);
      insert(state, -9223372036854775809_,      expect &:= -9223372036854775809_/1_);
      insert(state,  9223372036854775808_,      expect &:=  9223372036854775808_/1_);

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                           " (" & state.fieldName & ") VALUES (?)");
      insert(state,  0_/1_,                     expect &:=  0_/1_);
      insert(state,  1_/1_,                     expect &:=  1_/1_);
      insert(state,  7_/2_,                     expect &:=  7_/2_);
      insert(state,  9223372036854775807_/1_,   expect &:=  9223372036854775807_/1_);
      insert(state,  9223372036854775808_/1_,   expect &:=  9223372036854775808_/1_);
      insert(state,  12345678901234500000000_/1_,
          expect &:= 12345678901234500000000_/1_);
      insert(state,  123456789012345600000000_/1_,
          expect &:= 123456789012345600000000_/1_);
      insert(state,  12345678901234567890123400000000_/1_,
          expect &:= 12345678901234567890123400000000_/1_);
      insert(state,  12345678901234567890123456789012000_/1_,
          expect &:= 12345678901234567890123456789012000_/1_);
      insert(state,  1234567890123450_/1_,
          expect &:= 1234567890123450_/1_);
      insert(state,  12345678901234560_/1_,
          expect &:= 12345678901234560_/1_);
      insert(state,  1234567890123456789012340_/1_,
          expect &:= 1234567890123456789012340_/1_);
      insert(state,  123456789012345678901234567890120_/1_,
          expect &:= 123456789012345678901234567890120_/1_);
      insert(state,  123456789012345_/1_,
          expect &:= 123456789012345_/1_);
      insert(state,  1234567890123456_/1_,
          expect &:= 1234567890123456_/1_);
      insert(state,  123456789012345678901234_/1_,
          expect &:= 123456789012345678901234_/1_);
      insert(state,  12345678901234567890123456789012_/1_,
          expect &:= 12345678901234567890123456789012_/1_);
      insert(state,  123456789012345_/10_,
          expect &:= 123456789012345_/10_);
      insert(state,  1234567890123456_/10_,
          expect &:= 1234567890123456_/10_);
      insert(state,  123456789012345678901234_/10_,
          expect &:= 123456789012345678901234_/10_);
      insert(state,  12345678901234567890123456789012_/10_,
          expect &:= 12345678901234567890123456789012_/10_);
      insert(state,  123456789012345_/10000000_,
          expect &:= 123456789012345_/10000000_);
      insert(state,  1234567890123456_/100000000_,
          expect &:= 1234567890123456_/100000000_);
      insert(state,  123456789012345678901234_/1000000000000_,
          expect &:= 123456789012345678901234_/1000000000000_);
      insert(state,  12345678901234567890123456789012_/10000000000000000_,
          expect &:= 12345678901234567890123456789012_/10000000000000000_);
      insert(state,  123456789012345678901234567890123456789_/100000000000000000000_,
          expect &:= 123456789012345678901234567890123456789_/100000000000000000000_);
      insert(state,  123456789012345_/100000000000000_,
          expect &:= 123456789012345_/100000000000000_);
      insert(state,  1234567890123456_/1000000000000000_,
          expect &:= 1234567890123456_/1000000000000000_);
      insert(state,  123456789012345678901234_/100000000000000000000000_,
          expect &:= 123456789012345678901234_/100000000000000000000000_);
      insert(state,  1234567890123456789012345678901_/1000000000000000000000000000000_,
          expect &:= 1234567890123456789012345678901_/1000000000000000000000000000000_);
      insert(state,  123456789012345_/1000000000000000_,
          expect &:= 123456789012345_/1000000000000000_);
      insert(state,  1234567890123456_/10000000000000000_,
          expect &:= 1234567890123456_/10000000000000000_);
      insert(state,  123456789012345678901234_/1000000000000000000000000_,
          expect &:= 123456789012345678901234_/1000000000000000000000000_);
      insert(state,  123456789012345678901234567891_/1000000000000000000000000000000_,
          expect &:= 123456789012345678901234567891_/1000000000000000000000000000000_);
      insert(state,  123456789012345_/10000000000000000_,
          expect &:= 123456789012345_/10000000000000000_);
      insert(state,  1234567890123456_/100000000000000000_,
          expect &:= 1234567890123456_/100000000000000000_);
      insert(state,  123456789012345678901234_/10000000000000000000000000_,
          expect &:= 123456789012345678901234_/10000000000000000000000000_);
      insert(state,  12345678901234567890123456789_/1000000000000000000000000000000_,
          expect &:= 12345678901234567890123456789_/1000000000000000000000000000000_);
      insert(state,  123456789012345_/10000000000000000000_,
          expect &:= 123456789012345_/10000000000000000000_);
      insert(state,  1234567890123456_/100000000000000000000_,
          expect &:= 1234567890123456_/100000000000000000000_);
      insert(state,  123456789012345678901234_/1000000000000000000000000000000_,
          expect &:= 123456789012345678901234_/1000000000000000000000000000000_);
      insert(state, -0_/1_,                     expect &:= -0_/1_);
      insert(state, -1_/1_,                     expect &:= -1_/1_);
      insert(state, -7_/2_,                     expect &:= -7_/2_);
      insert(state, -9223372036854775807_/1_,   expect &:= -9223372036854775807_/1_);
      insert(state, -9223372036854775808_/1_,   expect &:= -9223372036854775808_/1_);
      insert(state,  -12345678901234500000000_/1_,
          expect &:= -12345678901234500000000_/1_);
      insert(state,  -123456789012345600000000_/1_,
          expect &:= -123456789012345600000000_/1_);
      insert(state,  -12345678901234567890123400000000_/1_,
          expect &:= -12345678901234567890123400000000_/1_);
      insert(state,  -1234567890123456789012345678901200_/1_,
          expect &:= -1234567890123456789012345678901200_/1_);
      insert(state,  -1234567890123450_/1_,
          expect &:= -1234567890123450_/1_);
      insert(state,  -12345678901234560_/1_,
          expect &:= -12345678901234560_/1_);
      insert(state,  -1234567890123456789012340_/1_,
          expect &:= -1234567890123456789012340_/1_);
      insert(state,  -123456789012345678901234567890120_/1_,
          expect &:= -123456789012345678901234567890120_/1_);
      insert(state,  -123456789012345_/1_,
          expect &:= -123456789012345_/1_);
      insert(state,  -1234567890123456_/1_,
          expect &:= -1234567890123456_/1_);
      insert(state,  -123456789012345678901234_/1_,
          expect &:= -123456789012345678901234_/1_);
      insert(state,  -12345678901234567890123456789012_/1_,
          expect &:= -12345678901234567890123456789012_/1_);
      insert(state,  -123456789012345_/10_,
          expect &:= -123456789012345_/10_);
      insert(state,  -1234567890123456_/10_,
          expect &:= -1234567890123456_/10_);
      insert(state,  -123456789012345678901234_/10_,
          expect &:= -123456789012345678901234_/10_);
      insert(state,  -12345678901234567890123456789012_/10_,
          expect &:= -12345678901234567890123456789012_/10_);
      insert(state,  -123456789012345_/10000000_,
          expect &:= -123456789012345_/10000000_);
      insert(state,  -1234567890123456_/100000000_,
          expect &:= -1234567890123456_/100000000_);
      insert(state,  -123456789012345678901234_/1000000000000_,
          expect &:= -123456789012345678901234_/1000000000000_);
      insert(state,  -12345678901234567890123456789012_/10000000000000000_,
          expect &:= -12345678901234567890123456789012_/10000000000000000_);
      insert(state,  -123456789012345678901234567890123456789_/100000000000000000000_,
          expect &:= -123456789012345678901234567890123456789_/100000000000000000000_);
      insert(state,  -123456789012345_/100000000000000_,
          expect &:= -123456789012345_/100000000000000_);
      insert(state,  -1234567890123456_/1000000000000000_,
          expect &:= -1234567890123456_/1000000000000000_);
      insert(state,  -123456789012345678901234_/100000000000000000000000_,
          expect &:= -123456789012345678901234_/100000000000000000000000_);
      insert(state,  -1234567890123456789012345678901_/1000000000000000000000000000000_,
          expect &:= -1234567890123456789012345678901_/1000000000000000000000000000000_);
      insert(state,  -123456789012345_/1000000000000000_,
          expect &:= -123456789012345_/1000000000000000_);
      insert(state,  -1234567890123456_/10000000000000000_,
          expect &:= -1234567890123456_/10000000000000000_);
      insert(state,  -123456789012345678901234_/1000000000000000000000000_,
          expect &:= -123456789012345678901234_/1000000000000000000000000_);
      insert(state,  -123456789012345678901234567891_/1000000000000000000000000000000_,
          expect &:= -123456789012345678901234567891_/1000000000000000000000000000000_);
      insert(state,  -123456789012345_/10000000000000000_,
          expect &:= -123456789012345_/10000000000000000_);
      insert(state,  -1234567890123456_/100000000000000000_,
          expect &:= -1234567890123456_/100000000000000000_);
      insert(state,  -123456789012345678901234_/10000000000000000000000000_,
          expect &:= -123456789012345678901234_/10000000000000000000000000_);
      insert(state,  -12345678901234567890123456789_/1000000000000000000000000000000_,
          expect &:= -12345678901234567890123456789_/1000000000000000000000000000000_);
      insert(state,  -123456789012345_/10000000000000000000_,
          expect &:= -123456789012345_/10000000000000000000_);
      insert(state,  -1234567890123456_/100000000000000000000_,
          expect &:= -1234567890123456_/100000000000000000000_);
      insert(state,  -123456789012345678901234_/1000000000000000000000000000000_,
          expect &:= -123456789012345678901234_/1000000000000000000000000000000_);
      if supportsFloatingDecimals(databaseKind) then
        insert(state,   12345678901234567890123456789012345678900000000_/1_,
            expect &:=  12345678901234567890123456789012345678900000000_/1_);
        insert(state,   1234567890123456789012345678901234567890_/1_,
            expect &:=  1234567890123456789012345678901234567890_/1_);
        insert(state,   123456789012345678901234567890123456789_/1_,
            expect &:=  123456789012345678901234567890123456789_/1_);
        insert(state,   123456789012345678901234567890123456789_/10_,
            expect &:=  123456789012345678901234567890123456789_/10_);
        insert(state,   123456789012345678901234567890123456789_/100000000000000000000000000000000000000_,
            expect &:=  123456789012345678901234567890123456789_/100000000000000000000000000000000000000_);
        insert(state,   123456789012345678901234567890123456789_/1000000000000000000000000000000000000000_,
            expect &:=  123456789012345678901234567890123456789_/1000000000000000000000000000000000000000_);
        insert(state,   123456789012345678901234567890123456789_/10000000000000000000000000000000000000000_,
            expect &:=  123456789012345678901234567890123456789_/10000000000000000000000000000000000000000_);
        insert(state,   12345678901234567890123456789012_/10000000000000000000000000000000000000000_,
            expect &:=  12345678901234567890123456789012_/10000000000000000000000000000000000000000_);
        insert(state,   123456789012345678901234567890123456789_/100000000000000000000000000000000000000000000000_,
            expect &:=  123456789012345678901234567890123456789_/100000000000000000000000000000000000000000000000_);
        insert(state,  -12345678901234567890123456789012345678900000000_/1_,
            expect &:= -12345678901234567890123456789012345678900000000_/1_);
        insert(state,  -1234567890123456789012345678901234567890_/1_,
            expect &:= -1234567890123456789012345678901234567890_/1_);
        insert(state,  -123456789012345678901234567890123456789_/1_,
            expect &:= -123456789012345678901234567890123456789_/1_);
        insert(state,  -123456789012345678901234567890123456789_/10_,
            expect &:= -123456789012345678901234567890123456789_/10_);
        insert(state,  -123456789012345678901234567890123456789_/100000000000000000000000000000000000000_,
            expect &:= -123456789012345678901234567890123456789_/100000000000000000000000000000000000000_);
        insert(state,  -123456789012345678901234567890123456789_/1000000000000000000000000000000000000000_,
            expect &:= -123456789012345678901234567890123456789_/1000000000000000000000000000000000000000_);
        insert(state,  -123456789012345678901234567890123456789_/10000000000000000000000000000000000000000_,
            expect &:= -123456789012345678901234567890123456789_/10000000000000000000000000000000000000000_);
        insert(state,  -12345678901234567890123456789012_/10000000000000000000000000000000000000000_,
            expect &:= -12345678901234567890123456789012_/10000000000000000000000000000000000000000_);
        insert(state,  -123456789012345678901234567890123456789_/100000000000000000000000000000000000000000000000_,
            expect &:= -123456789012345678901234567890123456789_/100000000000000000000000000000000000000000000000_);
      end if;
      insInf(state, -1_/0_,                     expect &:= -1_/0_);
      insInf(state,  1_/0_,                     expect &:=  1_/0_);
      insNaN(state,  0_/0_,                     expect &:=  0_/0_);
      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigRatField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found " <& bigRatColumn);
          end if;
        end if;
        if row = 1 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigRatField: Row: " <& row <&
                    " Expected NULL found " <& bigRatColumn);
          end if;
        end if;
        floatColumn := column(state.statement, 1, float);
        if floatColumn <> float(str(expect[row])) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigRatField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found float " <& floatColumn);
          end if;
        end if;
        if row = 1 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigRatField: Row: " <& row <&
                    " Expected NULL found float " <& floatColumn);
          end if;
        end if;
        if row > 1 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBigRatField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching bigRational fields works okay.");
    else
      writeln(" *** Inserting and fetching bigRational fields does not work okay.");
    end if;
  end func;


const proc: testAnyIntegerField (in database: testDb, inout testState: state,
    in string: fieldType, in integer: precision, in integer: sqlIntLiteralBits) is func
  local
    var array bigInteger: expect is 0 times 0_;
    var integer: integerColumn is 0;
    var bigInteger: bigIntColumn is 0_;
    var bigRational: bigRatColumn is bigRational.value;
    var float: floatColumn is 0.0;
    var string: floatAsString is "";
    var integer: row is 1;
  begin
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & fieldType & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0_);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,  expect &:= 0_);

      insert(testDb, state,  "0", expect &:=  0_);
      insert(testDb, state,  "1", expect &:=  1_);
      insert(testDb, state, "-1", expect &:= -1_);
      if precision >= 18 then
        insert(testDb, state,  "123456789012345678", expect &:=  123456789012345678_);
        insert(testDb, state,  "999999999999999999", expect &:=  999999999999999999_);
        insert(testDb, state, "-123456789012345678", expect &:= -123456789012345678_);
        insert(testDb, state, "-999999999999999999", expect &:= -999999999999999999_);
      end if;
      if sqlIntLiteralBits = 64 then
        insert(testDb, state,  "1000000000000000000", expect &:=  1000000000000000000_);
        insert(testDb, state,  "1234567890123456789", expect &:=  1234567890123456789_);
        insert(testDb, state,  "9223372036854775807", expect &:=  9223372036854775807_);
        insert(testDb, state, "-1000000000000000000", expect &:= -1000000000000000000_);
        insert(testDb, state, "-1234567890123456789", expect &:= -1234567890123456789_);
        insert(testDb, state, "-9223372036854775808", expect &:= -9223372036854775808_);
      end if;
      if sqlIntLiteralBits > 64 then
        insert(testDb, state,  "9223372036854775808", expect &:=  9223372036854775808_);
        insert(testDb, state,  "9999999999999999999", expect &:=  9999999999999999999_);
        insert(testDb, state, "-9223372036854775809", expect &:= -9223372036854775809_);
        insert(testDb, state, "-9999999999999999999", expect &:= -9999999999999999999_);
        if precision >= 19 then
          insert(testDb, state,  "1000000000000000000", expect &:=  1000000000000000000_);
          insert(testDb, state,  "1234567890123456789", expect &:=  1234567890123456789_);
          insert(testDb, state,  "9223372036854775807", expect &:=  9223372036854775807_);
          insert(testDb, state,  "9999999999999999999", expect &:=  9999999999999999999_);
          insert(testDb, state, "-1000000000000000000", expect &:= -1000000000000000000_);
          insert(testDb, state, "-1234567890123456789", expect &:= -1234567890123456789_);
          insert(testDb, state, "-9223372036854775808", expect &:= -9223372036854775808_);
          insert(testDb, state, "-9999999999999999999", expect &:= -9999999999999999999_);
        end if;
        if precision >= 38 then
          insert(testDb, state,  "12345678901234567890123456789012345678",
                      expect &:=  12345678901234567890123456789012345678_);
          insert(testDb, state,  "99999999999999999999999999999999999999",
                      expect &:=  99999999999999999999999999999999999999_);
          insert(testDb, state, "-12345678901234567890123456789012345678",
                      expect &:= -12345678901234567890123456789012345678_);
          insert(testDb, state, "-99999999999999999999999999999999999999",
                      expect &:= -99999999999999999999999999999999999999_);
        end if;
        if precision >= 65 then
          insert(testDb, state,  "12345678901234567890123456789012345678901234567890123456789012345",
                      expect &:=  12345678901234567890123456789012345678901234567890123456789012345_);
          insert(testDb, state,  "99999999999999999999999999999999999999999999999999999999999999999",
                      expect &:=  99999999999999999999999999999999999999999999999999999999999999999_);
          insert(testDb, state, "-12345678901234567890123456789012345678901234567890123456789012345",
                      expect &:= -12345678901234567890123456789012345678901234567890123456789012345_);
          insert(testDb, state, "-99999999999999999999999999999999999999999999999999999999999999999",
                      expect &:= -99999999999999999999999999999999999999999999999999999999999999999_);
        end if;
        if precision >= 100 then
          insert(testDb, state,
                        "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
              expect &:= 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_);
          insert(testDb, state,
                        "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999",
              expect &:= 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_);
          insert(testDb, state,
                        "-1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
              expect &:= -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_);
          insert(testDb, state,
                        "-9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999",
              expect &:= -9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_);
        end if;
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0, expect &:= 0_);
      insert(state, 1, expect &:= 1_);
      insert(state, -1, expect &:= -1_);
      if precision >= 18 then
        insert(state,  123456789012345678, expect &:=  123456789012345678_);
        insert(state,  999999999999999999, expect &:=  999999999999999999_);
        insert(state, -123456789012345678, expect &:= -123456789012345678_);
        insert(state, -999999999999999999, expect &:= -999999999999999999_);
      end if;
      if precision >= 19 then
        insert(state,       1000000000000000000,  expect &:=  1000000000000000000_);
        insert(state,       1234567890123456789,  expect &:=  1234567890123456789_);
        insert(state,       9223372036854775807,  expect &:=  9223372036854775807_);
        insert(state,      -1000000000000000000,  expect &:= -1000000000000000000_);
        insert(state,      -1234567890123456789,  expect &:= -1234567890123456789_);
        insert(state, pred(-9223372036854775807), expect &:= -9223372036854775808_);
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0_, expect &:= 0_);
      insert(state, 1_, expect &:= 1_);
      insert(state, -1_, expect &:= -1_);
      if precision >= 18 then
        insert(state,  123456789012345678_, expect &:=  123456789012345678_);
        insert(state,  999999999999999999_, expect &:=  999999999999999999_);
        insert(state, -123456789012345678_, expect &:= -123456789012345678_);
        insert(state, -999999999999999999_, expect &:= -999999999999999999_);
      end if;
      if precision >= 19 then
        insert(state,  1000000000000000000_, expect &:=  1000000000000000000_);
        insert(state,  1234567890123456789_, expect &:=  1234567890123456789_);
        insert(state,  9223372036854775807_, expect &:=  9223372036854775807_);
        insert(state,  9223372036854775808_, expect &:=  9223372036854775808_);
        insert(state,  9999999999999999999_, expect &:=  9999999999999999999_);
        insert(state, -1000000000000000000_, expect &:= -1000000000000000000_);
        insert(state, -1234567890123456789_, expect &:= -1234567890123456789_);
        insert(state, -9223372036854775808_, expect &:= -9223372036854775808_);
        insert(state, -9223372036854775809_, expect &:= -9223372036854775809_);
        insert(state, -9999999999999999999_, expect &:= -9999999999999999999_);
      end if;
      if precision >= 38 then
        insert(state,   12345678901234567890123456789012345678_,
            expect &:=  12345678901234567890123456789012345678_);
        insert(state,   99999999999999999999999999999999999999_,
            expect &:=  99999999999999999999999999999999999999_);
        insert(state,  -12345678901234567890123456789012345678_,
            expect &:= -12345678901234567890123456789012345678_);
        insert(state,  -99999999999999999999999999999999999999_,
            expect &:= -99999999999999999999999999999999999999_);
      end if;
      if precision >= 65 then
        insert(state,   12345678901234567890123456789012345678901234567890123456789012345_,
            expect &:=  12345678901234567890123456789012345678901234567890123456789012345_);
        insert(state,   99999999999999999999999999999999999999999999999999999999999999999_,
            expect &:=  99999999999999999999999999999999999999999999999999999999999999999_);
        insert(state,  -12345678901234567890123456789012345678901234567890123456789012345_,
            expect &:= -12345678901234567890123456789012345678901234567890123456789012345_);
        insert(state,  -99999999999999999999999999999999999999999999999999999999999999999_,
            expect &:= -99999999999999999999999999999999999999999999999999999999999999999_);
      end if;
      if precision >= 100 then
        insert(state,   1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_,
            expect &:=  1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_);
        insert(state,   9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_,
            expect &:=  9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_);
        insert(state,  -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_,
            expect &:= -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_);
        insert(state,  -9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_,
            expect &:= -9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_);
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0_/1_, expect &:= 0_);
      insert(state, 1_/1_, expect &:= 1_);
      insert(state, -1_/1_, expect &:= -1_);
      if precision >= 18 then
        insert(state,  123456789012345678_/1_, expect &:=  123456789012345678_);
        insert(state,  999999999999999999_/1_, expect &:=  999999999999999999_);
        insert(state, -123456789012345678_/1_, expect &:= -123456789012345678_);
        insert(state, -999999999999999999_/1_, expect &:= -999999999999999999_);
      end if;
      if precision >= 19 then
        insert(state,  1000000000000000000_/1_, expect &:=  1000000000000000000_);
        insert(state,  1234567890123456789_/1_, expect &:=  1234567890123456789_);
        insert(state,  9223372036854775807_/1_, expect &:=  9223372036854775807_);
        insert(state,  9223372036854775808_/1_, expect &:=  9223372036854775808_);
        insert(state,  9999999999999999999_/1_, expect &:=  9999999999999999999_);
        insert(state, -1000000000000000000_/1_, expect &:= -1000000000000000000_);
        insert(state, -1234567890123456789_/1_, expect &:= -1234567890123456789_);
        insert(state, -9223372036854775808_/1_, expect &:= -9223372036854775808_);
        insert(state, -9223372036854775809_/1_, expect &:= -9223372036854775809_);
        insert(state, -9999999999999999999_/1_, expect &:= -9999999999999999999_);
      end if;
      if precision >= 38 then
        insert(state,   12345678901234567890123456789012345678_/1_,
            expect &:=  12345678901234567890123456789012345678_);
        insert(state,   99999999999999999999999999999999999999_/1_,
            expect &:=  99999999999999999999999999999999999999_);
        insert(state,  -12345678901234567890123456789012345678_/1_,
            expect &:= -12345678901234567890123456789012345678_);
        insert(state,  -99999999999999999999999999999999999999_/1_,
            expect &:= -99999999999999999999999999999999999999_);
      end if;
      if precision >= 65 then
        insert(state,   12345678901234567890123456789012345678901234567890123456789012345_/1_,
            expect &:=  12345678901234567890123456789012345678901234567890123456789012345_);
        insert(state,   99999999999999999999999999999999999999999999999999999999999999999_/1_,
            expect &:=  99999999999999999999999999999999999999999999999999999999999999999_);
        insert(state,  -12345678901234567890123456789012345678901234567890123456789012345_/1_,
            expect &:= -12345678901234567890123456789012345678901234567890123456789012345_);
        insert(state,  -99999999999999999999999999999999999999999999999999999999999999999_/1_,
            expect &:= -99999999999999999999999999999999999999999999999999999999999999999_);
      end if;
      if precision >= 100 then
        insert(state,   1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_/1_,
            expect &:=  1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_);
        insert(state,   9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_/1_,
            expect &:=  9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_);
        insert(state,  -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_/1_,
            expect &:= -1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_);
        insert(state,  -9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_/1_,
            expect &:= -9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_);
      end if;

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        if expect[row] >= bigInteger(integer.first) and
            expect[row] <= bigInteger(integer.last) then
          integerColumn := column(state.statement, 1, integer);
          if integerColumn <> integer(expect[row]) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyIntegerField " <& state.tableName <& ": Row: " <& row <&
                      " Expected " <& expect[row] <& " found integer " <& integerColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyIntegerField " <& state.tableName <& ": Row: " <& row <&
                      " Expected NULL found integer " <& integerColumn);
            end if;
          end if;
        end if;
        bigIntColumn := column(state.statement, 1, bigInteger);
        if bigIntColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyIntegerField " <& state.tableName <& ": Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigInteger " <& bigIntColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyIntegerField " <& state.tableName <& ": Row: " <& row <&
                    " Expected NULL found bigInteger " <& bigIntColumn);
          end if;
        end if;
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> expect[row] / 1_ then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyIntegerField " <& state.tableName <& ": Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigRational " <& bigRatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyIntegerField " <& state.tableName <& ": Row: " <& row <&
                    " Expected NULL found bigRational " <& bigRatColumn);
          end if;
        end if;
        floatAsString := str(float(str(expect[row])));
        if endsWith(floatAsString, ".0") and
            expect[row] = bigInteger(floatAsString[.. length(floatAsString) - 2]) then
          # The expected value is representable as float.
          floatColumn := column(state.statement, 1, float);
          if floatColumn <> float(str(expect[row])) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyIntegerField: Row: " <& row <&
                      " Expected " <& expect[row] <& " found float " <& floatColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyIntegerField: Row: " <& row <&
                    " Expected NULL found float " <& floatColumn);
            end if;
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyIntegerField " <& state.tableName <& ": Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);
  end func;


const proc: testDecimalIntField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("decimalTest", "decimalField", FALSE);
  begin
    if state.details then
      writeln("testDecimalIntField: " <& databaseKind);
    end if;
    testAnyIntegerField(testDb, state, decimalIntType(databaseKind),
                        maxDecimalPrecision(databaseKind), sqlIntLiteralBits(databaseKind));

    if state.okay then
      writeln("Inserting and fetching decimal fields with integers works okay.");
    else
      writeln(" *** Inserting and fetching decimal fields with integers does not work okay.");
    end if;
  end func;


const proc: testNumericIntField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("numericTest", "numericField", FALSE);
  begin
    if state.details then
      writeln("testNumericIntField: " <& databaseKind);
    end if;
    testAnyIntegerField(testDb, state, numericIntType(databaseKind),
                        maxNumericPrecision(databaseKind), sqlIntLiteralBits(databaseKind));

    if state.okay then
      writeln("Inserting and fetching numeric fields with integers works okay.");
    else
      writeln(" *** Inserting and fetching numeric fields with integers does not work okay.");
    end if;
  end func;


const proc: testAnyRationalField (in database: testDb, inout testState: state,
    in string: fieldType, in integer: precision, in integer: literalPrecision,
    in integer: scale) is func
  local
    var bigRational: bigValue is bigRational.value;
    var array bigRational: expect is 0 times 0_/1_;
    var bigRational: bigRatColumn is bigRational.value;
    var float: floatColumn is 0.0;
    var integer: integerColumn is 0;
    var integer: row is 1;
  begin
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & fieldType & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= 0_/1_);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,  expect &:= 0_/1_);

      if scale > 0 then
        # Positive values
        insert(testDb, state, str(1_ / 10_ ** scale), expect &:= 1_ / 10_ ** scale);
        bigValue := pred(10_ ** literalPrecision) / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := 10_ ** pred(literalPrecision) / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := 1234567890_ / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := 123456789012345_ / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := (1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - literalPrecision)) / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);

        # Negative values:
        insert(testDb, state, str(-1_ / 10_ ** scale), expect &:= -1_ / 10_ ** scale);
        bigValue := -pred(10_ ** literalPrecision) / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := -10_ ** pred(literalPrecision) / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := -1234567890_ / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := -123456789012345_ / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
        bigValue := -(1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - literalPrecision)) / 10_ ** scale;
        insert(testDb, state, str(bigValue), expect &:= bigValue);
      else
        # We use integer literals here, because some databases (Firebird)
        # refuse some floating point literals (999999999999999999.0),
        # when the scale is zero and the literalPrecision is at the maximum (18).
        # Positive values
        insert(testDb, state, 10_ ** (-scale) / 1_ digits 0, expect &:= 10_ ** (-scale) / 1_);
        bigValue := pred(10_ ** literalPrecision) * 10_ ** (-scale) / 1_;
        insert(testDb, state, bigValue digits 0, expect &:= bigValue);
        bigValue := (1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - literalPrecision)) * 10_ ** (-scale) / 1_;
        insert(testDb, state, bigValue digits 0, expect &:= bigValue);

        # Negative values:
        insert(testDb, state, -10_ ** (-scale) / 1_ digits 0, expect &:= -10_ ** (-scale) / 1_);
        bigValue := -pred(10_ ** literalPrecision) * 10_ ** (-scale) / 1_;
        insert(testDb, state, bigValue digits 0, expect &:= bigValue);
        bigValue := -(1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - literalPrecision)) * 10_ ** (-scale) / 1_;
        insert(testDb, state, bigValue digits 0, expect &:= bigValue);
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0_/1_, expect &:= 0_/1_);
      if scale > 0 then
        # Positive values
        insert(state, 1_ / 10_ ** scale, expect &:= 1_ / 10_ ** scale);
        bigValue := pred(10_ ** precision) / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := 10_ ** pred(precision) / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := 1234567890_ / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := 123456789012345_ / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := (1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - precision)) / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);

        # Negative values:
        insert(state, -1_ / 10_ ** scale, expect &:= -1_ / 10_ ** scale);
        bigValue := -pred(10_ ** precision) / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := -10_ ** pred(precision) / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := -1234567890_ / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := -123456789012345_ / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := -(1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - precision)) / 10_ ** scale;
        insert(state, bigValue, expect &:= bigValue);
      else
        # Positive values
        insert(state, 10_ ** (-scale) / 1_, expect &:= 10_ ** (-scale) / 1_);
        bigValue := pred(10_ ** precision) * 10_ ** (-scale) / 1_;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := (1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - precision)) * 10_ ** (-scale) / 1_;
        insert(state, bigValue, expect &:= bigValue);

        # Negative values:
        insert(state, -10_ ** (-scale) / 1_, expect &:= -10_ ** (-scale) / 1_);
        bigValue := -pred(10_ ** precision) * 10_ ** (-scale) / 1_;
        insert(state, bigValue, expect &:= bigValue);
        bigValue := -(1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890_ div
                     10_ ** (100 - precision)) * 10_ ** (-scale) / 1_;
        insert(state, bigValue, expect &:= bigValue);
      end if;
      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        bigRatColumn := column(state.statement, 1, bigRational);
        if bigRatColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyRationalField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found bigRational " <& bigRatColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyRationalField: Row: " <& row <&
                    " Expected NULL found bigRational " <& bigRatColumn);
          end if;
        end if;
        if expect[row] = bigRational(str(float(str(expect[row])))) then
          # The expected value is representable as float.
          floatColumn := column(state.statement, 1, float);
          if floatColumn <> float(str(expect[row])) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyRationalField: Row: " <& row <&
                      " Expected " <& expect[row] <& " found float " <& floatColumn);
              # writeln("numerator: " <& expect[row].numerator);
              # writeln("denominator: " <& expect[row].denominator);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyRationalField: Row: " <& row <&
                      " Expected NULL found float " <& floatColumn);
            end if;
          end if;
        end if;
        if scale = 0 and trunc(expect[row]) >= bigInteger(integer.first) and
            trunc(expect[row]) <= bigInteger(integer.last) then
          integerColumn := column(state.statement, 1, integer);
          if integerColumn <> integer(expect[row] digits 0) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyRationalField: Row: " <& row <&
                      " Expected " <& expect[row] digits 0 <& " found integer " <& integerColumn);
            end if;
          end if;
          if row <= 2 and not isNull(state.statement, 1) then
            state.okay := FALSE;
            if state.details then
              writeln(" *** testAnyRationalField: Row: " <& row <&
                    " Expected NULL found integer " <& integerColumn);
            end if;
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testAnyRationalField " <& state.tableName <& ": Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);
  end func;


const proc: testDecimalField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("decimalTest", "decimalField", FALSE);
    var integer: scale is 0;
  begin
    if state.details then
      writeln("testDecimalField: " <& databaseKind);
    end if;
    for scale range minDecimalScale(databaseKind) to maxDecimalScale(databaseKind) do
      testAnyRationalField(testDb, state,
                           decimalType(databaseKind, scale),
                           maxDecimalPrecision(databaseKind),
                           maxDecimalLiteralPrecision(databaseKind), scale);
    end for;

    if state.okay then
      writeln("Inserting and fetching decimal fields works okay.");
    else
      writeln(" *** Inserting and fetching decimal fields does not work okay.");
    end if;
  end func;


const proc: testNumericField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("numericTest", "numericField", FALSE);
    var integer: scale is 0;
  begin
    if state.details then
      writeln("testNumericField: " <& databaseKind);
    end if;
    for scale range minNumericScale(databaseKind) to maxNumericScale(databaseKind) do
      testAnyRationalField(testDb, state,
                           numericType(databaseKind, scale),
                           maxNumericPrecision(databaseKind),
                           maxNumericLiteralPrecision(databaseKind), scale);
    end for;

    if state.okay then
      writeln("Inserting and fetching numeric fields works okay.");
    else
      writeln(" *** Inserting and fetching numeric fields does not work okay.");
    end if;
  end func;


const proc: testChar1AsciiField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("char1AsciiTest", "char1AsciiField", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testChar1AsciiField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= "");
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,  expect &:= "");

      insert(testDb, state, "''",      expect &:= "");
      if nullAllowedInStringLiteral(databaseKind) then
        insert(testDb, state, "'\0;'", expect &:= "\0;");
      end if;
      insert(testDb, state, "'\1;'",   expect &:= "\1;");
      insert(testDb, state, "'\2;'",   expect &:= "\2;");
      insert(testDb, state, "'\3;'",   expect &:= "\3;");
      insert(testDb, state, "'\4;'",   expect &:= "\4;");
      insert(testDb, state, "'\5;'",   expect &:= "\5;");
      insert(testDb, state, "'\6;'",   expect &:= "\6;");
      insert(testDb, state, "'\7;'",   expect &:= "\7;");
      insert(testDb, state, "'\8;'",   expect &:= "\8;");
      insert(testDb, state, "'\9;'",   expect &:= "\9;");
      insert(testDb, state, "'\10;'",  expect &:= "\10;");
      insert(testDb, state, "'\11;'",  expect &:= "\11;");
      insert(testDb, state, "'\12;'",  expect &:= "\12;");
      insert(testDb, state, "'\13;'",  expect &:= "\13;");
      insert(testDb, state, "'\14;'",  expect &:= "\14;");
      insert(testDb, state, "'\15;'",  expect &:= "\15;");
      insert(testDb, state, "'\16;'",  expect &:= "\16;");
      insert(testDb, state, "'\17;'",  expect &:= "\17;");
      insert(testDb, state, "'\18;'",  expect &:= "\18;");
      insert(testDb, state, "'\19;'",  expect &:= "\19;");
      insert(testDb, state, "'\20;'",  expect &:= "\20;");
      insert(testDb, state, "'\21;'",  expect &:= "\21;");
      insert(testDb, state, "'\22;'",  expect &:= "\22;");
      insert(testDb, state, "'\23;'",  expect &:= "\23;");
      insert(testDb, state, "'\24;'",  expect &:= "\24;");
      insert(testDb, state, "'\25;'",  expect &:= "\25;");
      insert(testDb, state, "'\26;'",  expect &:= "\26;");
      insert(testDb, state, "'\27;'",  expect &:= "\27;");
      insert(testDb, state, "'\28;'",  expect &:= "\28;");
      insert(testDb, state, "'\29;'",  expect &:= "\29;");
      insert(testDb, state, "'\30;'",  expect &:= "\30;");
      insert(testDb, state, "'\31;'",  expect &:= "\31;");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(testDb, state, "' '",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(testDb, state, "' '",   expect &:= "");
      end if;
      insert(testDb, state, "'!'",     expect &:= "!");
      insert(testDb, state, "'\"'",    expect &:= "\"");
      insert(testDb, state, "'#'",     expect &:= "#");
      insert(testDb, state, "'$'",     expect &:= "$");
      insert(testDb, state, "'%'",     expect &:= "%");
      insert(testDb, state, "'&'",     expect &:= "&");
      insert(testDb, state, "''''",    expect &:= "'");
      insert(testDb, state, "'('",     expect &:= "(");
      insert(testDb, state, "')'",     expect &:= ")");
      insert(testDb, state, "'*'",     expect &:= "*");
      insert(testDb, state, "'+'",     expect &:= "+");
      insert(testDb, state, "','",     expect &:= ",");
      insert(testDb, state, "'-'",     expect &:= "-");
      insert(testDb, state, "'.'",     expect &:= ".");
      insert(testDb, state, "'/'",     expect &:= "/");
      insert(testDb, state, "'0'",     expect &:= "0");
      insert(testDb, state, "'1'",     expect &:= "1");
      insert(testDb, state, "'9'",     expect &:= "9");
      insert(testDb, state, "':'",     expect &:= ":");
      insert(testDb, state, "';'",     expect &:= ";");
      insert(testDb, state, "'<'",     expect &:= "<");
      insert(testDb, state, "'='",     expect &:= "=");
      insert(testDb, state, "'>'",     expect &:= ">");
      insert(testDb, state, "'?'",     expect &:= "?");
      insert(testDb, state, "'@'",     expect &:= "@");
      insert(testDb, state, "'A'",     expect &:= "A");
      insert(testDb, state, "'Z'",     expect &:= "Z");
      insert(testDb, state, "'['",     expect &:= "[");
      insert(testDb, state, "'\\'",    expect &:= "\\");
      insert(testDb, state, "']'",     expect &:= "]");
      insert(testDb, state, "'^'",     expect &:= "^");
      insert(testDb, state, "'_'",     expect &:= "_");
      insert(testDb, state, "'`'",     expect &:= "`");
      insert(testDb, state, "'a'",     expect &:= "a");
      insert(testDb, state, "'z'",     expect &:= "z");
      insert(testDb, state, "'{'",     expect &:= "{");
      insert(testDb, state, "'|'",     expect &:= "|");
      insert(testDb, state, "'}'",     expect &:= "}");
      insert(testDb, state, "'~'",     expect &:= "~");
      insert(testDb, state, "'\127;'", expect &:= "\127;");

      insert(testDb, state, "0",     expect &:= "0");
      insert(testDb, state, "1",     expect &:= "1");
      insert(testDb, state, "9",     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, "",    expect &:= "");
      if nullAllowedInString(databaseKind) then
        insert(state, "\0;", expect &:= "\0;");
      end if;
      insert(state, "\1;",   expect &:= "\1;");
      insert(state, "\2;",   expect &:= "\2;");
      insert(state, "\3;",   expect &:= "\3;");
      insert(state, "\4;",   expect &:= "\4;");
      insert(state, "\5;",   expect &:= "\5;");
      insert(state, "\6;",   expect &:= "\6;");
      insert(state, "\7;",   expect &:= "\7;");
      insert(state, "\8;",   expect &:= "\8;");
      insert(state, "\9;",   expect &:= "\9;");
      insert(state, "\10;",  expect &:= "\10;");
      insert(state, "\11;",  expect &:= "\11;");
      insert(state, "\12;",  expect &:= "\12;");
      insert(state, "\13;",  expect &:= "\13;");
      insert(state, "\14;",  expect &:= "\14;");
      insert(state, "\15;",  expect &:= "\15;");
      insert(state, "\16;",  expect &:= "\16;");
      insert(state, "\17;",  expect &:= "\17;");
      insert(state, "\18;",  expect &:= "\18;");
      insert(state, "\19;",  expect &:= "\19;");
      insert(state, "\20;",  expect &:= "\20;");
      insert(state, "\21;",  expect &:= "\21;");
      insert(state, "\22;",  expect &:= "\22;");
      insert(state, "\23;",  expect &:= "\23;");
      insert(state, "\24;",  expect &:= "\24;");
      insert(state, "\25;",  expect &:= "\25;");
      insert(state, "\26;",  expect &:= "\26;");
      insert(state, "\27;",  expect &:= "\27;");
      insert(state, "\28;",  expect &:= "\28;");
      insert(state, "\29;",  expect &:= "\29;");
      insert(state, "\30;",  expect &:= "\30;");
      insert(state, "\31;",  expect &:= "\31;");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(state, " ",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(state, " ",   expect &:= "");
      end if;
      insert(state, "!",     expect &:= "!");
      insert(state, "\"",    expect &:= "\"");
      insert(state, "#",     expect &:= "#");
      insert(state, "$",     expect &:= "$");
      insert(state, "%",     expect &:= "%");
      insert(state, "&",     expect &:= "&");
      insert(state, "'",     expect &:= "'");
      insert(state, "(",     expect &:= "(");
      insert(state, ")",     expect &:= ")");
      insert(state, "*",     expect &:= "*");
      insert(state, "+",     expect &:= "+");
      insert(state, ",",     expect &:= ",");
      insert(state, "-",     expect &:= "-");
      insert(state, ".",     expect &:= ".");
      insert(state, "/",     expect &:= "/");
      insert(state, "0",     expect &:= "0");
      insert(state, "1",     expect &:= "1");
      insert(state, "9",     expect &:= "9");
      insert(state, ":",     expect &:= ":");
      insert(state, ";",     expect &:= ";");
      insert(state, "<",     expect &:= "<");
      insert(state, "=",     expect &:= "=");
      insert(state, ">",     expect &:= ">");
      insert(state, "?",     expect &:= "?");
      insert(state, "@",     expect &:= "@");
      insert(state, "A",     expect &:= "A");
      insert(state, "Z",     expect &:= "Z");
      insert(state, "[",     expect &:= "[");
      insert(state, "\\",    expect &:= "\\");
      insert(state, "]",     expect &:= "]");
      insert(state, "^",     expect &:= "^");
      insert(state, "_",     expect &:= "_");
      insert(state, "`",     expect &:= "`");
      insert(state, "a",     expect &:= "a");
      insert(state, "z",     expect &:= "z");
      insert(state, "{",     expect &:= "{");
      insert(state, "|",     expect &:= "|");
      insert(state, "}",     expect &:= "}");
      insert(state, "~",     expect &:= "~");
      insert(state, "\127;", expect &:= "\127;");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0,     expect &:= "0");
      insert(state, 1,     expect &:= "1");
      insert(state, 9,     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0_,    expect &:= "0");
      insert(state, 1_,    expect &:= "1");
      insert(state, 9_,    expect &:= "9");

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1AsciiField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <&
                    " found " <& literal(stringColumn));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1AsciiField: Row: " <& row <&
                    " Expected NULL found " <& stringColumn);
          end if;
        end if;
        if expect[row] <> "" and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1AsciiField: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching char(1) fields with ASCII characters works okay.");
    else
      writeln(" *** Inserting and fetching char(1) fields with ASCII characters does not work okay.");
    end if;
  end func;


const proc: testChar1Latin1Field (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("char1Latin1Test", "char1Latin1Field", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testChar1Latin1Field: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= "");
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,  expect &:= "");

      insert(testDb, state, "''",      expect &:= "");
      if nullAllowedInStringLiteral(databaseKind) then
        insert(testDb, state, "'\0;'", expect &:= "\0;");
      end if;
      insert(testDb, state, "'\1;'",   expect &:= "\1;");
      insert(testDb, state, "'\b'",    expect &:= "\b");
      insert(testDb, state, "'\t'",    expect &:= "\t");
      insert(testDb, state, "'\n'",    expect &:= "\n");
      insert(testDb, state, "'\e'",    expect &:= "\e");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(testDb, state, "' '",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(testDb, state, "' '",   expect &:= "");
      end if;
      insert(testDb, state, "'!'",     expect &:= "!");
      insert(testDb, state, "'\"'",    expect &:= "\"");
      insert(testDb, state, "''''",    expect &:= "'");
      insert(testDb, state, "'0'",     expect &:= "0");
      insert(testDb, state, "'1'",     expect &:= "1");
      insert(testDb, state, "'9'",     expect &:= "9");
      insert(testDb, state, "'?'",     expect &:= "?");
      insert(testDb, state, "'X'",     expect &:= "X");
      insert(testDb, state, "'\\'",    expect &:= "\\");
      insert(testDb, state, "'^'",     expect &:= "^");
      insert(testDb, state, "'`'",     expect &:= "`");
      insert(testDb, state, "'a'",     expect &:= "a");
      insert(testDb, state, "'~'",     expect &:= "~");
      insert(testDb, state, "'\127;'", expect &:= "\127;");
      insert(testDb, state, "'\128;'", expect &:= "\128;");
      insert(testDb, state, "'\129;'", expect &:= "\129;");
      insert(testDb, state, "'\130;'", expect &:= "\130;");
      insert(testDb, state, "'\131;'", expect &:= "\131;");
      insert(testDb, state, "'\132;'", expect &:= "\132;");
      insert(testDb, state, "'\133;'", expect &:= "\133;");
      insert(testDb, state, "'\134;'", expect &:= "\134;");
      insert(testDb, state, "'\135;'", expect &:= "\135;");
      insert(testDb, state, "'\136;'", expect &:= "\136;");
      insert(testDb, state, "'\137;'", expect &:= "\137;");
      insert(testDb, state, "'\138;'", expect &:= "\138;");
      insert(testDb, state, "'\139;'", expect &:= "\139;");
      insert(testDb, state, "'\140;'", expect &:= "\140;");
      insert(testDb, state, "'\141;'", expect &:= "\141;");
      insert(testDb, state, "'\142;'", expect &:= "\142;");
      insert(testDb, state, "'\143;'", expect &:= "\143;");
      insert(testDb, state, "'\144;'", expect &:= "\144;");
      insert(testDb, state, "'\145;'", expect &:= "\145;");
      insert(testDb, state, "'\146;'", expect &:= "\146;");
      insert(testDb, state, "'\147;'", expect &:= "\147;");
      insert(testDb, state, "'\148;'", expect &:= "\148;");
      insert(testDb, state, "'\149;'", expect &:= "\149;");
      insert(testDb, state, "'\150;'", expect &:= "\150;");
      insert(testDb, state, "'\151;'", expect &:= "\151;");
      insert(testDb, state, "'\152;'", expect &:= "\152;");
      insert(testDb, state, "'\153;'", expect &:= "\153;");
      insert(testDb, state, "'\154;'", expect &:= "\154;");
      insert(testDb, state, "'\155;'", expect &:= "\155;");
      insert(testDb, state, "'\156;'", expect &:= "\156;");
      insert(testDb, state, "'\157;'", expect &:= "\157;");
      insert(testDb, state, "'\158;'", expect &:= "\158;");
      insert(testDb, state, "'\159;'", expect &:= "\159;");
      insert(testDb, state, "'\160;'", expect &:= "\160;");
      insert(testDb, state, "'¡'",     expect &:= "¡");
      insert(testDb, state, "'¤'",     expect &:= "¤");
      insert(testDb, state, "'§'",     expect &:= "§");
      insert(testDb, state, "'¬'",     expect &:= "¬");
      insert(testDb, state, "'­'",     expect &:= "­");
      insert(testDb, state, "'µ'",     expect &:= "µ");
      insert(testDb, state, "'¿'",     expect &:= "¿");
      insert(testDb, state, "'Ä'",     expect &:= "Ä");
      insert(testDb, state, "'×'",     expect &:= "×");
      insert(testDb, state, "'ß'",     expect &:= "ß");
      insert(testDb, state, "'ä'",     expect &:= "ä");
      insert(testDb, state, "'÷'",     expect &:= "÷");
      insert(testDb, state, "'ÿ'",     expect &:= "ÿ");

      insert(testDb, state, "0",     expect &:= "0");
      insert(testDb, state, "1",     expect &:= "1");
      insert(testDb, state, "9",     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, "",    expect &:= "");
      if nullAllowedInString(databaseKind) then
        insert(state, "\0;", expect &:= "\0;");
      end if;
      insert(state, "\1;",   expect &:= "\1;");
      insert(state, "\b",    expect &:= "\b");
      insert(state, "\t",    expect &:= "\t");
      insert(state, "\n",    expect &:= "\n");
      insert(state, "\e",    expect &:= "\e");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(state, " ",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(state, " ",   expect &:= "");
      end if;
      insert(state, "!",     expect &:= "!");
      insert(state, "\"",    expect &:= "\"");
      insert(state, "'",     expect &:= "'");
      insert(state, "0",     expect &:= "0");
      insert(state, "1",     expect &:= "1");
      insert(state, "9",     expect &:= "9");
      insert(state, "?",     expect &:= "?");
      insert(state, "X",     expect &:= "X");
      insert(state, "\\",    expect &:= "\\");
      insert(state, "^",     expect &:= "^");
      insert(state, "`",     expect &:= "`");
      insert(state, "a",     expect &:= "a");
      insert(state, "~",     expect &:= "~");
      insert(state, "\127;", expect &:= "\127;");
      insert(state, "\128;", expect &:= "\128;");
      insert(state, "\129;", expect &:= "\129;");
      insert(state, "\130;", expect &:= "\130;");
      insert(state, "\131;", expect &:= "\131;");
      insert(state, "\132;", expect &:= "\132;");
      insert(state, "\133;", expect &:= "\133;");
      insert(state, "\134;", expect &:= "\134;");
      insert(state, "\135;", expect &:= "\135;");
      insert(state, "\136;", expect &:= "\136;");
      insert(state, "\137;", expect &:= "\137;");
      insert(state, "\138;", expect &:= "\138;");
      insert(state, "\139;", expect &:= "\139;");
      insert(state, "\140;", expect &:= "\140;");
      insert(state, "\141;", expect &:= "\141;");
      insert(state, "\142;", expect &:= "\142;");
      insert(state, "\143;", expect &:= "\143;");
      insert(state, "\144;", expect &:= "\144;");
      insert(state, "\145;", expect &:= "\145;");
      insert(state, "\146;", expect &:= "\146;");
      insert(state, "\147;", expect &:= "\147;");
      insert(state, "\148;", expect &:= "\148;");
      insert(state, "\149;", expect &:= "\149;");
      insert(state, "\150;", expect &:= "\150;");
      insert(state, "\151;", expect &:= "\151;");
      insert(state, "\152;", expect &:= "\152;");
      insert(state, "\153;", expect &:= "\153;");
      insert(state, "\154;", expect &:= "\154;");
      insert(state, "\155;", expect &:= "\155;");
      insert(state, "\156;", expect &:= "\156;");
      insert(state, "\157;", expect &:= "\157;");
      insert(state, "\158;", expect &:= "\158;");
      insert(state, "\159;", expect &:= "\159;");
      insert(state, "\160;", expect &:= "\160;");
      insert(state, "¡",     expect &:= "¡");
      insert(state, "¤",     expect &:= "¤");
      insert(state, "§",     expect &:= "§");
      insert(state, "¬",     expect &:= "¬");
      insert(state, "­",     expect &:= "­");
      insert(state, "µ",     expect &:= "µ");
      insert(state, "¿",     expect &:= "¿");
      insert(state, "Ä",     expect &:= "Ä");
      insert(state, "×",     expect &:= "×");
      insert(state, "ß",     expect &:= "ß");
      insert(state, "ä",     expect &:= "ä");
      insert(state, "÷",     expect &:= "÷");
      insert(state, "ÿ",     expect &:= "ÿ");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0,     expect &:= "0");
      insert(state, 1,     expect &:= "1");
      insert(state, 9,     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0_,    expect &:= "0");
      insert(state, 1_,    expect &:= "1");
      insert(state, 9_,    expect &:= "9");

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1Latin1Field: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <&
                    " found " <& literal(stringColumn));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1Latin1Field: Row: " <& row <&
                    " Expected NULL found " <& stringColumn);
          end if;
        end if;
        if expect[row] <> "" and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1Latin1Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching char(1) fields with LATIN-1 characters works okay.");
    else
      writeln(" *** Inserting and fetching char(1) fields with LATIN-1 characters does not work okay.");
    end if;
  end func;


const proc: testCodePageField (in database: testDb, in integer: codePage,
    in dbCategory: databaseKind) is func
  local
    var testState: state is testState("codePageTest", "codePageField", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testCodePageField: Code page: " <& codePage <& " " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= "");
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,  expect &:= "");

      insert(testDb, state, "''",      expect &:= "");
      if nullAllowedInStringLiteral(databaseKind) then
        insert(testDb, state, "'\0;'", expect &:= "\0;");
      end if;
      insert(testDb, state, "'\1;'",   expect &:= "\1;");
      insert(testDb, state, "'\b'",    expect &:= "\b");
      insert(testDb, state, "'\t'",    expect &:= "\t");
      insert(testDb, state, "'\n'",    expect &:= "\n");
      insert(testDb, state, "'\e'",    expect &:= "\e");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(testDb, state, "' '",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(testDb, state, "' '",   expect &:= "");
      end if;
      insert(testDb, state, "'!'",     expect &:= "!");
      insert(testDb, state, "'\"'",    expect &:= "\"");
      insert(testDb, state, "''''",    expect &:= "'");
      insert(testDb, state, "'0'",     expect &:= "0");
      insert(testDb, state, "'1'",     expect &:= "1");
      insert(testDb, state, "'9'",     expect &:= "9");
      insert(testDb, state, "'?'",     expect &:= "?");
      insert(testDb, state, "'X'",     expect &:= "X");
      insert(testDb, state, "'\\'",    expect &:= "\\");
      insert(testDb, state, "'^'",     expect &:= "^");
      insert(testDb, state, "'`'",     expect &:= "`");
      insert(testDb, state, "'a'",     expect &:= "a");
      insert(testDb, state, "'~'",     expect &:= "~");
      insert(testDb, state, "'\127;'", expect &:= "\127;");

      insert(testDb, state, "'€'",     expect &:= "€");
      insert(testDb, state, "'\129;'", expect &:= "\129;");
      insert(testDb, state, "'‚'",     expect &:= "‚");
      # insert(testDb, state, "'\131;'", expect &:= "\131;");
      insert(testDb, state, "'„'",     expect &:= "„");
      insert(testDb, state, "'…'",     expect &:= "…");
      insert(testDb, state, "'†'",     expect &:= "†");
      insert(testDb, state, "'‡'",     expect &:= "‡");
      # insert(testDb, state, "'\136;'", expect &:= "\136;");
      insert(testDb, state, "'‰'",     expect &:= "‰");
      insert(testDb, state, "'Š'",     expect &:= "Š");
      insert(testDb, state, "'‹'",     expect &:= "‹");
      if codePage = 1250 then
        insert(testDb, state, "'Ś'",   expect &:= "Ś");
        insert(testDb, state, "'Ť'",   expect &:= "Ť");
      elsif codePage = 1252 then
        insert(testDb, state, "'Œ'",   expect &:= "Œ");
      end if;
      insert(testDb, state, "'Ž'",     expect &:= "Ž");
      if codePage = 1250 then
        insert(testDb, state, "'Ź'",   expect &:= "Ź");
      end if;
      insert(testDb, state, "'\144;'", expect &:= "\144;");
      insert(testDb, state, "'‘'",     expect &:= "‘");
      insert(testDb, state, "'’'",     expect &:= "’");
      insert(testDb, state, "'“'",     expect &:= "“");
      insert(testDb, state, "'”'",     expect &:= "”");
      insert(testDb, state, "'•'",     expect &:= "•");
      insert(testDb, state, "'–'",     expect &:= "–");
      insert(testDb, state, "'—'",     expect &:= "—");
      # insert(testDb, state, "'\152;'", expect &:= "\152;");
      insert(testDb, state, "'™'",     expect &:= "™");
      insert(testDb, state, "'š'",     expect &:= "š");
      insert(testDb, state, "'›'",     expect &:= "›");
      if codePage = 1250 then
        insert(testDb, state, "'ś'",   expect &:= "ś");
        insert(testDb, state, "'ť'",   expect &:= "ť");
      elsif codePage = 1252 then
        insert(testDb, state, "'œ'",   expect &:= "œ");
      end if;
      insert(testDb, state, "'ž'",     expect &:= "ž");
      if codePage = 1250 then
        insert(testDb, state, "'ź'",   expect &:= "ź");
      elsif codePage = 1252 then
        insert(testDb, state, "'Ÿ'",   expect &:= "Ÿ");
      end if;

      insert(testDb, state, "'\160;'", expect &:= "\160;");
      insert(testDb, state, "'¡'",     expect &:= "¡");
      insert(testDb, state, "'¤'",     expect &:= "¤");
      insert(testDb, state, "'§'",     expect &:= "§");
      insert(testDb, state, "'¬'",     expect &:= "¬");
      insert(testDb, state, "'­'",     expect &:= "­");
      insert(testDb, state, "'µ'",     expect &:= "µ");
      insert(testDb, state, "'¿'",     expect &:= "¿");
      insert(testDb, state, "'Ä'",     expect &:= "Ä");
      insert(testDb, state, "'×'",     expect &:= "×");
      insert(testDb, state, "'ß'",     expect &:= "ß");
      insert(testDb, state, "'ä'",     expect &:= "ä");
      insert(testDb, state, "'÷'",     expect &:= "÷");
      insert(testDb, state, "'ÿ'",     expect &:= "ÿ");

      insert(testDb, state, "0",     expect &:= "0");
      insert(testDb, state, "1",     expect &:= "1");
      insert(testDb, state, "9",     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, "",    expect &:= "");
      if nullAllowedInString(databaseKind) then
        insert(state, "\0;", expect &:= "\0;");
      end if;
      insert(state, "\1;",   expect &:= "\1;");
      insert(state, "\b",    expect &:= "\b");
      insert(state, "\t",    expect &:= "\t");
      insert(state, "\n",    expect &:= "\n");
      insert(state, "\e",    expect &:= "\e");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(state, " ",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(state, " ",   expect &:= "");
      end if;
      insert(state, "!",     expect &:= "!");
      insert(state, "\"",    expect &:= "\"");
      insert(state, "'",     expect &:= "'");
      insert(state, "0",     expect &:= "0");
      insert(state, "1",     expect &:= "1");
      insert(state, "9",     expect &:= "9");
      insert(state, "?",     expect &:= "?");
      insert(state, "X",     expect &:= "X");
      insert(state, "\\",    expect &:= "\\");
      insert(state, "^",     expect &:= "^");
      insert(state, "`",     expect &:= "`");
      insert(state, "a",     expect &:= "a");
      insert(state, "~",     expect &:= "~");
      insert(state, "\127;", expect &:= "\127;");

      insert(state, "€",     expect &:= "€");
      insert(state, "\129;", expect &:= "\129;");
      insert(state, "‚",     expect &:= "‚");
      # insert(state, "\131;", expect &:= "\131;");
      insert(state, "„",     expect &:= "„");
      insert(state, "…",     expect &:= "…");
      insert(state, "†",     expect &:= "†");
      insert(state, "‡",     expect &:= "‡");
      # insert(state, "\136;", expect &:= "\136;");
      insert(state, "‰",     expect &:= "‰");
      insert(state, "Š",     expect &:= "Š");
      insert(state, "‹",     expect &:= "‹");
      if codePage = 1250 then
        insert(state, "Ś",   expect &:= "Ś");
        insert(state, "Ť",   expect &:= "Ť");
      elsif codePage = 1252 then
        insert(state, "Œ",   expect &:= "Œ");
      end if;
      insert(state, "Ž",     expect &:= "Ž");
      if codePage = 1250 then
        insert(state, "Ź",   expect &:= "Ź");
      end if;
      insert(state, "\144;", expect &:= "\144;");
      insert(state, "‘",     expect &:= "‘");
      insert(state, "’",     expect &:= "’");
      insert(state, "“",     expect &:= "“");
      insert(state, "”",     expect &:= "”");
      insert(state, "•",     expect &:= "•");
      insert(state, "–",     expect &:= "–");
      insert(state, "—",     expect &:= "—");
      # insert(state, "\152;", expect &:= "\152;");
      insert(state, "™",     expect &:= "™");
      insert(state, "š",     expect &:= "š");
      insert(state, "›",     expect &:= "›");
      if codePage = 1250 then
        insert(state, "ś",   expect &:= "ś");
        insert(state, "ť",   expect &:= "ť");
      elsif codePage = 1252 then
        insert(state, "œ",   expect &:= "œ");
      end if;
      insert(state, "ž",     expect &:= "ž");
      if codePage = 1250 then
        insert(state, "ź",   expect &:= "ź");
      elsif codePage = 1252 then
        insert(state, "Ÿ",   expect &:= "Ÿ");
      end if;

      insert(state, "\160;", expect &:= "\160;");
      insert(state, "¡",     expect &:= "¡");
      insert(state, "¤",     expect &:= "¤");
      insert(state, "§",     expect &:= "§");
      insert(state, "¬",     expect &:= "¬");
      insert(state, "­",     expect &:= "­");
      insert(state, "µ",     expect &:= "µ");
      insert(state, "¿",     expect &:= "¿");
      insert(state, "Ä",     expect &:= "Ä");
      insert(state, "×",     expect &:= "×");
      insert(state, "ß",     expect &:= "ß");
      insert(state, "ä",     expect &:= "ä");
      insert(state, "÷",     expect &:= "÷");
      insert(state, "ÿ",     expect &:= "ÿ");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0,     expect &:= "0");
      insert(state, 1,     expect &:= "1");
      insert(state, 9,     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0_,    expect &:= "0");
      insert(state, 1_,    expect &:= "1");
      insert(state, 9_,    expect &:= "9");

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCodePageField: Code page: " <& codePage <& " Row: " <& row <&
                    " Expected " <& literal(expect[row]) <&
                    " found " <& literal(stringColumn));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCodePageField: Code page: " <& codePage <& " Row: " <& row <&
                    " Expected NULL found " <& stringColumn);
          end if;
        end if;
        if expect[row] <> "" and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCodePageField: Code page: " <& codePage <& " Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching char(1) fields with code page " <& codePage <& " characters works okay.");
    else
      writeln(" *** Inserting and fetching char(1) fields with code page " <& codePage <& " characters does not work okay.");
    end if;
  end func;


const proc: testChar1Field (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("char1Test", "char1Field", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testChar1Field: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= "");
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,  expect &:= "");

      insert(testDb, state, "''",      expect &:= "");
      if nullAllowedInStringLiteral(databaseKind) then
        insert(testDb, state, "'\0;'", expect &:= "\0;");
      end if;
      insert(testDb, state, "'\1;'",   expect &:= "\1;");
      insert(testDb, state, "'\2;'",   expect &:= "\2;");
      insert(testDb, state, "'\3;'",   expect &:= "\3;");
      insert(testDb, state, "'\4;'",   expect &:= "\4;");
      insert(testDb, state, "'\5;'",   expect &:= "\5;");
      insert(testDb, state, "'\6;'",   expect &:= "\6;");
      insert(testDb, state, "'\7;'",   expect &:= "\7;");
      insert(testDb, state, "'\8;'",   expect &:= "\8;");
      insert(testDb, state, "'\9;'",   expect &:= "\9;");
      insert(testDb, state, "'\10;'",  expect &:= "\10;");
      insert(testDb, state, "'\11;'",  expect &:= "\11;");
      insert(testDb, state, "'\12;'",  expect &:= "\12;");
      insert(testDb, state, "'\13;'",  expect &:= "\13;");
      insert(testDb, state, "'\14;'",  expect &:= "\14;");
      insert(testDb, state, "'\15;'",  expect &:= "\15;");
      insert(testDb, state, "'\16;'",  expect &:= "\16;");
      insert(testDb, state, "'\17;'",  expect &:= "\17;");
      insert(testDb, state, "'\18;'",  expect &:= "\18;");
      insert(testDb, state, "'\19;'",  expect &:= "\19;");
      insert(testDb, state, "'\20;'",  expect &:= "\20;");
      insert(testDb, state, "'\21;'",  expect &:= "\21;");
      insert(testDb, state, "'\22;'",  expect &:= "\22;");
      insert(testDb, state, "'\23;'",  expect &:= "\23;");
      insert(testDb, state, "'\24;'",  expect &:= "\24;");
      insert(testDb, state, "'\25;'",  expect &:= "\25;");
      insert(testDb, state, "'\26;'",  expect &:= "\26;");
      insert(testDb, state, "'\27;'",  expect &:= "\27;");
      insert(testDb, state, "'\28;'",  expect &:= "\28;");
      insert(testDb, state, "'\29;'",  expect &:= "\29;");
      insert(testDb, state, "'\30;'",  expect &:= "\30;");
      insert(testDb, state, "'\31;'",  expect &:= "\31;");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(testDb, state, "' '",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(testDb, state, "' '",   expect &:= "");
      end if;
      insert(testDb, state, "'!'",     expect &:= "!");
      insert(testDb, state, "'\"'",    expect &:= "\"");
      insert(testDb, state, "'#'",     expect &:= "#");
      insert(testDb, state, "'$'",     expect &:= "$");
      insert(testDb, state, "'%'",     expect &:= "%");
      insert(testDb, state, "'&'",     expect &:= "&");
      insert(testDb, state, "''''",    expect &:= "'");
      insert(testDb, state, "'('",     expect &:= "(");
      insert(testDb, state, "')'",     expect &:= ")");
      insert(testDb, state, "'*'",     expect &:= "*");
      insert(testDb, state, "'+'",     expect &:= "+");
      insert(testDb, state, "','",     expect &:= ",");
      insert(testDb, state, "'-'",     expect &:= "-");
      insert(testDb, state, "'.'",     expect &:= ".");
      insert(testDb, state, "'/'",     expect &:= "/");
      insert(testDb, state, "'0'",     expect &:= "0");
      insert(testDb, state, "'1'",     expect &:= "1");
      insert(testDb, state, "'9'",     expect &:= "9");
      insert(testDb, state, "':'",     expect &:= ":");
      insert(testDb, state, "';'",     expect &:= ";");
      insert(testDb, state, "'<'",     expect &:= "<");
      insert(testDb, state, "'='",     expect &:= "=");
      insert(testDb, state, "'>'",     expect &:= ">");
      insert(testDb, state, "'?'",     expect &:= "?");
      insert(testDb, state, "'@'",     expect &:= "@");
      insert(testDb, state, "'A'",     expect &:= "A");
      insert(testDb, state, "'Z'",     expect &:= "Z");
      insert(testDb, state, "'['",     expect &:= "[");
      insert(testDb, state, "'\\'",    expect &:= "\\");
      insert(testDb, state, "']'",     expect &:= "]");
      insert(testDb, state, "'^'",     expect &:= "^");
      insert(testDb, state, "'_'",     expect &:= "_");
      insert(testDb, state, "'`'",     expect &:= "`");
      insert(testDb, state, "'a'",     expect &:= "a");
      insert(testDb, state, "'z'",     expect &:= "z");
      insert(testDb, state, "'{'",     expect &:= "{");
      insert(testDb, state, "'|'",     expect &:= "|");
      insert(testDb, state, "'}'",     expect &:= "}");
      insert(testDb, state, "'~'",     expect &:= "~");
      insert(testDb, state, "'\127;'", expect &:= "\127;");
      if maxChar1FieldCharacter(databaseKind) >= '\255;' then
        insert(testDb, state, "'\160;'", expect &:= "\160;");
        insert(testDb, state, "'¡'",     expect &:= "¡");
        insert(testDb, state, "'¤'",     expect &:= "¤");
        insert(testDb, state, "'§'",     expect &:= "§");
        insert(testDb, state, "'¬'",     expect &:= "¬");
        insert(testDb, state, "'­'",     expect &:= "­");
        insert(testDb, state, "'µ'",     expect &:= "µ");
        insert(testDb, state, "'¿'",     expect &:= "¿");
        insert(testDb, state, "'Ä'",     expect &:= "Ä");
        insert(testDb, state, "'×'",     expect &:= "×");
        insert(testDb, state, "'ß'",     expect &:= "ß");
        insert(testDb, state, "'ä'",     expect &:= "ä");
        insert(testDb, state, "'÷'",     expect &:= "÷");
        insert(testDb, state, "'ÿ'",     expect &:= "ÿ");
      end if;
      if maxChar1FieldCharacter(databaseKind) >= '\8888;' then # Code page 1252
        insert(testDb, state, "'Œ'",        expect &:= "Œ");
        insert(testDb, state, "'Š'",        expect &:= "Š");
        insert(testDb, state, "'ƒ'",        expect &:= "ƒ");
        insert(testDb, state, "'†'",        expect &:= "†");
        insert(testDb, state, "'•'",        expect &:= "•");
        insert(testDb, state, "'‰'",        expect &:= "‰");
        insert(testDb, state, "'€'",        expect &:= "€");
        insert(testDb, state, "'™'",        expect &:= "™");
      end if;
      if maxChar1FieldCharacter(databaseKind) >= '\65535;' then
        insert(testDb, state, "'Ā'",        expect &:= "Ā");
        insert(testDb, state, "'\65535;'",  expect &:= "\65535;");
      end if;
      if maxChar1FieldCharacter(databaseKind) >= '\16#10ffff;' then
        insert(testDb, state, "'\65536;'",  expect &:= "\65536;");
        insert(testDb, state, "'\16#10ffff;'",  expect &:= "\16#10ffff;");
      end if;

      insert(testDb, state, "0",     expect &:= "0");
      insert(testDb, state, "1",     expect &:= "1");
      insert(testDb, state, "9",     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, "",    expect &:= "");
      if nullAllowedInString(databaseKind) then
        insert(state, "\0;", expect &:= "\0;");
      end if;
      insert(state, "\1;",   expect &:= "\1;");
      insert(state, "\2;",   expect &:= "\2;");
      insert(state, "\3;",   expect &:= "\3;");
      insert(state, "\4;",   expect &:= "\4;");
      insert(state, "\5;",   expect &:= "\5;");
      insert(state, "\6;",   expect &:= "\6;");
      insert(state, "\7;",   expect &:= "\7;");
      insert(state, "\8;",   expect &:= "\8;");
      insert(state, "\9;",   expect &:= "\9;");
      insert(state, "\10;",  expect &:= "\10;");
      insert(state, "\11;",  expect &:= "\11;");
      insert(state, "\12;",  expect &:= "\12;");
      insert(state, "\13;",  expect &:= "\13;");
      insert(state, "\14;",  expect &:= "\14;");
      insert(state, "\15;",  expect &:= "\15;");
      insert(state, "\16;",  expect &:= "\16;");
      insert(state, "\17;",  expect &:= "\17;");
      insert(state, "\18;",  expect &:= "\18;");
      insert(state, "\19;",  expect &:= "\19;");
      insert(state, "\20;",  expect &:= "\20;");
      insert(state, "\21;",  expect &:= "\21;");
      insert(state, "\22;",  expect &:= "\22;");
      insert(state, "\23;",  expect &:= "\23;");
      insert(state, "\24;",  expect &:= "\24;");
      insert(state, "\25;",  expect &:= "\25;");
      insert(state, "\26;",  expect &:= "\26;");
      insert(state, "\27;",  expect &:= "\27;");
      insert(state, "\28;",  expect &:= "\28;");
      insert(state, "\29;",  expect &:= "\29;");
      insert(state, "\30;",  expect &:= "\30;");
      insert(state, "\31;",  expect &:= "\31;");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(state, " ",   expect &:= " ");
      else
        # Reading a char field removes trailing spaces.
        insert(state, " ",   expect &:= "");
      end if;
      insert(state, "!",     expect &:= "!");
      insert(state, "\"",    expect &:= "\"");
      insert(state, "#",     expect &:= "#");
      insert(state, "$",     expect &:= "$");
      insert(state, "%",     expect &:= "%");
      insert(state, "&",     expect &:= "&");
      insert(state, "'",     expect &:= "'");
      insert(state, "(",     expect &:= "(");
      insert(state, ")",     expect &:= ")");
      insert(state, "*",     expect &:= "*");
      insert(state, "+",     expect &:= "+");
      insert(state, ",",     expect &:= ",");
      insert(state, "-",     expect &:= "-");
      insert(state, ".",     expect &:= ".");
      insert(state, "/",     expect &:= "/");
      insert(state, "0",     expect &:= "0");
      insert(state, "1",     expect &:= "1");
      insert(state, "9",     expect &:= "9");
      insert(state, ":",     expect &:= ":");
      insert(state, ";",     expect &:= ";");
      insert(state, "<",     expect &:= "<");
      insert(state, "=",     expect &:= "=");
      insert(state, ">",     expect &:= ">");
      insert(state, "?",     expect &:= "?");
      insert(state, "@",     expect &:= "@");
      insert(state, "A",     expect &:= "A");
      insert(state, "Z",     expect &:= "Z");
      insert(state, "[",     expect &:= "[");
      insert(state, "\\",    expect &:= "\\");
      insert(state, "]",     expect &:= "]");
      insert(state, "^",     expect &:= "^");
      insert(state, "_",     expect &:= "_");
      insert(state, "`",     expect &:= "`");
      insert(state, "a",     expect &:= "a");
      insert(state, "z",     expect &:= "z");
      insert(state, "{",     expect &:= "{");
      insert(state, "|",     expect &:= "|");
      insert(state, "}",     expect &:= "}");
      insert(state, "~",     expect &:= "~");
      insert(state, "\127;", expect &:= "\127;");
      if maxChar1FieldCharacter(databaseKind) >= '\255;' then
        insert(state, "\160;", expect &:= "\160;");
        insert(state, "¡",     expect &:= "¡");
        insert(state, "¤",     expect &:= "¤");
        insert(state, "§",     expect &:= "§");
        insert(state, "¬",     expect &:= "¬");
        insert(state, "­",     expect &:= "­");
        insert(state, "µ",     expect &:= "µ");
        insert(state, "¿",     expect &:= "¿");
        insert(state, "Ä",     expect &:= "Ä");
        insert(state, "×",     expect &:= "×");
        insert(state, "ß",     expect &:= "ß");
        insert(state, "ä",     expect &:= "ä");
        insert(state, "÷",     expect &:= "÷");
        insert(state, "ÿ",     expect &:= "ÿ");
      end if;
      if maxChar1FieldCharacter(databaseKind) >= '\8888;' then # Code page 1252
        insert(state, "Œ",        expect &:= "Œ");
        insert(state, "Š",        expect &:= "Š");
        insert(state, "ƒ",        expect &:= "ƒ");
        insert(state, "†",        expect &:= "†");
        insert(state, "•",        expect &:= "•");
        insert(state, "‰",        expect &:= "‰");
        insert(state, "€",        expect &:= "€");
        insert(state, "™",        expect &:= "™");
      end if;
      if maxChar1FieldCharacter(databaseKind) >= '\65535;' then
        insert(state, "Ā",        expect &:= "Ā");
        insert(state, "\65535;",  expect &:= "\65535;");
      end if;
      if maxChar1FieldCharacter(databaseKind) >= '\16#10ffff;' then
        insert(state, "\65536;",      expect &:= "\65536;");
        insert(state, "\16#10ffff;",  expect &:= "\16#10ffff;");
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0,     expect &:= "0");
      insert(state, 1,     expect &:= "1");
      insert(state, 9,     expect &:= "9");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, 0_,    expect &:= "0");
      insert(state, 1_,    expect &:= "1");
      insert(state, 9_,    expect &:= "9");

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1Field: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <&
                    " found " <& literal(stringColumn));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1Field: Row: " <& row <&
                    " Expected NULL found " <& stringColumn);
          end if;
        end if;
        if expect[row] <> "" and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testChar1Field: Row: " <& row <&
                    " Expected " <& expect[row] <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching char(1) fields works okay.");
    else
      writeln(" *** Inserting and fetching char(1) fields does not work okay.");
    end if;
  end func;


const proc: testCharField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("charTest", "charField", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testCharField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR(32))");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= "");
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,         expect &:= "");

      insert(testDb, state, "''",           expect &:= "");
      insert(testDb, state, "'X'",          expect &:= "X");
      insert(testDb, state, "'Ab2'",        expect &:= "Ab2");
      insert(testDb, state, "'abcdefghij'", expect &:= "abcdefghij");
      insert(testDb, state, "'ÄäÖöÜüß'",    expect &:= "ÄäÖöÜüß");
      insert(testDb, state, "'€µ¹²³¼½«»¬'", expect &:= "€µ¹²³¼½«»¬");
      # Chars that are defined with different ordinal in code page 1252:
      insert(testDb, state, "'€‚ƒ„…†‡ˆ‰'",  expect &:= "€‚ƒ„…†‡ˆ‰");
      insert(testDb, state, "'Š‹ŒŽ‘’“”•'",  expect &:= "Š‹ŒŽ‘’“”•");
      insert(testDb, state, "'–—˜™š›œžŸ'",  expect &:= "–—˜™š›œžŸ");
      insert(testDb, state, "'" & "x" mult 32 & "'",  expect &:= "x" mult 32);
      insert(testDb, state, "'A B'",        expect &:= "A B");
      if nullAllowedInStringLiteral(databaseKind) then
        insert(testDb, state, "'A\0;B'",    expect &:= "A\0;B");
      end if;
      insert(testDb, state, "'\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;'",
                 expect &:= "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;");
      insert(testDb, state, "' !\"#$%&''()*+,-./'",         expect &:= " !\"#$%&'()*+,-./");
      insert(testDb, state, "'0123456789:;<=>?@'",          expect &:= "0123456789:;<=>?@");
      insert(testDb, state, "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'", expect &:= "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      insert(testDb, state, "'[\\]^_`{|}~\127;'",           expect &:= "[\\]^_`{|}~\127;");
      insert(testDb, state, "'abcdefghijklmnopqrstuvwxyz'", expect &:= "abcdefghijklmnopqrstuvwxyz");
      insert(testDb, state, "'\160;¡¢£¤¥¦§¨©ª«¬­®¯'",       expect &:= "\160;¡¢£¤¥¦§¨©ª«¬­®¯");
      insert(testDb, state, "'°±²³´µ¶·¸¹º»¼½¾¿'",           expect &:= "°±²³´µ¶·¸¹º»¼½¾¿");
      insert(testDb, state, "'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ'",           expect &:= "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ");
      insert(testDb, state, "'ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß'",           expect &:= "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß");
      insert(testDb, state, "'àáâãäåæçèéêëìíîï'",           expect &:= "àáâãäåæçèéêëìíîï");
      insert(testDb, state, "'ðñòóôõö÷øùúûüýþÿ'",           expect &:= "ðñòóôõö÷øùúûüýþÿ");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(testDb, state, "'a '",       expect &:= "a ");
        # insert(testDb, state, "'" & "b" mult 3999 & " '", expect &:= "b" mult 3999 & " ");
      else
        # Reading a char field removes trailing spaces.
        insert(testDb, state, "'a '",       expect &:= "a");
        # insert(testDb, state, "'" & "b" mult 3999 & " '", expect &:= "b" mult 3999);
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, "",           expect &:= "");
      insert(state, "X",          expect &:= "X");
      insert(state, "Ab2",        expect &:= "Ab2");
      insert(state, "abcdefghij", expect &:= "abcdefghij");
      insert(state, "ÄäÖöÜüß",    expect &:= "ÄäÖöÜüß");
      insert(state, "€µ¹²³¼½«»¬", expect &:= "€µ¹²³¼½«»¬");
      # Chars that are defined with different ordinal in code page 1252:
      insert(state, "€‚ƒ„…†‡ˆ‰",  expect &:= "€‚ƒ„…†‡ˆ‰");
      insert(state, "Š‹ŒŽ‘’“”•",  expect &:= "Š‹ŒŽ‘’“”•");
      insert(state, "–—˜™š›œžŸ",  expect &:= "–—˜™š›œžŸ");
      insert(state, "x" mult 32,  expect &:= "x" mult 32);
      insert(state, "A B",        expect &:= "A B");
      if nullAllowedInString(databaseKind) then
        insert(state, "A\0;B",    expect &:= "A\0;B");
      end if;
      insert(state, "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                    \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                    \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;",
         expect &:= "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                    \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                    \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;");
      insert(state, " !\"#$%&'()*+,-./",          expect &:= " !\"#$%&'()*+,-./");
      insert(state, "0123456789:;<=>?@",          expect &:= "0123456789:;<=>?@");
      insert(state, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", expect &:= "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      insert(state, "[\\]^_`{|}~\127;",           expect &:= "[\\]^_`{|}~\127;");
      insert(state, "abcdefghijklmnopqrstuvwxyz", expect &:= "abcdefghijklmnopqrstuvwxyz");
      insert(state, "\160;¡¢£¤¥¦§¨©ª«¬­®¯",       expect &:= "\160;¡¢£¤¥¦§¨©ª«¬­®¯");
      insert(state, "°±²³´µ¶·¸¹º»¼½¾¿",           expect &:= "°±²³´µ¶·¸¹º»¼½¾¿");
      insert(state, "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ",           expect &:= "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ");
      insert(state, "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß",           expect &:= "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß");
      insert(state, "àáâãäåæçèéêëìíîï",           expect &:= "àáâãäåæçèéêëìíîï");
      insert(state, "ðñòóôõö÷øùúûüýþÿ",           expect &:= "ðñòóôõö÷øùúûüýþÿ");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(state, "a ",         expect &:= "a ");
        # insert(state, "b" mult 3999 & " ",      expect &:= "b" mult 3999 & " ");
      else
        # Reading a char field removes trailing spaces.
        insert(state, "a ",         expect &:= "a");
        # insert(state, "b" mult 3999 & " ",      expect &:= "b" mult 3999);
      end if;

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,          0,   expect &:= "0");
      insert(state,          1,   expect &:= "1");
      insert(state, 1234567890,   expect &:= "1234567890");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,          0_,  expect &:= "0");
      insert(state,          1_,  expect &:= "1");
      insert(state, 1234567890_,  expect &:= "1234567890");

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCharField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <&
                    " found string " <& literal(stringColumn));
            writeln("Expected length: " <& length(expect[row]));
            writeln("Length found:    " <& length(stringColumn));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCharField: Row: " <& row <&
                    " Expected NULL found string " <& stringColumn);
          end if;
        end if;
        if expect[row] <> "" and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCharField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching char fields works okay.");
    else
      writeln(" *** Inserting and fetching char fields does not work okay.");
    end if;
  end func;


const proc: testCharField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("charTest", "charField", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testCharField2: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " CHAR(32))");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= "");
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,         expect &:= "");

      insert(testDb, state, "\"\"",           expect &:= "");
      insert(testDb, state, "\"X\"",          expect &:= "X");
      insert(testDb, state, "\"Ab2\"",        expect &:= "Ab2");
      insert(testDb, state, "\"abcdefghij\"", expect &:= "abcdefghij");
      insert(testDb, state, "\"ÄäÖöÜüß\"",    expect &:= "ÄäÖöÜüß");
      insert(testDb, state, "\"€µ¹²³¼½«»¬\"", expect &:= "€µ¹²³¼½«»¬");
      # Chars that are defined with different ordinal in code page 1252:
      insert(testDb, state, "\"€‚ƒ„…†‡ˆ‰\"",  expect &:= "€‚ƒ„…†‡ˆ‰");
      insert(testDb, state, "\"Š‹ŒŽ‘’“”•\"",  expect &:= "Š‹ŒŽ‘’“”•");
      insert(testDb, state, "\"–—˜™š›œžŸ\"",  expect &:= "–—˜™š›œžŸ");
      insert(testDb, state, "\"" & "x" mult 32 & "\"",  expect &:= "x" mult 32);
      insert(testDb, state, "\"A B\"",        expect &:= "A B");
      if nullAllowedInStringLiteral(databaseKind) then
        insert(testDb, state, "\"A\0;B\"",    expect &:= "A\0;B");
      end if;
      insert(testDb, state, "\"\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;\"",
                 expect &:= "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;");
      insert(testDb, state, "\" !\"\"#$%&'()*+,-./\"",         expect &:= " !\"#$%&'()*+,-./");
      insert(testDb, state, "\"0123456789:;<=>?@\"",          expect &:= "0123456789:;<=>?@");
      insert(testDb, state, "\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"", expect &:= "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      insert(testDb, state, "\"[\\]^_`{|}~\127;\"",           expect &:= "[\\]^_`{|}~\127;");
      insert(testDb, state, "\"abcdefghijklmnopqrstuvwxyz\"", expect &:= "abcdefghijklmnopqrstuvwxyz");
      insert(testDb, state, "\"\160;¡¢£¤¥¦§¨©ª«¬­®¯\"",       expect &:= "\160;¡¢£¤¥¦§¨©ª«¬­®¯");
      insert(testDb, state, "\"°±²³´µ¶·¸¹º»¼½¾¿\"",           expect &:= "°±²³´µ¶·¸¹º»¼½¾¿");
      insert(testDb, state, "\"ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ\"",           expect &:= "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ");
      insert(testDb, state, "\"ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß\"",           expect &:= "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß");
      insert(testDb, state, "\"àáâãäåæçèéêëìíîï\"",           expect &:= "àáâãäåæçèéêëìíîï");
      insert(testDb, state, "\"ðñòóôõö÷øùúûüýþÿ\"",           expect &:= "ðñòóôõö÷øùúûüýþÿ");
      if charFieldPreservesTrailingSpaces(databaseKind) then
        # Reading a char field preserves trailing spaces.
        insert(testDb, state, "\"a \"",       expect &:= "a ");
        # insert(testDb, state, "\"" & "b" mult 3999 & " \"", expect &:= "b" mult 3999 & " ");
      else
        # Reading a char field removes trailing spaces.
        insert(testDb, state, "\"a \"",       expect &:= "a");
        # insert(testDb, state, "\"" & "b" mult 3999 & " \"", expect &:= "b" mult 3999);
      end if;

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCharField2: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <&
                    " found string " <& literal(stringColumn));
            writeln("Expected length: " <& length(expect[row]));
            writeln("Length found:    " <& length(stringColumn));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCharField2: Row: " <& row <&
                    " Expected NULL found string " <& stringColumn);
          end if;
        end if;
        if expect[row] <> "" and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testCharField2: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching char fields works okay.");
    else
      writeln(" *** Inserting and fetching char fields does not work okay.");
    end if;
  end func;


const proc: testVarcharField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("varcharTest", "varcharField", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testVarcharField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & varcharType(databaseKind) & "(32))");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= "");
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,         expect &:= "");

      insert(testDb, state, "''",           expect &:= "");
      insert(testDb, state, "'X'",          expect &:= "X");
      insert(testDb, state, "'Ab2'",        expect &:= "Ab2");
      insert(testDb, state, "'abcdefghij'", expect &:= "abcdefghij");
      insert(testDb, state, "'ÄäÖöÜüß'",    expect &:= "ÄäÖöÜüß");
      insert(testDb, state, "'€µ¹²³¼½«»¬'", expect &:= "€µ¹²³¼½«»¬");
      # Chars that are defined with different ordinal in code page 1252:
      insert(testDb, state, "'€‚ƒ„…†‡ˆ‰'",  expect &:= "€‚ƒ„…†‡ˆ‰");
      insert(testDb, state, "'Š‹ŒŽ‘’“”•'",  expect &:= "Š‹ŒŽ‘’“”•");
      insert(testDb, state, "'–—˜™š›œžŸ'",  expect &:= "–—˜™š›œžŸ");
      insert(testDb, state, "'" & "x" mult 32 & "'",  expect &:= "x" mult 32);
      insert(testDb, state, "'A B'",        expect &:= "A B");
      if nullAllowedInStringLiteral(databaseKind) then
        insert(testDb, state, "'A\0;B'",    expect &:= "A\0;B");
      end if;
      insert(testDb, state, "'\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;'",
                 expect &:= "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;");
      insert(testDb, state, "' !\"#$%&''()*+,-./'",         expect &:= " !\"#$%&'()*+,-./");
      insert(testDb, state, "'0123456789:;<=>?@'",          expect &:= "0123456789:;<=>?@");
      insert(testDb, state, "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'", expect &:= "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      insert(testDb, state, "'[\\]^_`{|}~\127;'",           expect &:= "[\\]^_`{|}~\127;");
      insert(testDb, state, "'abcdefghijklmnopqrstuvwxyz'", expect &:= "abcdefghijklmnopqrstuvwxyz");
      insert(testDb, state, "'\160;¡¢£¤¥¦§¨©ª«¬­®¯'",       expect &:= "\160;¡¢£¤¥¦§¨©ª«¬­®¯");
      insert(testDb, state, "'°±²³´µ¶·¸¹º»¼½¾¿'",           expect &:= "°±²³´µ¶·¸¹º»¼½¾¿");
      insert(testDb, state, "'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ'",           expect &:= "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ");
      insert(testDb, state, "'ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß'",           expect &:= "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß");
      insert(testDb, state, "'àáâãäåæçèéêëìíîï'",           expect &:= "àáâãäåæçèéêëìíîï");
      insert(testDb, state, "'ðñòóôõö÷øùúûüýþÿ'",           expect &:= "ðñòóôõö÷øùúûüýþÿ");
      # Reading a varchar field preserves trailing spaces.
      insert(testDb, state, "'a '",         expect &:= "a ");
      # insert(testDb, state, "'" & "b" mult 3999 & " '",     expect &:= "b" mult 3999 & " ");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, "",           expect &:= "");
      insert(state, "X",          expect &:= "X");
      insert(state, "Ab2",        expect &:= "Ab2");
      insert(state, "abcdefghij", expect &:= "abcdefghij");
      insert(state, "ÄäÖöÜüß",    expect &:= "ÄäÖöÜüß");
      insert(state, "€µ¹²³¼½«»¬", expect &:= "€µ¹²³¼½«»¬");
      # Chars that are defined with different ordinal in code page 1252:
      insert(state, "€‚ƒ„…†‡ˆ‰",  expect &:= "€‚ƒ„…†‡ˆ‰");
      insert(state, "Š‹ŒŽ‘’“”•",  expect &:= "Š‹ŒŽ‘’“”•");
      insert(state, "–—˜™š›œžŸ",  expect &:= "–—˜™š›œžŸ");
      insert(state, "x" mult 32,  expect &:= "x" mult 32);
      insert(state, "A B",        expect &:= "A B");
      if nullAllowedInString(databaseKind) then
        insert(state, "A\0;B",    expect &:= "A\0;B");
      end if;
      insert(state, "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                    \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                    \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;",
         expect &:= "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                    \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                    \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;");
      insert(state, " !\"#$%&'()*+,-./",          expect &:= " !\"#$%&'()*+,-./");
      insert(state, "0123456789:;<=>?@",          expect &:= "0123456789:;<=>?@");
      insert(state, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", expect &:= "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      insert(state, "[\\]^_`{|}~\127;",           expect &:= "[\\]^_`{|}~\127;");
      insert(state, "abcdefghijklmnopqrstuvwxyz", expect &:= "abcdefghijklmnopqrstuvwxyz");
      insert(state, "\160;¡¢£¤¥¦§¨©ª«¬­®¯",       expect &:= "\160;¡¢£¤¥¦§¨©ª«¬­®¯");
      insert(state, "°±²³´µ¶·¸¹º»¼½¾¿",           expect &:= "°±²³´µ¶·¸¹º»¼½¾¿");
      insert(state, "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ",           expect &:= "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ");
      insert(state, "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß",           expect &:= "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß");
      insert(state, "àáâãäåæçèéêëìíîï",           expect &:= "àáâãäåæçèéêëìíîï");
      insert(state, "ðñòóôõö÷øùúûüýþÿ",           expect &:= "ðñòóôõö÷øùúûüýþÿ");
      # Reading a varchar field preserves trailing spaces.
      insert(state, "a ",         expect &:= "a ");
      # insert(state, "b" mult 3999 & " ",          expect &:= "b" mult 3999 & " ");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,          0,   expect &:= "0");
      insert(state,          1,   expect &:= "1");
      insert(state, 1234567890,   expect &:= "1234567890");

      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state,          0_,  expect &:= "0");
      insert(state,          1_,  expect &:= "1");
      insert(state, 1234567890_,  expect &:= "1234567890");
#      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
#                           " (" & state.fieldName & ") VALUES (N'" <&
#                           "\128;\129;\130;\131;\132;\133;\134;\135;\
#                           \\136;\137;\138;\139;\140;\141;\142;\143;\144;\145;\146;\147;\148;\
#                           \\149;\150;\151;\152;\153;\154;\155;\156;\157;\158;\159;" & "')");
#      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
#                           " (" & state.fieldName & ") VALUES (\
#                           \CHAR(128) + CHAR(129) + CHAR(130) + CHAR(131) + CHAR(132) + CHAR(133) + CHAR(134) + CHAR(135) + CHAR(136) + CHAR(137) + \
#                           \CHAR(138) + CHAR(139) + CHAR(140) + CHAR(141) + CHAR(142) + CHAR(143) + CHAR(144) + CHAR(145) + CHAR(146) + CHAR(147) + \
#                           \CHAR(148) + CHAR(149) + CHAR(150) + CHAR(151) + CHAR(152) + CHAR(153) + CHAR(154) + CHAR(155) + CHAR(156) + CHAR(157) + \
#                           \CHAR(158) + CHAR(159))");
#      execute(state.statement);
#      expect &:= "\128;\129;\130;\131;\132;\133;\134;\135;\
#                 \\136;\137;\138;\139;\140;\141;\142;\143;\144;\145;\146;\147;\148;\
#                 \\149;\150;\151;\152;\153;\154;\155;\156;\157;\158;\159;";
      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testVarcharField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <&
                    " found string " <& literal(stringColumn));
            writeln("Expected length: " <& length(expect[row]));
            writeln("Length found:    " <& length(stringColumn));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testVarcharField: Row: " <& row <&
                    " Expected NULL found string " <& stringColumn);
          end if;
        end if;
        if expect[row] <> "" and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testVarcharField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching varchar fields works okay.");
    else
      writeln(" *** Inserting and fetching varchar fields does not work okay.");
    end if;
  end func;


const proc: testBlobField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("blobTest", "blobField", FALSE);
    var array bstring: expect is 0 times bstring("");
    var bstring: bstringColumn is bstring("");
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testBlobField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                         " (" & state.fieldName & " " & blobType(databaseKind) & ")");
      execute(state.statement);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                           " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,                  expect &:= bstring(""));
      insert(state, bstring(""),           expect &:= bstring(""));
      insert(state, bstring("X"),          expect &:= bstring("X"));
      insert(state, bstring("!~"),         expect &:= bstring("!~"));
      insert(state, bstring("Ab2"),        expect &:= bstring("Ab2"));
      insert(state, bstring("abcdefghij"), expect &:= bstring("abcdefghij"));
      insert(state, bstring("ÄäÖöÜüß"),    expect &:= bstring("ÄäÖöÜüß"));
      insert(state, bstring("µ¹²³¼½«»¬"),  expect &:= bstring("µ¹²³¼½«»¬"));
      insert(state, bstring("x" mult 65535), expect &:= bstring("x" mult 65535));
      insert(state, bstring("y" mult 1000000), expect &:= bstring("y" mult 1000000));
      # BStrings that contain all possible byte values (from 0 to 255):
      insert(state, bstring("\0;\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;\127;"),
         expect &:= bstring("\0;\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                            \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                            \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;\127;"));
      insert(state, bstring("\128;\129;\130;\131;\132;\133;\134;\135;\
                            \\136;\137;\138;\139;\140;\141;\142;\143;\144;\145;\146;\147;\148;\
                            \\149;\150;\151;\152;\153;\154;\155;\156;\157;\158;\159;\160;"),
         expect &:= bstring("\128;\129;\130;\131;\132;\133;\134;\135;\
                            \\136;\137;\138;\139;\140;\141;\142;\143;\144;\145;\146;\147;\148;\
                            \\149;\150;\151;\152;\153;\154;\155;\156;\157;\158;\159;\160;"));
      insert(state, bstring(" !\"#$%&'()*+,-./"),          expect &:= bstring(" !\"#$%&'()*+,-./"));
      insert(state, bstring("0123456789:;<=>?@"),          expect &:= bstring("0123456789:;<=>?@"));
      insert(state, bstring("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), expect &:= bstring("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
      insert(state, bstring("[\\]^_`{|}~\127;"),           expect &:= bstring("[\\]^_`{|}~\127;"));
      insert(state, bstring("abcdefghijklmnopqrstuvwxyz"), expect &:= bstring("abcdefghijklmnopqrstuvwxyz"));
      insert(state, bstring("\160;¡¢£¤¥¦§¨©ª«¬­®¯"),       expect &:= bstring("\160;¡¢£¤¥¦§¨©ª«¬­®¯"));
      insert(state, bstring("°±²³´µ¶·¸¹º»¼½¾¿"),           expect &:= bstring("°±²³´µ¶·¸¹º»¼½¾¿"));
      insert(state, bstring("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ"),           expect &:= bstring("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ"));
      insert(state, bstring("ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß"),           expect &:= bstring("ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß"));
      insert(state, bstring("àáâãäåæçèéêëìíîï"),           expect &:= bstring("àáâãäåæçèéêëìíîï"));
      insert(state, bstring("ðñòóôõö÷øùúûüýþÿ"),           expect &:= bstring("ðñòóôõö÷øùúûüýþÿ"));
      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        bstringColumn := column(state.statement, 1, bstring);
        if bstringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            if length(expect[row]) <= 1000 and length(bstringColumn) <= 1000 then
              writeln(" *** testBlobField: Row: " <& row <&
                      " Expected " <& literal(str(expect[row])) <&
                      " found bstring " <& literal(str(bstringColumn)));
            else
              writeln(" *** testBlobField: Row: " <& row <&
                      " Expected length: " <& length(expect[row]) <&
                      " bstring length found: " <& length(bstringColumn));
            end if;
          end if;
        end if;
        if row = 1 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBlobField: Row: " <& row <&
                    " Expected NULL found " <& bstringColumn);
          end if;
        end if;
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> string(expect[row]) then
          state.okay := FALSE;
          if state.details then
            if length(expect[row]) <= 1000 and length(stringColumn) <= 1000 then
              writeln(" *** testBlobField: Row: " <& row <&
                      " Expected " <& literal(str(expect[row])) <&
                      " found string " <& literal(str(stringColumn)));
            else
              writeln(" *** testBlobField: Row: " <& row <&
                      " Expected length: " <& length(expect[row]) <&
                      " string length found: " <& length(stringColumn));
            end if;
          end if;
        end if;
        if row = 1 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBlobField: Row: " <& row <&
                    " Expected NULL found " <& stringColumn);
          end if;
        end if;
        if length(expect[row]) <> 0 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testBlobField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching blob fields works okay.");
    else
      writeln(" *** Inserting and fetching blob fields does not work okay.");
    end if;
  end func;


const proc: testClobField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("clobTest", "clobField", FALSE);
    var array string: expect is 0 times "";
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    if state.details then
      writeln("testClobField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                         " (" & state.fieldName & " " & clobType(databaseKind) & ")");
      execute(state.statement);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                           " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,         expect &:= "");
      insert(state, "",           expect &:= "");
      insert(state, "X",          expect &:= "X");
      insert(state, "Ab2",        expect &:= "Ab2");
      insert(state, "abcdefghij", expect &:= "abcdefghij");
      insert(state, "ÄäÖöÜüß",    expect &:= "ÄäÖöÜüß");
      insert(state, "€µ¹²³¼½«»¬", expect &:= "€µ¹²³¼½«»¬");
      # Chars that are defined with different ordinal in code page 1252:
      insert(state, "€‚ƒ„…†‡ˆ‰",  expect &:= "€‚ƒ„…†‡ˆ‰");
      insert(state, "Š‹ŒŽ‘’“”•",  expect &:= "Š‹ŒŽ‘’“”•");
      insert(state, "–—˜™š›œžŸ",  expect &:= "–—˜™š›œžŸ");
      insert(state, "x" mult 32,  expect &:= "x" mult 32);
      insert(state, "A B",        expect &:= "A B");
      insert(state, "x" mult 65535,   expect &:= "x" mult 65535);
      insert(state, "y" mult 1000000, expect &:= "y" mult 1000000);
      if nullAllowedInString(databaseKind) then
        insert(state, "A\0;B",    expect &:= "A\0;B");
      end if;
      insert(state, "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                    \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                    \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;\127;",
         expect &:= "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                    \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                    \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;\127;");
      insert(state, " !\"#$%&'()*+,-./",          expect &:= " !\"#$%&'()*+,-./");
      insert(state, "0123456789:;<=>?@",          expect &:= "0123456789:;<=>?@");
      insert(state, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", expect &:= "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      insert(state, "[\\]^_`{|}~\127;",           expect &:= "[\\]^_`{|}~\127;");
      insert(state, "abcdefghijklmnopqrstuvwxyz", expect &:= "abcdefghijklmnopqrstuvwxyz");
      insert(state, "\160;¡¢£¤¥¦§¨©ª«¬­®¯",       expect &:= "\160;¡¢£¤¥¦§¨©ª«¬­®¯");
      insert(state, "°±²³´µ¶·¸¹º»¼½¾¿",           expect &:= "°±²³´µ¶·¸¹º»¼½¾¿");
      insert(state, "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ",           expect &:= "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ");
      insert(state, "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß",           expect &:= "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß");
      insert(state, "àáâãäåæçèéêëìíîï",           expect &:= "àáâãäåæçèéêëìíîï");
      insert(state, "ðñòóôõö÷øùúûüýþÿ",           expect &:= "ðñòóôõö÷øùúûüýþÿ");
      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        stringColumn := column(state.statement, 1, string);
        if stringColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            if length(expect[row]) <= 1000 and length(stringColumn) <= 1000 then
              writeln(" *** testClobField: Row: " <& row <&
                      " Expected " <& literal(expect[row]) <&
                      " found string " <& literal(str(stringColumn)));
            else
              writeln(" *** testClobField: Row: " <& row <&
                      " Expected length: " <& length(expect[row]) <&
                      " string length found: " <& length(stringColumn));
            end if;
          end if;
        end if;
        if row = 1 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testClobField: Row: " <& row <&
                    " Expected NULL found " <& stringColumn);
          end if;
        end if;
        if length(expect[row]) <> 0 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testClobField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching clob fields works okay.");
    else
      writeln(" *** Inserting and fetching clob fields does not work okay.");
    end if;
  end func;


const proc: testDateField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("dateTest", "dateField", FALSE);
    var array time: expect is 0 times time.value;
    var time: dateColumn is time.value;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testDateField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " DATE)");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= time.value);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,               expect &:= time.value);

      if minDate(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(testDb, state, toDate(databaseKind, "-4711-1-1"),   expect &:= time("-4711-1-1"));
        insert(testDb, state, toDate(databaseKind, "-4711-12-31"), expect &:= time("-4711-12-31"));
        insert(testDb, state, toDate(databaseKind, "-999-12-31"),  expect &:= time("-999-12-31"));
        insert(testDb, state, toDate(databaseKind, "-123-1-23"),   expect &:= time("-123-1-23"));
        insert(testDb, state, toDate(databaseKind, "-42-4-2"),     expect &:= time("-42-4-2"));
        insert(testDb, state, toDate(databaseKind, "-1-1-1"),      expect &:= time("-1-1-1"));
        insert(testDb, state, toDate(databaseKind, "-1-12-31"),    expect &:= time("-1-12-31"));
      end if;
      if minDate(databaseKind) < time("1-1-1 0:0:0") then
        insert(testDb, state, toDate(databaseKind, "0-1-1"),       expect &:= time("0-1-1"));
        insert(testDb, state, toDate(databaseKind, "0-12-31"),     expect &:= time("0-12-31"));
      end if;
      insert(testDb, state, toDate(databaseKind, "1-1-1"),       expect &:= time("1-1-1"));
      insert(testDb, state, toDate(databaseKind, "1-12-31"),     expect &:= time("1-12-31"));
      insert(testDb, state, toDate(databaseKind, "42-4-2"),      expect &:= time("42-4-2"));
      insert(testDb, state, toDate(databaseKind, "123-1-23"),    expect &:= time("123-1-23"));
      insert(testDb, state, toDate(databaseKind, "999-12-31"),   expect &:= time("999-12-31"));
      insert(testDb, state, toDate(databaseKind, "1000-1-1"),    expect &:= time("1000-1-1"));
      insert(testDb, state, toDate(databaseKind, "1752-12-31"),  expect &:= time("1752-12-31"));
      insert(testDb, state, toDate(databaseKind, "1753-1-1"),    expect &:= time("1753-1-1"));
      insert(testDb, state, toDate(databaseKind, "1800-1-1"),    expect &:= time("1800-1-1"));
      insert(testDb, state, toDate(databaseKind, "1899-12-31"),  expect &:= time("1899-12-31"));
      insert(testDb, state, toDate(databaseKind, "1900-1-1"),    expect &:= time("1900-1-1"));
      insert(testDb, state, toDate(databaseKind, "1961-1-9"),    expect &:= time("1961-1-9"));
      insert(testDb, state, toDate(databaseKind, "1969-12-31"),  expect &:= time("1969-12-31"));
      insert(testDb, state, toDate(databaseKind, "1970-1-1"),    expect &:= time("1970-1-1"));
      insert(testDb, state, toDate(databaseKind, "1979-12-31"),  expect &:= time("1979-12-31"));
      insert(testDb, state, toDate(databaseKind, "1980-1-1"),    expect &:= time("1980-1-1"));
      insert(testDb, state, toDate(databaseKind, "2010-11-12"),  expect &:= time("2010-11-12"));
      insert(testDb, state, toDate(databaseKind, "2011-11-11"),  expect &:= time("2011-11-11"));
      insert(testDb, state, toDate(databaseKind, "2012-12-12"),  expect &:= time("2012-12-12"));

      if minDate(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, time("-4711-1-1"),   expect &:= time("-4711-1-1"));
        insert(state, time("-4711-12-31"), expect &:= time("-4711-12-31"));
        insert(state, time("-999-12-31"),  expect &:= time("-999-12-31"));
        insert(state, time("-123-1-23"),   expect &:= time("-123-1-23"));
        insert(state, time("-42-4-2"),     expect &:= time("-42-4-2"));
        insert(state, time("-1-1-1"),      expect &:= time("-1-1-1"));
        insert(state, time("-1-12-31"),    expect &:= time("-1-12-31"));
      end if;
      if minDate(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, time("0-1-1"),       expect &:= time("0-1-1"));
        insert(state, time("0-12-31"),     expect &:= time("0-12-31"));
      end if;
      insert(state, time("1-1-1"),       expect &:= time("1-1-1"));
      insert(state, time("1-12-31"),     expect &:= time("1-12-31"));
      insert(state, time("42-4-2"),      expect &:= time("42-4-2"));
      insert(state, time("123-1-23"),    expect &:= time("123-1-23"));
      insert(state, time("999-12-31"),   expect &:= time("999-12-31"));
      insert(state, time("1000-1-1"),    expect &:= time("1000-1-1"));
      insert(state, time("1752-12-31"),  expect &:= time("1752-12-31"));
      insert(state, time("1753-1-1"),    expect &:= time("1753-1-1"));
      insert(state, time("1800-1-1"),    expect &:= time("1800-1-1"));
      insert(state, time("1899-12-31"),  expect &:= time("1899-12-31"));
      insert(state, time("1900-1-1"),    expect &:= time("1900-1-1"));
      insert(state, time("1961-1-9"),    expect &:= time("1961-1-9"));
      insert(state, time("1969-12-31"),  expect &:= time("1969-12-31"));
      insert(state, time("1970-1-1"),    expect &:= time("1970-1-1"));
      insert(state, time("1979-12-31"),  expect &:= time("1979-12-31"));
      insert(state, time("1980-1-1"),    expect &:= time("1980-1-1"));
      insert(state, time("2010-11-12"),  expect &:= time("2010-11-12"));
      insert(state, time("2011-11-11"),  expect &:= time("2011-11-11"));
      insert(state, time("2012-12-12"),  expect &:= time("2012-12-12"));

      if minDate(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, setLocalTZ(time("-4711-1-1")),   expect &:= setLocalTZ(time("-4711-1-1")));
        insert(state, setLocalTZ(time("-4711-12-31")), expect &:= setLocalTZ(time("-4711-12-31")));
        insert(state, setLocalTZ(time("-999-12-31")),  expect &:= setLocalTZ(time("-999-12-31")));
        insert(state, setLocalTZ(time("-123-1-23")),   expect &:= setLocalTZ(time("-123-1-23")));
        insert(state, setLocalTZ(time("-42-4-2")),     expect &:= setLocalTZ(time("-42-4-2")));
        insert(state, setLocalTZ(time("-1-1-1")),      expect &:= setLocalTZ(time("-1-1-1")));
        insert(state, setLocalTZ(time("-1-12-31")),    expect &:= setLocalTZ(time("-1-12-31")));
      end if;
      if minDate(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, setLocalTZ(time("0-1-1")),       expect &:= setLocalTZ(time("0-1-1")));
        insert(state, setLocalTZ(time("0-12-31")),     expect &:= setLocalTZ(time("0-12-31")));
      end if;
      insert(state, setLocalTZ(time("1-1-1")),       expect &:= setLocalTZ(time("1-1-1")));
      insert(state, setLocalTZ(time("42-4-2")),      expect &:= setLocalTZ(time("42-4-2")));
      insert(state, setLocalTZ(time("123-1-23")),    expect &:= setLocalTZ(time("123-1-23")));
      insert(state, setLocalTZ(time("999-12-31")),   expect &:= setLocalTZ(time("999-12-31")));
      insert(state, setLocalTZ(time("1000-1-1")),    expect &:= setLocalTZ(time("1000-1-1")));
      insert(state, setLocalTZ(time("1752-12-31")),  expect &:= setLocalTZ(time("1752-12-31")));
      insert(state, setLocalTZ(time("1753-1-1")),    expect &:= setLocalTZ(time("1753-1-1")));
      insert(state, setLocalTZ(time("1800-1-1")),    expect &:= setLocalTZ(time("1800-1-1")));
      insert(state, setLocalTZ(time("1899-12-31")),  expect &:= setLocalTZ(time("1899-12-31")));
      insert(state, setLocalTZ(time("1900-1-1")),    expect &:= setLocalTZ(time("1900-1-1")));
      insert(state, setLocalTZ(time("1961-1-9")),    expect &:= setLocalTZ(time("1961-1-9")));
      insert(state, setLocalTZ(time("1969-12-31")),  expect &:= setLocalTZ(time("1969-12-31")));
      insert(state, setLocalTZ(time("1970-1-1")),    expect &:= setLocalTZ(time("1970-1-1")));
      insert(state, setLocalTZ(time("1979-12-31")),  expect &:= setLocalTZ(time("1979-12-31")));
      insert(state, setLocalTZ(time("1980-1-1")),    expect &:= setLocalTZ(time("1980-1-1")));
      insert(state, setLocalTZ(time("2010-11-12")),  expect &:= setLocalTZ(time("2010-11-12")));
      insert(state, setLocalTZ(time("2011-11-11")),  expect &:= setLocalTZ(time("2011-11-11")));
      insert(state, setLocalTZ(time("2012-12-12")),  expect &:= setLocalTZ(time("2012-12-12")));

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        dateColumn := column(state.statement, 1, time);
        if dateColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDateField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <&
                    " found " <& literal(str(dateColumn)));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDateField: Row: " <& row <&
                    " Expected NULL found " <& dateColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDateField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching date fields works okay.");
    else
      writeln(" *** Inserting and fetching date fields does not work okay.");
    end if;
  end func;


const proc: testTimeField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("timeTest", "timeField", FALSE);
    var array time: expect is 0 times time.value;
    var time: timeColumn is time.value;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testTimeField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & timeType(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= time.value);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,               expect &:= time.value);

      insert(testDb, state, toTime(databaseKind, "0:0:0"),           expect &:= time("0:0:0"));
      insert(testDb, state, toTime(databaseKind, "0:0:59"),          expect &:= time("0:0:59"));
      insert(testDb, state, toTime(databaseKind, "0:59:59"),         expect &:= time("0:59:59"));
      insert(testDb, state, toTime(databaseKind, "1:0:0"),           expect &:= time("1:0:0"));
      insert(testDb, state, toTime(databaseKind, "11:59:59"),        expect &:= time("11:59:59"));
      insert(testDb, state, toTime(databaseKind, "12:0:0"),          expect &:= time("12:0:0"));
      insert(testDb, state, toTime(databaseKind, "23:59:59"),        expect &:= time("23:59:59"));

      insert(state, time("0:0:0"),           expect &:= time("0:0:0"));
      insert(state, time("0:0:59"),          expect &:= time("0:0:59"));
      insert(state, time("0:59:59"),         expect &:= time("0:59:59"));
      insert(state, time("1:0:0"),           expect &:= time("1:0:0"));
      insert(state, time("11:59:59"),        expect &:= time("11:59:59"));
      insert(state, time("12:0:0"),          expect &:= time("12:0:0"));
      insert(state, time("23:59:59"),        expect &:= time("23:59:59"));

      insert(state, setLocalTZ(time("0:0:0")),           expect &:= setLocalTZ(time("0:0:0")));
      insert(state, setLocalTZ(time("0:0:59")),          expect &:= setLocalTZ(time("0:0:59")));
      insert(state, setLocalTZ(time("0:59:59")),         expect &:= setLocalTZ(time("0:59:59")));
      insert(state, setLocalTZ(time("1:0:0")),           expect &:= setLocalTZ(time("1:0:0")));
      insert(state, setLocalTZ(time("11:59:59")),        expect &:= setLocalTZ(time("11:59:59")));
      insert(state, setLocalTZ(time("12:0:0")),          expect &:= setLocalTZ(time("12:0:0")));
      insert(state, setLocalTZ(time("23:59:59")),        expect &:= setLocalTZ(time("23:59:59")));

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        timeColumn := column(state.statement, 1, time);
        if timeColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <&
                    " found " <& literal(str(timeColumn)));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeField: Row: " <& row <&
                    " Expected NULL found " <& timeColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching time fields works okay.");
    else
      writeln(" *** Inserting and fetching time fields does not work okay.");
    end if;
  end func;


const proc: testDateTimeField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("dateTimeTest", "dateTimeField", FALSE);
    var array time: expect is 0 times time.value;
    var time: dateTimeColumn is time.value;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testDateTimeField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & dateTimeType(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= time.value);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,                           expect &:= time.value);

      if minDate(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(testDb, state, toDateTime(databaseKind, "-4711-1-1 0:0:0"),      expect &:= time("-4711-1-1 0:0:0"));
        insert(testDb, state, toDateTime(databaseKind, "-4711-12-31 23:59:59"), expect &:= time("-4711-12-31 23:59:59"));
        insert(testDb, state, toDateTime(databaseKind, "-999-12-31 23:59:59"),  expect &:= time("-999-12-31 23:59:59"));
        insert(testDb, state, toDateTime(databaseKind, "-123-1-23 12:31:12"),   expect &:= time("-123-1-23 12:31:12"));
        insert(testDb, state, toDateTime(databaseKind, "-42-4-2 4:42:42"),      expect &:= time("-42-4-2 4:42:42"));
        insert(testDb, state, toDateTime(databaseKind, "-1-1-1 0:0:0"),         expect &:= time("-1-1-1 0:0:0"));
        insert(testDb, state, toDateTime(databaseKind, "-1-12-31 23:59:59"),    expect &:= time("-1-12-31 23:59:59"));
      end if;
      if minDate(databaseKind) < time("1-1-1 0:0:0") then
        insert(testDb, state, toDateTime(databaseKind, "0-1-1 0:0:0"),          expect &:= time("0-1-1 0:0:0"));
        insert(testDb, state, toDateTime(databaseKind, "0-12-31 23:59:59"),     expect &:= time("0-12-31 23:59:59"));
      end if;
      insert(testDb, state, toDateTime(databaseKind, "1-1-1 0:0:0"),          expect &:= time("1-1-1 0:0:0"));
      insert(testDb, state, toDateTime(databaseKind, "1-12-31 23:59:59"),     expect &:= time("1-12-31 23:59:59"));
      insert(testDb, state, toDateTime(databaseKind, "42-4-2 4:42:42"),       expect &:= time("42-4-2 4:42:42"));
      insert(testDb, state, toDateTime(databaseKind, "123-1-23 12:31:12"),    expect &:= time("123-1-23 12:31:12"));
      insert(testDb, state, toDateTime(databaseKind, "999-12-31 23:59:59"),   expect &:= time("999-12-31 23:59:59"));
      insert(testDb, state, toDateTime(databaseKind, "1000-1-1 0:0:0"),       expect &:= time("1000-1-1 0:0:0"));
      insert(testDb, state, toDateTime(databaseKind, "1752-12-31 23:59:59"),  expect &:= time("1752-12-31 23:59:59"));
      insert(testDb, state, toDateTime(databaseKind, "1753-1-1 0:0:0"),       expect &:= time("1753-1-1 0:0:0"));
      insert(testDb, state, toDateTime(databaseKind, "1800-1-1 0:0:0"),       expect &:= time("1800-1-1 0:0:0"));
      insert(testDb, state, toDateTime(databaseKind, "1899-12-31 23:59:59"),  expect &:= time("1899-12-31 23:59:59"));
      insert(testDb, state, toDateTime(databaseKind, "1900-1-1 0:0:0"),       expect &:= time("1900-1-1 0:0:0"));
      insert(testDb, state, toDateTime(databaseKind, "1961-1-9 6:1:0"),       expect &:= time("1961-1-9 6:1:0"));
      insert(testDb, state, toDateTime(databaseKind, "1969-12-31 23:59:59"),  expect &:= time("1969-12-31 23:59:59"));
      insert(testDb, state, toDateTime(databaseKind, "1970-1-1 0:0:0"),       expect &:= time("1970-1-1 0:0:0"));
      insert(testDb, state, toDateTime(databaseKind, "1979-12-31 23:59:59"),  expect &:= time("1979-12-31 23:59:59"));
      insert(testDb, state, toDateTime(databaseKind, "1980-1-1 0:0:0"),       expect &:= time("1980-1-1 0:0:0"));
      insert(testDb, state, toDateTime(databaseKind, "2010-11-12 13:14:15"),  expect &:= time("2010-11-12 13:14:15"));
      insert(testDb, state, toDateTime(databaseKind, "2011-11-11 11:11:11"),  expect &:= time("2011-11-11 11:11:11"));
      insert(testDb, state, toDateTime(databaseKind, "2012-12-12 12:12:12"),  expect &:= time("2012-12-12 12:12:12"));

      if minDate(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, time("-4711-1-1 0:0:0"),      expect &:= time("-4711-1-1 0:0:0"));
        insert(state, time("-4711-12-31 23:59:59"), expect &:= time("-4711-12-31 23:59:59"));
        insert(state, time("-999-12-31 23:59:59"),  expect &:= time("-999-12-31 23:59:59"));
        insert(state, time("-123-1-23 12:31:12"),   expect &:= time("-123-1-23 12:31:12"));
        insert(state, time("-42-4-2 4:42:42"),      expect &:= time("-42-4-2 4:42:42"));
        insert(state, time("-1-1-1 0:0:0"),         expect &:= time("-1-1-1 0:0:0"));
        insert(state, time("-1-12-31 23:59:59"),    expect &:= time("-1-12-31 23:59:59"));
      end if;
      if minDate(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, time("0-1-1 0:0:0"),          expect &:= time("0-1-1 0:0:0"));
        insert(state, time("0-12-31 23:59:59"),     expect &:= time("0-12-31 23:59:59"));
      end if;
      insert(state, time("1-1-1 0:0:0"),          expect &:= time("1-1-1 0:0:0"));
      insert(state, time("1-12-31 23:59:59"),     expect &:= time("1-12-31 23:59:59"));
      insert(state, time("42-4-2 4:42:42"),       expect &:= time("42-4-2 4:42:42"));
      insert(state, time("123-1-23 12:31:12"),    expect &:= time("123-1-23 12:31:12"));
      insert(state, time("999-12-31 23:59:59"),   expect &:= time("999-12-31 23:59:59"));
      insert(state, time("1000-1-1 0:0:0"),       expect &:= time("1000-1-1 0:0:0"));
      insert(state, time("1752-12-31 23:59:59"),  expect &:= time("1752-12-31 23:59:59"));
      insert(state, time("1753-1-1 0:0:0"),       expect &:= time("1753-1-1 0:0:0"));
      insert(state, time("1800-1-1 0:0:0"),       expect &:= time("1800-1-1 0:0:0"));
      insert(state, time("1899-12-31 23:59:59"),  expect &:= time("1899-12-31 23:59:59"));
      insert(state, time("1900-1-1 0:0:0"),       expect &:= time("1900-1-1 0:0:0"));
      insert(state, time("1961-1-9 6:1:0"),       expect &:= time("1961-1-9 6:1:0"));
      insert(state, time("1969-12-31 23:59:59"),  expect &:= time("1969-12-31 23:59:59"));
      insert(state, time("1970-1-1 0:0:0"),       expect &:= time("1970-1-1 0:0:0"));
      insert(state, time("1979-12-31 23:59:59"),  expect &:= time("1979-12-31 23:59:59"));
      insert(state, time("1980-1-1 0:0:0"),       expect &:= time("1980-1-1 0:0:0"));
      insert(state, time("2010-11-12 13:14:15"),  expect &:= time("2010-11-12 13:14:15"));
      insert(state, time("2011-11-11 11:11:11"),  expect &:= time("2011-11-11 11:11:11"));
      insert(state, time("2012-12-12 12:12:12"),  expect &:= time("2012-12-12 12:12:12"));

      if minDate(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, setLocalTZ(time("-4711-1-1 0:0:0")),      expect &:= setLocalTZ(time("-4711-1-1 0:0:0")));
        insert(state, setLocalTZ(time("-4711-12-31 23:59:59")), expect &:= setLocalTZ(time("-4711-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-999-12-31 23:59:59")),  expect &:= setLocalTZ(time("-999-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-123-1-23 12:31:12")),   expect &:= setLocalTZ(time("-123-1-23 12:31:12")));
        insert(state, setLocalTZ(time("-42-4-2 4:42:42")),      expect &:= setLocalTZ(time("-42-4-2 4:42:42")));
        insert(state, setLocalTZ(time("-1-1-1 0:0:0")),         expect &:= setLocalTZ(time("-1-1-1 0:0:0")));
        insert(state, setLocalTZ(time("-1-12-31 23:59:59")),    expect &:= setLocalTZ(time("-1-12-31 23:59:59")));
      end if;
      if minDate(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, setLocalTZ(time("0-1-1 0:0:0")),          expect &:= setLocalTZ(time("0-1-1 0:0:0")));
        insert(state, setLocalTZ(time("0-12-31 23:59:59")),     expect &:= setLocalTZ(time("0-12-31 23:59:59")));
      end if;
      insert(state, setLocalTZ(time("1-1-1 0:0:0")),          expect &:= setLocalTZ(time("1-1-1 0:0:0")));
      insert(state, setLocalTZ(time("42-4-2 4:42:42")),       expect &:= setLocalTZ(time("42-4-2 4:42:42")));
      insert(state, setLocalTZ(time("123-1-23 12:31:12")),    expect &:= setLocalTZ(time("123-1-23 12:31:12")));
      insert(state, setLocalTZ(time("999-12-31 23:59:59")),   expect &:= setLocalTZ(time("999-12-31 23:59:59")));
      insert(state, setLocalTZ(time("1000-1-1 0:0:0")),       expect &:= setLocalTZ(time("1000-1-1 0:0:0")));
      insert(state, setLocalTZ(time("1752-12-31 23:59:59")),  expect &:= setLocalTZ(time("1752-12-31 23:59:59")));
      insert(state, setLocalTZ(time("1753-1-1 0:0:0")),       expect &:= setLocalTZ(time("1753-1-1 0:0:0")));
      insert(state, setLocalTZ(time("1800-1-1 0:0:0")),       expect &:= setLocalTZ(time("1800-1-1 0:0:0")));
      insert(state, setLocalTZ(time("1899-12-31 23:59:59")),  expect &:= setLocalTZ(time("1899-12-31 23:59:59")));
      insert(state, setLocalTZ(time("1900-1-1 0:0:0")),       expect &:= setLocalTZ(time("1900-1-1 0:0:0")));
      insert(state, setLocalTZ(time("1961-1-9 6:1:0")),       expect &:= setLocalTZ(time("1961-1-9 6:1:0")));
      insert(state, setLocalTZ(time("1969-12-31 23:59:59")),  expect &:= setLocalTZ(time("1969-12-31 23:59:59")));
      insert(state, setLocalTZ(time("1970-1-1 0:0:0")),       expect &:= setLocalTZ(time("1970-1-1 0:0:0")));
      insert(state, setLocalTZ(time("1979-12-31 23:59:59")),  expect &:= setLocalTZ(time("1979-12-31 23:59:59")));
      insert(state, setLocalTZ(time("1980-1-1 0:0:0")),       expect &:= setLocalTZ(time("1980-1-1 0:0:0")));
      insert(state, setLocalTZ(time("2010-11-12 13:14:15")),  expect &:= setLocalTZ(time("2010-11-12 13:14:15")));
      insert(state, setLocalTZ(time("2011-11-11 11:11:11")),  expect &:= setLocalTZ(time("2011-11-11 11:11:11")));
      insert(state, setLocalTZ(time("2012-12-12 12:12:12")),  expect &:= setLocalTZ(time("2012-12-12 12:12:12")));

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        dateTimeColumn := column(state.statement, 1, time);
        if dateTimeColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDateTimeField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <&
                    " found " <& literal(str(dateTimeColumn)));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDateTimeField: Row: " <& row <&
                    " Expected NULL found " <& dateTimeColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDateTimeField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching dateTime fields works okay.");
    else
      writeln(" *** Inserting and fetching dateTime fields does not work okay.");
    end if;
  end func;


const proc: testTimeStampField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("timeStampTest", "timeStampField", FALSE);
    var array time: expect is 0 times time.value;
    var time: timeColumn is time.value;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testTimeStampField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & timeStampType(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= time.value);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,                           expect &:= time.value);

      if minTimeStamp(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "-4711-1-1 0:0:0"),      expect &:= time("-4711-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "-4711-12-31 23:59:59"), expect &:= time("-4711-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "-4711-12-31 23:59:59.123456"),
               expect &:= time("-4711-12-31 23:59:59.123456"));
        insert(testDb, state, toTimeStamp(databaseKind, "-999-12-31 23:59:59"),  expect &:= time("-999-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "-123-1-23 12:31:12"),   expect &:= time("-123-1-23 12:31:12"));
        insert(testDb, state, toTimeStamp(databaseKind, "-42-4-2 4:42:42"),      expect &:= time("-42-4-2 4:42:42"));
        insert(testDb, state, toTimeStamp(databaseKind, "-1-1-1 0:0:0"),         expect &:= time("-1-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "-1-12-31 23:59:59"),    expect &:= time("-1-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "-1-12-31 23:59:59.999999"),
               expect &:= time("-1-12-31 23:59:59.999999"));
      end if;
      if minTimeStamp(databaseKind) < time("1-1-1 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "0-1-1 0:0:0"),            expect &:= time("0-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "0-12-31 23:59:59"),       expect &:= time("0-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "0-12-31 23:59:59.123456"),
               expect &:= time("0-12-31 23:59:59.123456"));
        insert(testDb, state, toTimeStamp(databaseKind, "0-12-31 23:59:59.999999"),
               expect &:= time("0-12-31 23:59:59.999999"));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-1 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "1-1-1 0:0:0"),            expect &:= time("1-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "1-12-31 23:59:59"),       expect &:= time("1-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "1-12-31 23:59:59.123456"),
               expect &:= time("1-12-31 23:59:59.123456"));
        insert(testDb, state, toTimeStamp(databaseKind, "1-12-31 23:59:59.999999"),
               expect &:= time("1-12-31 23:59:59.999999"));
        insert(testDb, state, toTimeStamp(databaseKind, "42-4-2 4:42:42"),         expect &:= time("42-4-2 4:42:42"));
        insert(testDb, state, toTimeStamp(databaseKind, "123-1-23 12:31:12"),      expect &:= time("123-1-23 12:31:12"));
        insert(testDb, state, toTimeStamp(databaseKind, "999-12-31 23:59:59"),     expect &:= time("999-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "1000-1-1 0:0:0"),         expect &:= time("1000-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "1752-12-31 23:59:59"),    expect &:= time("1752-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "1753-1-1 0:0:0"),         expect &:= time("1753-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "1800-1-1 0:0:0"),         expect &:= time("1800-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "1899-12-31 23:59:59"),    expect &:= time("1899-12-31 23:59:59"));
        insert(testDb, state, toTimeStamp(databaseKind, "1900-1-1 0:0:0"),         expect &:= time("1900-1-1 0:0:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "1961-1-9 6:1:0"),         expect &:= time("1961-1-9 6:1:0"));
        insert(testDb, state, toTimeStamp(databaseKind, "1969-12-31 23:59:59"),    expect &:= time("1969-12-31 23:59:59"));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-2 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "1970-1-1 0:0:0"),         expect &:= time("1970-1-1 0:0:0"));
      end if;
      insert(testDb, state, toTimeStamp(databaseKind, "1970-1-2 0:0:0"),         expect &:= time("1970-1-2 0:0:0"));
      insert(testDb, state, toTimeStamp(databaseKind, "1979-12-31 23:59:59"),    expect &:= time("1979-12-31 23:59:59"));
      insert(testDb, state, toTimeStamp(databaseKind, "1980-1-1 0:0:0"),         expect &:= time("1980-1-1 0:0:0"));
      insert(testDb, state, toTimeStamp(databaseKind, "2010-11-12 13:14:15.16"), expect &:= time("2010-11-12 13:14:15.16"));
      insert(testDb, state, toTimeStamp(databaseKind, "2011-11-11 11:11:11.11"), expect &:= time("2011-11-11 11:11:11.11"));
      insert(testDb, state, toTimeStamp(databaseKind, "2012-12-12 12:12:12.12"), expect &:= time("2012-12-12 12:12:12.12"));

      if minTimeStamp(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, time("-4711-1-1 0:0:0"),      expect &:= time("-4711-1-1 0:0:0"));
        insert(state, time("-4711-12-31 23:59:59"), expect &:= time("-4711-12-31 23:59:59"));
        insert(state, time("-4711-12-31 23:59:59.123456"),
               expect &:= time("-4711-12-31 23:59:59.123456"));
        insert(state, time("-999-12-31 23:59:59"),  expect &:= time("-999-12-31 23:59:59"));
        insert(state, time("-123-1-23 12:31:12"),   expect &:= time("-123-1-23 12:31:12"));
        insert(state, time("-42-4-2 4:42:42"),      expect &:= time("-42-4-2 4:42:42"));
        insert(state, time("-1-1-1 0:0:0"),         expect &:= time("-1-1-1 0:0:0"));
        insert(state, time("-1-12-31 23:59:59"),    expect &:= time("-1-12-31 23:59:59"));
        insert(state, time("-1-12-31 23:59:59.999999"),
               expect &:= time("-1-12-31 23:59:59.999999"));
      end if;
      if minTimeStamp(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, time("0-1-1 0:0:0"),            expect &:= time("0-1-1 0:0:0"));
        insert(state, time("0-12-31 23:59:59"),       expect &:= time("0-12-31 23:59:59"));
        insert(state, time("0-12-31 23:59:59.123456"),
               expect &:= time("0-12-31 23:59:59.123456"));
        insert(state, time("0-12-31 23:59:59.999999"),
               expect &:= time("0-12-31 23:59:59.999999"));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-1 0:0:0") then
        insert(state, time("1-1-1 0:0:0"),            expect &:= time("1-1-1 0:0:0"));
        insert(state, time("1-12-31 23:59:59"),       expect &:= time("1-12-31 23:59:59"));
        insert(state, time("1-12-31 23:59:59.123456"),
               expect &:= time("1-12-31 23:59:59.123456"));
        insert(state, time("1-12-31 23:59:59.999999"),
               expect &:= time("1-12-31 23:59:59.999999"));
        insert(state, time("42-4-2 4:42:42"),         expect &:= time("42-4-2 4:42:42"));
        insert(state, time("123-1-23 12:31:12"),      expect &:= time("123-1-23 12:31:12"));
        insert(state, time("999-12-31 23:59:59"),     expect &:= time("999-12-31 23:59:59"));
        insert(state, time("1000-1-1 0:0:0"),         expect &:= time("1000-1-1 0:0:0"));
        insert(state, time("1752-12-31 23:59:59"),    expect &:= time("1752-12-31 23:59:59"));
        insert(state, time("1753-1-1 0:0:0"),         expect &:= time("1753-1-1 0:0:0"));
        insert(state, time("1800-1-1 0:0:0"),         expect &:= time("1800-1-1 0:0:0"));
        insert(state, time("1899-12-31 23:59:59"),    expect &:= time("1899-12-31 23:59:59"));
        insert(state, time("1900-1-1 0:0:0"),         expect &:= time("1900-1-1 0:0:0"));
        insert(state, time("1961-1-9 6:1:0"),         expect &:= time("1961-1-9 6:1:0"));
        insert(state, time("1969-12-31 23:59:59"),    expect &:= time("1969-12-31 23:59:59"));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-2 0:0:0") then
        insert(state, time("1970-1-1 0:0:0"),         expect &:= time("1970-1-1 0:0:0"));
      end if;
      insert(state, time("1970-1-2 0:0:0"),         expect &:= time("1970-1-2 0:0:0"));
      insert(state, time("1979-12-31 23:59:59"),    expect &:= time("1979-12-31 23:59:59"));
      insert(state, time("1980-1-1 0:0:0"),         expect &:= time("1980-1-1 0:0:0"));
      insert(state, time("2010-11-12 13:14:15.16"), expect &:= time("2010-11-12 13:14:15.16"));
      insert(state, time("2011-11-11 11:11:11.11"), expect &:= time("2011-11-11 11:11:11.11"));
      insert(state, time("2012-12-12 12:12:12.12"), expect &:= time("2012-12-12 12:12:12.12"));

      if minTimeStamp(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, setLocalTZ(time("-4711-1-1 0:0:0")),      expect &:= setLocalTZ(time("-4711-1-1 0:0:0")));
        insert(state, setLocalTZ(time("-4711-12-31 23:59:59")), expect &:= setLocalTZ(time("-4711-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-4711-12-31 23:59:59.123456")),
               expect &:= setLocalTZ(time("-4711-12-31 23:59:59.123456")));
        insert(state, setLocalTZ(time("-999-12-31 23:59:59")),  expect &:= setLocalTZ(time("-999-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-123-1-23 12:31:12")),   expect &:= setLocalTZ(time("-123-1-23 12:31:12")));
        insert(state, setLocalTZ(time("-42-4-2 4:42:42")),      expect &:= setLocalTZ(time("-42-4-2 4:42:42")));
        insert(state, setLocalTZ(time("-1-1-1 0:0:0")),         expect &:= setLocalTZ(time("-1-1-1 0:0:0")));
        insert(state, setLocalTZ(time("-1-12-31 23:59:59")),    expect &:= setLocalTZ(time("-1-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-1-12-31 23:59:59.999999")),
               expect &:= setLocalTZ(time("-1-12-31 23:59:59.999999")));
      end if;
      if minTimeStamp(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, setLocalTZ(time("0-1-1 0:0:0")),            expect &:= setLocalTZ(time("0-1-1 0:0:0")));
        insert(state, setLocalTZ(time("0-12-31 23:59:59")),       expect &:= setLocalTZ(time("0-12-31 23:59:59")));
        insert(state, setLocalTZ(time("0-12-31 23:59:59.123456")),
               expect &:= setLocalTZ(time("0-12-31 23:59:59.123456")));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-1 0:0:0") then
        insert(state, setLocalTZ(time("1-1-1 0:0:0")),            expect &:= setLocalTZ(time("1-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1-12-31 23:59:59")),       expect &:= setLocalTZ(time("1-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1-12-31 23:59:59.123456")),
               expect &:= setLocalTZ(time("1-12-31 23:59:59.123456")));
        insert(state, setLocalTZ(time("1-12-31 23:59:59.999999")),
               expect &:= setLocalTZ(time("1-12-31 23:59:59.999999")));
        insert(state, setLocalTZ(time("42-4-2 4:42:42")),         expect &:= setLocalTZ(time("42-4-2 4:42:42")));
        insert(state, setLocalTZ(time("123-1-23 12:31:12")),      expect &:= setLocalTZ(time("123-1-23 12:31:12")));
        insert(state, setLocalTZ(time("999-12-31 23:59:59")),     expect &:= setLocalTZ(time("999-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1000-1-1 0:0:0")),         expect &:= setLocalTZ(time("1000-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1752-12-31 23:59:59")),    expect &:= setLocalTZ(time("1752-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1753-1-1 0:0:0")),         expect &:= setLocalTZ(time("1753-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1800-1-1 0:0:0")),         expect &:= setLocalTZ(time("1800-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1899-12-31 23:59:59")),    expect &:= setLocalTZ(time("1899-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1900-1-1 0:0:0")),         expect &:= setLocalTZ(time("1900-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1961-1-9 6:1:0")),         expect &:= setLocalTZ(time("1961-1-9 6:1:0")));
        insert(state, setLocalTZ(time("1969-12-31 23:59:59")),    expect &:= setLocalTZ(time("1969-12-31 23:59:59")));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-2 0:0:0") then
        insert(state, setLocalTZ(time("1970-1-1 0:0:0")),         expect &:= setLocalTZ(time("1970-1-1 0:0:0")));
      end if;
      insert(state, setLocalTZ(time("1970-1-2 0:0:0")),         expect &:= setLocalTZ(time("1970-1-2 0:0:0")));
      insert(state, setLocalTZ(time("1979-12-31 23:59:59")),    expect &:= setLocalTZ(time("1979-12-31 23:59:59")));
      insert(state, setLocalTZ(time("1980-1-1 0:0:0")),         expect &:= setLocalTZ(time("1980-1-1 0:0:0")));
      insert(state, setLocalTZ(time("2010-11-12 13:14:15.16")), expect &:= setLocalTZ(time("2010-11-12 13:14:15.16")));
      insert(state, setLocalTZ(time("2011-11-11 11:11:11.11")), expect &:= setLocalTZ(time("2011-11-11 11:11:11.11")));
      insert(state, setLocalTZ(time("2012-12-12 12:12:12.12")), expect &:= setLocalTZ(time("2012-12-12 12:12:12.12")));

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        timeColumn := column(state.statement, 1, time);
        if timeColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeStampField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <&
                    " found " <& literal(str(timeColumn)));
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeStampField: Row: " <& row <&
                    " Expected NULL found " <& timeColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeStampField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching timeStamp fields works okay.");
    else
      writeln(" *** Inserting and fetching timeStamp fields does not work okay.");
    end if;
  end func;


const proc: testTimeStampTzField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("timeStampTzTest", "timeStampTzField", FALSE);
    var array time: expect is 0 times time.value;
    var time: timeColumn is time.value;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testTimeStampTzField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & timeStampTzType(databaseKind) & ")");
      execute(state.statement);
      insert(testDb, state, "NULL", expect &:= time.value);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,                           expect &:= time.value);

      if minTimeStamp(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "-4711-1-1 0:0:0"),      expect &:= setLocalTZ(time("-4711-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "-4711-12-31 23:59:59"), expect &:= setLocalTZ(time("-4711-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "-4711-12-31 23:59:59.123456"),
               expect &:= setLocalTZ(time("-4711-12-31 23:59:59.123456")));
        insert(testDb, state, toTimeStamp(databaseKind, "-999-12-31 23:59:59"),  expect &:= setLocalTZ(time("-999-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "-123-1-23 12:31:12"),   expect &:= setLocalTZ(time("-123-1-23 12:31:12")));
        insert(testDb, state, toTimeStamp(databaseKind, "-42-4-2 4:42:42"),      expect &:= setLocalTZ(time("-42-4-2 4:42:42")));
        insert(testDb, state, toTimeStamp(databaseKind, "-1-1-1 0:0:0"),         expect &:= setLocalTZ(time("-1-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "-1-12-31 23:59:59"),    expect &:= setLocalTZ(time("-1-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "-1-12-31 23:59:59.999999"),
               expect &:= setLocalTZ(time("-1-12-31 23:59:59.999999")));
      end if;
      if minTimeStamp(databaseKind) < time("1-1-1 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "0-1-1 0:0:0"),            expect &:= setLocalTZ(time("0-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "0-12-31 23:59:59"),       expect &:= setLocalTZ(time("0-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "0-12-31 23:59:59.123456"),
               expect &:= setLocalTZ(time("0-12-31 23:59:59.123456")));
        insert(testDb, state, toTimeStamp(databaseKind, "0-12-31 23:59:59.999999"),
               expect &:= setLocalTZ(time("0-12-31 23:59:59.999999")));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-1 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "1-1-1 0:0:0"),            expect &:= setLocalTZ(time("1-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "1-12-31 23:59:59"),       expect &:= setLocalTZ(time("1-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "1-12-31 23:59:59.123456"),
               expect &:= setLocalTZ(time("1-12-31 23:59:59.123456")));
        insert(testDb, state, toTimeStamp(databaseKind, "1-12-31 23:59:59.999999"),
               expect &:= setLocalTZ(time("1-12-31 23:59:59.999999")));
        insert(testDb, state, toTimeStamp(databaseKind, "42-4-2 4:42:42"),         expect &:= setLocalTZ(time("42-4-2 4:42:42")));
        insert(testDb, state, toTimeStamp(databaseKind, "123-1-23 12:31:12"),      expect &:= setLocalTZ(time("123-1-23 12:31:12")));
        insert(testDb, state, toTimeStamp(databaseKind, "999-12-31 23:59:59"),     expect &:= setLocalTZ(time("999-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "1000-1-1 0:0:0"),         expect &:= setLocalTZ(time("1000-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "1752-12-31 23:59:59"),    expect &:= setLocalTZ(time("1752-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "1753-1-1 0:0:0"),         expect &:= setLocalTZ(time("1753-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "1800-1-1 0:0:0"),         expect &:= setLocalTZ(time("1800-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "1899-12-31 23:59:59"),    expect &:= setLocalTZ(time("1899-12-31 23:59:59")));
        insert(testDb, state, toTimeStamp(databaseKind, "1900-1-1 0:0:0"),         expect &:= setLocalTZ(time("1900-1-1 0:0:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "1961-1-9 6:1:0"),         expect &:= setLocalTZ(time("1961-1-9 6:1:0")));
        insert(testDb, state, toTimeStamp(databaseKind, "1969-12-31 23:59:59"),    expect &:= setLocalTZ(time("1969-12-31 23:59:59")));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-2 0:0:0") then
        insert(testDb, state, toTimeStamp(databaseKind, "1970-1-1 0:0:0"),         expect &:= setLocalTZ(time("1970-1-1 0:0:0")));
      end if;
      insert(testDb, state, toTimeStamp(databaseKind, "1970-1-2 0:0:0"),         expect &:= setLocalTZ(time("1970-1-2 0:0:0")));
      insert(testDb, state, toTimeStamp(databaseKind, "1979-12-31 23:59:59"),    expect &:= setLocalTZ(time("1979-12-31 23:59:59")));
      insert(testDb, state, toTimeStamp(databaseKind, "1980-1-1 0:0:0"),         expect &:= setLocalTZ(time("1980-1-1 0:0:0")));
      insert(testDb, state, toTimeStamp(databaseKind, "2010-11-12 13:14:15.16"), expect &:= setLocalTZ(time("2010-11-12 13:14:15.16")));
      insert(testDb, state, toTimeStamp(databaseKind, "2011-11-11 11:11:11.11"), expect &:= setLocalTZ(time("2011-11-11 11:11:11.11")));
      insert(testDb, state, toTimeStamp(databaseKind, "2012-12-12 12:12:12.12"), expect &:= setLocalTZ(time("2012-12-12 12:12:12.12")));

      if minTimeStamp(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, time("-4711-1-1 0:0:0"),      expect &:= time("-4711-1-1 0:0:0"));
        insert(state, time("-4711-12-31 23:59:59"), expect &:= time("-4711-12-31 23:59:59"));
        insert(state, time("-4711-12-31 23:59:59.123456"),
               expect &:= time("-4711-12-31 23:59:59.123456"));
        insert(state, time("-999-12-31 23:59:59"),  expect &:= time("-999-12-31 23:59:59"));
        insert(state, time("-123-1-23 12:31:12"),   expect &:= time("-123-1-23 12:31:12"));
        insert(state, time("-42-4-2 4:42:42"),      expect &:= time("-42-4-2 4:42:42"));
        insert(state, time("-1-1-1 0:0:0"),         expect &:= time("-1-1-1 0:0:0"));
        insert(state, time("-1-12-31 23:59:59"),    expect &:= time("-1-12-31 23:59:59"));
        insert(state, time("-1-12-31 23:59:59.999999"),
               expect &:= time("-1-12-31 23:59:59.999999"));
      end if;
      if minTimeStamp(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, time("0-1-1 0:0:0"),            expect &:= time("0-1-1 0:0:0"));
        insert(state, time("0-12-31 23:59:59"),       expect &:= time("0-12-31 23:59:59"));
        insert(state, time("0-12-31 23:59:59.123456"),
               expect &:= time("0-12-31 23:59:59.123456"));
        insert(state, time("0-12-31 23:59:59.999999"),
               expect &:= time("0-12-31 23:59:59.999999"));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-1 0:0:0") then
        insert(state, time("1-1-1 0:0:0"),            expect &:= time("1-1-1 0:0:0"));
        insert(state, time("1-12-31 23:59:59"),       expect &:= time("1-12-31 23:59:59"));
        insert(state, time("1-12-31 23:59:59.123456"),
               expect &:= time("1-12-31 23:59:59.123456"));
        insert(state, time("1-12-31 23:59:59.999999"),
               expect &:= time("1-12-31 23:59:59.999999"));
        insert(state, time("42-4-2 4:42:42"),         expect &:= time("42-4-2 4:42:42"));
        insert(state, time("123-1-23 12:31:12"),      expect &:= time("123-1-23 12:31:12"));
        insert(state, time("999-12-31 23:59:59"),     expect &:= time("999-12-31 23:59:59"));
        insert(state, time("1000-1-1 0:0:0"),         expect &:= time("1000-1-1 0:0:0"));
        insert(state, time("1752-12-31 23:59:59"),    expect &:= time("1752-12-31 23:59:59"));
        insert(state, time("1753-1-1 0:0:0"),         expect &:= time("1753-1-1 0:0:0"));
        insert(state, time("1800-1-1 0:0:0"),         expect &:= time("1800-1-1 0:0:0"));
        insert(state, time("1899-12-31 23:59:59"),    expect &:= time("1899-12-31 23:59:59"));
        insert(state, time("1900-1-1 0:0:0"),         expect &:= time("1900-1-1 0:0:0"));
        insert(state, time("1961-1-9 6:1:0"),         expect &:= time("1961-1-9 6:1:0"));
        insert(state, time("1969-12-31 23:59:59"),    expect &:= time("1969-12-31 23:59:59"));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-2 0:0:0") then
        insert(state, time("1970-1-1 0:0:0"),         expect &:= time("1970-1-1 0:0:0"));
      end if;
      insert(state, time("1970-1-2 0:0:0"),         expect &:= time("1970-1-2 0:0:0"));
      insert(state, time("1979-12-31 23:59:59"),    expect &:= time("1979-12-31 23:59:59"));
      insert(state, time("1980-1-1 0:0:0"),         expect &:= time("1980-1-1 0:0:0"));
      insert(state, time("2010-11-12 13:14:15.16"), expect &:= time("2010-11-12 13:14:15.16"));
      insert(state, time("2011-11-11 11:11:11.11"), expect &:= time("2011-11-11 11:11:11.11"));
      insert(state, time("2012-12-12 12:12:12.12"), expect &:= time("2012-12-12 12:12:12.12"));

      if minTimeStamp(databaseKind) <= time("-4711-1-1 0:0:0") then
        insert(state, setLocalTZ(time("-4711-1-1 0:0:0")),      expect &:= setLocalTZ(time("-4711-1-1 0:0:0")));
        insert(state, setLocalTZ(time("-4711-12-31 23:59:59")), expect &:= setLocalTZ(time("-4711-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-4711-12-31 23:59:59.123456")),
               expect &:= setLocalTZ(time("-4711-12-31 23:59:59.123456")));
        insert(state, setLocalTZ(time("-999-12-31 23:59:59")),  expect &:= setLocalTZ(time("-999-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-123-1-23 12:31:12")),   expect &:= setLocalTZ(time("-123-1-23 12:31:12")));
        insert(state, setLocalTZ(time("-42-4-2 4:42:42")),      expect &:= setLocalTZ(time("-42-4-2 4:42:42")));
        insert(state, setLocalTZ(time("-1-1-1 0:0:0")),         expect &:= setLocalTZ(time("-1-1-1 0:0:0")));
        insert(state, setLocalTZ(time("-1-12-31 23:59:59")),    expect &:= setLocalTZ(time("-1-12-31 23:59:59")));
        insert(state, setLocalTZ(time("-1-12-31 23:59:59.999999")),
               expect &:= setLocalTZ(time("-1-12-31 23:59:59.999999")));
      end if;
      if minTimeStamp(databaseKind) < time("1-1-1 0:0:0") then
        insert(state, setLocalTZ(time("0-1-1 0:0:0")),            expect &:= setLocalTZ(time("0-1-1 0:0:0")));
        insert(state, setLocalTZ(time("0-12-31 23:59:59")),       expect &:= setLocalTZ(time("0-12-31 23:59:59")));
        insert(state, setLocalTZ(time("0-12-31 23:59:59.123456")),
               expect &:= setLocalTZ(time("0-12-31 23:59:59.123456")));
        insert(state, setLocalTZ(time("0-12-31 23:59:59.999999")),
               expect &:= setLocalTZ(time("0-12-31 23:59:59.999999")));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-1 0:0:0") then
        insert(state, setLocalTZ(time("1-1-1 0:0:0")),            expect &:= setLocalTZ(time("1-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1-12-31 23:59:59")),       expect &:= setLocalTZ(time("1-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1-12-31 23:59:59.123456")),
               expect &:= setLocalTZ(time("1-12-31 23:59:59.123456")));
        insert(state, setLocalTZ(time("1-12-31 23:59:59.999999")),
               expect &:= setLocalTZ(time("1-12-31 23:59:59.999999")));
        insert(state, setLocalTZ(time("42-4-2 4:42:42")),         expect &:= setLocalTZ(time("42-4-2 4:42:42")));
        insert(state, setLocalTZ(time("123-1-23 12:31:12")),      expect &:= setLocalTZ(time("123-1-23 12:31:12")));
        insert(state, setLocalTZ(time("999-12-31 23:59:59")),     expect &:= setLocalTZ(time("999-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1000-1-1 0:0:0")),         expect &:= setLocalTZ(time("1000-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1752-12-31 23:59:59")),    expect &:= setLocalTZ(time("1752-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1753-1-1 0:0:0")),         expect &:= setLocalTZ(time("1753-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1800-1-1 0:0:0")),         expect &:= setLocalTZ(time("1800-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1899-12-31 23:59:59")),    expect &:= setLocalTZ(time("1899-12-31 23:59:59")));
        insert(state, setLocalTZ(time("1900-1-1 0:0:0")),         expect &:= setLocalTZ(time("1900-1-1 0:0:0")));
        insert(state, setLocalTZ(time("1961-1-9 6:1:0")),         expect &:= setLocalTZ(time("1961-1-9 6:1:0")));
        insert(state, setLocalTZ(time("1969-12-31 23:59:59")),    expect &:= setLocalTZ(time("1969-12-31 23:59:59")));
      end if;
      if minTimeStamp(databaseKind) < time("1970-1-2 0:0:0") then
        insert(state, setLocalTZ(time("1970-1-1 0:0:0")),         expect &:= setLocalTZ(time("1970-1-1 0:0:0")));
      end if;
      insert(state, setLocalTZ(time("1970-1-2 0:0:0")),         expect &:= setLocalTZ(time("1970-1-2 0:0:0")));
      insert(state, setLocalTZ(time("1979-12-31 23:59:59")),    expect &:= setLocalTZ(time("1979-12-31 23:59:59")));
      insert(state, setLocalTZ(time("1980-1-1 0:0:0")),         expect &:= setLocalTZ(time("1980-1-1 0:0:0")));
      insert(state, setLocalTZ(time("2010-11-12 13:14:15.16")), expect &:= setLocalTZ(time("2010-11-12 13:14:15.16")));
      insert(state, setLocalTZ(time("2011-11-11 11:11:11.11")), expect &:= setLocalTZ(time("2011-11-11 11:11:11.11")));
      insert(state, setLocalTZ(time("2012-12-12 12:12:12.12")), expect &:= setLocalTZ(time("2012-12-12 12:12:12.12")));

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        timeColumn := column(state.statement, 1, time);
        if timeColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeStampTzField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <&
                    " found " <& literal(str(timeColumn)));
          end if;
        end if;
        if timeColumn.timeZone <> expect[row].timeZone then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeStampTzField: Row: " <& row <&
                    " Expected time zone " <& expect[row] <&
                    " found " <& timeColumn);
          end if;
        end if;
        if row <= 2 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeStampTzField: Row: " <& row <&
                    " Expected NULL found " <& timeColumn);
          end if;
        end if;
        if row > 2 and isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testTimeStampTzField: Row: " <& row <&
                    " Expected " <& literal(expect[row]) <& " found NULL");
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching timeStampTz fields works okay.");
    else
      writeln(" *** Inserting and fetching timeStampTz fields does not work okay.");
    end if;
  end func;


const proc: testDurationField (in database: testDb, in dbCategory: databaseKind) is func
  local
    var testState: state is testState("durationTest", "durationField", FALSE);
    var array duration: expect is 0 times duration.value;
    var duration: durationColumn is duration.value;
    var integer: row is 1;
  begin
    if state.details then
      writeln("testDurationField: " <& databaseKind);
    end if;
    block
      state.statement := prepare(testDb, "CREATE TABLE " & state.tableName &
                                 " (" & state.fieldName & " " & durationType(databaseKind) & ")");
      execute(state.statement);
      state.statement := prepare(testDb, "INSERT INTO " & state.tableName &
                                 " (" & state.fieldName & ") VALUES (?)");
      insert(state, NULL,                       expect &:= duration.value);
      insert(state, duration("P0D"),            expect &:= duration("P0D"));
      insert(state, duration("P1Y"),            expect &:= duration("P1Y"));
      insert(state, duration("P1M"),            expect &:= duration("P1M"));
      insert(state, duration("P1D"),            expect &:= duration("P1D"));
      insert(state, duration("PT1H"),           expect &:= duration("PT1H"));
      insert(state, duration("PT1M"),           expect &:= duration("PT1M"));
      insert(state, duration("PT1S"),           expect &:= duration("PT1S"));
      insert(state, duration("PT0.1S"),         expect &:= duration("PT0.1S"));
      insert(state, duration("P-1Y"),           expect &:= duration("P-1Y"));
      insert(state, duration("P-1M"),           expect &:= duration("P-1M"));
      insert(state, duration("P-1D"),           expect &:= duration("P-1D"));
      insert(state, duration("PT-1H"),          expect &:= duration("PT-1H"));
      insert(state, duration("PT-1M"),          expect &:= duration("PT-1M"));
      insert(state, duration("PT-1S"),          expect &:= duration("PT-1S"));
      insert(state, duration("PT-0.1S"),        expect &:= duration("PT-0.1S"));
      insert(state, duration("P1Y1M"),          expect &:= duration("P1Y1M"));
      insert(state, duration("P1Y-1M"),         expect &:= duration("P1Y-1M"));
      insert(state, duration("P1Y1D"),          expect &:= duration("P1Y1D"));
      insert(state, duration("P1Y-1D"),         expect &:= duration("P1Y-1D"));
      insert(state, duration("P1YT1H"),         expect &:= duration("P1YT1H"));
      insert(state, duration("P1YT-1H"),        expect &:= duration("P1YT-1H"));
      insert(state, duration("P1YT1M"),         expect &:= duration("P1YT1M"));
      insert(state, duration("P1YT-1M"),        expect &:= duration("P1YT-1M"));
      insert(state, duration("P1YT1S"),         expect &:= duration("P1YT1S"));
      insert(state, duration("P1YT-1S"),        expect &:= duration("P1YT-1S"));
      insert(state, duration("P1YT0.1S"),       expect &:= duration("P1YT0.1S"));
      insert(state, duration("P1YT-0.1S"),      expect &:= duration("P1YT-0.1S"));
      insert(state, duration("P-1Y1M"),         expect &:= duration("P-1Y1M"));
      insert(state, duration("P-1Y-1M"),        expect &:= duration("P-1Y-1M"));
      insert(state, duration("P-1Y1D"),         expect &:= duration("P-1Y1D"));
      insert(state, duration("P-1Y-1D"),        expect &:= duration("P-1Y-1D"));
      insert(state, duration("P-1YT1H"),        expect &:= duration("P-1YT1H"));
      insert(state, duration("P-1YT-1H"),       expect &:= duration("P-1YT-1H"));
      insert(state, duration("P-1YT1M"),        expect &:= duration("P-1YT1M"));
      insert(state, duration("P-1YT-1M"),       expect &:= duration("P-1YT-1M"));
      insert(state, duration("P-1YT1S"),        expect &:= duration("P-1YT1S"));
      insert(state, duration("P-1YT-1S"),       expect &:= duration("P-1YT-1S"));
      insert(state, duration("P-1YT0.1S"),      expect &:= duration("P-1YT0.1S"));
      insert(state, duration("P-1YT-0.1S"),     expect &:= duration("P-1YT-0.1S"));

      state.statement := prepare(testDb, "SELECT * FROM " & state.tableName);
      execute(state.statement);
      while fetch(state.statement) do
        durationColumn := column(state.statement, 1, duration);
        if durationColumn <> expect[row] then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDurationField: Row: " <& row <&
                    " Expected " <& literal(str(expect[row])) <&
                    " found " <& literal(str(durationColumn)));
          end if;
        end if;
        if row = 1 and not isNull(state.statement, 1) then
          state.okay := FALSE;
          if state.details then
            writeln(" *** testDurationField: Row: " <& row <&
                    " Expected NULL found " <& durationColumn);
          end if;
        end if;
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        state.okay := FALSE;
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        state.okay := FALSE;
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        state.okay := FALSE;
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    state.statement := prepare(testDb, "DROP TABLE " & state.tableName);
    execute(state.statement);

    if state.okay then
      writeln("Inserting and fetching duration fields works okay.");
    else
      writeln(" *** Inserting and fetching duration fields does not work okay.");
    end if;
  end func;


const proc: testFloatField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    const string: tableName is "floatTest";
    var sqlStatement: statement is sqlStatement.value;
    var float: floatColumn is 0.0;
    var integer: row is 1;
  begin
    writeln("testFloatField2: " <& databaseKind);
    statement := prepare(testDb, "CREATE TABLE " & tableName & " (floatField " & floatType(databaseKind) & ")");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (floatField FLOAT)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (floatField REAL)");
    execute(statement);
    block
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (floatField) VALUES (NULL)");
      statement := prepare(testDb, "INSERT INTO " & tableName & " (floatField) VALUES (-9223372036854775808.0)");
      execute(statement);
      statement := prepare(testDb, "SELECT * FROM " & tableName);
      execute(statement);
      while fetch(statement) do
        writeln(column(statement, 1, float));
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    statement := prepare(testDb, "DROP TABLE " & tableName);
    execute(statement);
  end func;


const proc: testBigRatField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    const string: tableName is "bigRatTest";
    var sqlStatement: statement is sqlStatement.value;
    var bigRational: bigRatColumn is bigRational.value;
    var integer: row is 1;
  begin
    writeln("testBigRatField2: " <& databaseKind);
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (bigRatField " & bigRatType(databaseKind) & ")");
    statement := prepare(testDb, "CREATE TABLE " & tableName & " (bigRatField NUMERIC(38,15))");
    execute(statement);
    block
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (bigRatField) VALUES (1)");
      statement := prepare(testDb, "INSERT INTO " & tableName & " (bigRatField) VALUES (?)"); bind(statement, 1, 1_ / 1_);
      execute(statement);
      statement := prepare(testDb, "SELECT * FROM " & tableName);
      execute(statement);
      while fetch(statement) do
        writeln(column(statement, 1, bigRational));
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    statement := prepare(testDb, "DROP TABLE " & tableName);
    execute(statement);
  end func;


const proc: testBlobField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    const string: tableName is "blobTest";
    var sqlStatement: statement is sqlStatement.value;
    var bstring: bstringColumn is bstring("");
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    writeln("testBlobField2: " <& databaseKind);
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (blobField " & blobType(databaseKind) & ")");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (blobField BLOB)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (blobField VARBINARY(MAX))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (blobField VARCHAR(MAX))");
    # statement := prepare(testDb, "CREATE TABLE blobTest (int32Field INTEGER, blobField BLOB, varcharField VARCHAR(32))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (int32Field INTEGER, blobField " & blobType(databaseKind) & ", varcharField " & varcharType(databaseKind) & "(32))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (int32Field INTEGER, blobField " & blobType(databaseKind) & ", numericField " & numericType(databaseKind) & ")");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (int32Field INTEGER, numericField " & numericType(databaseKind) & ")");
    execute(statement);
    block
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES (NULL)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES (0xfedcba9876543210)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES ('some text')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES (?)"); bind(statement, 1, bstring(""));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES (?)"); bind(statement, 1, bstring(getf("data.txt")));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES (?)"); bind(statement, 1, bstring("\16#fe;\16#dc;\16#ba;\16#98;\16#76;\16#54;\16#32;\16#10;"));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES (?)"); bind(statement, 1, bstring("abcdefgh" mult 1024 * 1024 * 16));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (blobField) VALUES (?)"); bind(statement, 1, "abcdefgh" mult 1024 * 1024);
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (int32Field, blobField, varcharField) VALUES (123, 0xfedcba9876543210, 'some text')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (int32Field, blobField, numericField) VALUES (123, 0xfedcba9876543210, 0.123456789)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (int32Field, numericField) VALUES (123, 0.123456789)");
      execute(statement);
      statement := prepare(testDb, "SELECT * FROM " & tableName);
      execute(statement);
      while fetch(statement) do
        # writeln(column(statement, 1, bstring));
        # writeln(column(statement, 1, string));
        # writeln(column(statement, 1, integer));
        # writeln(column(statement, 2, bstring));
        # writeln(column(statement, 2, bigRational));
        # writeln(column(statement, 3, string));
        # writeln(column(statement, 3, bigRational));
        # writeln(length(column(statement, 1, bstring)));
        # writeln(length(column(statement, 1, string)));
        # putf("data2.txt", str(column(statement, 1, bstring)));
       incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    statement := prepare(testDb, "DROP TABLE " & tableName);
    execute(statement);
  end func;


const proc: testTimeField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    const string: tableName is "timeTest";
    var array time: expect is 0 times time.value;
    var sqlStatement: statement is sqlStatement.value;
    var integer: row is 1;
  begin
    writeln("testTimeField2: " <& databaseKind);
     statement := prepare(testDb, "CREATE TABLE " & tableName & " (timeField TIMESTAMP)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (timeField TIMESTAMPTZ)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (timeField DATE)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (timeField DATETIME)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (timeField DATETIME2(7))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (timeField TIME)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (timeField TIMETZ)");
    execute(statement);
    block
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('0010-11-12 13:14:15 BC')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('0001-01-01 00:00:00 BC')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('0001-01-01 00:00:00')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('2017-03-14')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('2017-03-14 15:16:17.18')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('1893-04-01 00:00:00.00')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('1893-03-31 23:54:38.999999')");  # UTC+1:5 ??
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('1893-03-31 23:54:39.00')");      # UTC+1
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (current_date)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (getdate)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (current_timestamp)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('16:17:18.19')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES ('2010-11-12 13:14:15.16')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (?)"); bind(statement, 1, time(NOW));
       statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (?)"); bind(statement, 1, toUTC(time(NOW)));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (?)"); bind(statement, 1, setLocalTZ(time("2010-11-12 13:14:15.16")));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (?)"); bind(statement, 1, setLocalTZ(time("-10-11-12 13:14:15")));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (?)"); bind(statement, 1, time("0-1-1 0:0:0"));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (timeField) VALUES (?)"); bind(statement, 1, setLocalTZ(time("0-1-1 0:0:0")));
      execute(statement);
      statement := prepare(testDb, "SELECT * FROM " & tableName);
      execute(statement);
      while fetch(statement) do
        writeln(" *** testTimeField2: Row: " <& row <& " Found " <& literal(str(column(statement, 1, time))));
        # writeln(" *** testTimeField2: Row: " <& row <& " Found " <& column(statement, 1, string));
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    statement := prepare(testDb, "DROP TABLE " & tableName);
    execute(statement);
  end func;


const proc: testDurationField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    const string: tableName is "durationTest";
    var array duration: expect is 0 times duration.value;
    var sqlStatement: statement is sqlStatement.value;
    var duration: durationColumn is duration.value;
    var integer: row is 1;
  begin
    writeln("testDurationField2: " <& databaseKind);
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField TIMESTAMP)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField TIMESTAMPTZ)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField DATE)");
     statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField DATETIME)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField TIME)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField TIMETZ)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField INTERVAL)");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField VARCHAR(32))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (durationField INTERVAL DAY(3) TO SECOND(6))");
    execute(statement);
    block
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('2017-03-14')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('2017-03-14 15:16:17.18')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES (current_date)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES (current_timestamp)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('16:17:18.19')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('2010-11-12T13:14:15')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('2010-11-12 13:14:15.16')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('0010-11-12 13:14:15.16')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('P1Y2M3DT4H5M6S')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('P1Y2M3DT4H5M6.7S')");
       statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('P1Y2M3DT4H5M6.7890123S')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES ('P-1Y-2M-3DT-4H-5M-6.7S')");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES (?)"); bind(statement, 1, time(NOW));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES (?)"); bind(statement, 1, duration("P2010Y11M12DT13H14M15.16S"));
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (durationField) VALUES (?)"); bind(statement, 1, duration("P10Y11M12DT13H14M15.16S"));
      execute(statement);
      statement := prepare(testDb, "SELECT * FROM " & tableName);
      execute(statement);
      while fetch(statement) do
        durationColumn := column(statement, 1, duration);
        writeln(" *** testDurationField: Row: " <& row <&
                " Found " <& literal(str(durationColumn)));
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    statement := prepare(testDb, "DROP TABLE " & tableName);
    execute(statement);
  end func;


const proc: testNumericField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    const string: tableName is "numericTest";
    var sqlStatement: statement is sqlStatement.value;
    var integer: integerColumn is 0;
    var bigInteger: bigIntColumn is 0_;
    var bigRational: bigRatColumn is 0_/1_;
    var float: floatColumn is 0.0;
    var integer: row is 1;
  begin
    writeln("testNumericField2: " <& databaseKind);
     statement := prepare(testDb, "CREATE TABLE " & tableName & " (numericField NUMERIC(38,15))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (numericField NUMERIC(38,30))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (numericField NUMERIC(38,38))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (numericField NUMERIC(38,0))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (numericField NUMERIC(38,-1))");
    # statement := prepare(testDb, "CREATE TABLE " & tableName & " (numericField NUMERIC(38,15))");
    execute(statement);
    block
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (NULL)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (12345.678901)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (-12345.678901)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (0.12345678901234567890123456789012345678)");
       statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (0.00000000000000000000000000000000000001)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (-12345.678901234567890123456789012345)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (-0.12345678901234567890123456789012345678)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (-12345678901234567890123456789012345678)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (-123456789012345678901234567890123456780)");
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (?)"); bind(statement, 1, 12345.678901);
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (?)"); bind(statement, 1, -12345678901234567890123456789012345678_);
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (?)"); bind(statement, 1, -12345678901234567890123456789012345678_ / 1_);
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (?)"); bind(statement, 1, 12345678901234560000000_/1_);
      # statement := prepare(testDb, "INSERT INTO " & tableName & " (numericField) VALUES (?)"); bind(statement, 1, 123456789012345600000000_/1_);
      execute(statement);
      statement := prepare(testDb, "SELECT * FROM " & tableName);
      execute(statement);
      while fetch(statement) do
        writeln("isNull: " <& isNull(statement, 1));
        writeln(column(statement, 1, float));
        writeln(column(statement, 1, bigRational));
        writeln(column(statement, 1, bigInteger));
        writeln(column(statement, 1, integer));
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    statement := prepare(testDb, "DROP TABLE " & tableName);
    execute(statement);
  end func;


const proc: testVarcharField2 (in database: testDb, in dbCategory: databaseKind) is func
  local
    const string: tableName is "varcharTest2";
    var array string: expect is 0 times "";
    var sqlStatement: statement is sqlStatement.value;
    var string: stringColumn is "";
    var integer: row is 1;
  begin
    writeln("testVarcharField: " <& databaseKind);
    statement := prepare(testDb, "CREATE TABLE " & tableName &
                         " (varcharField varchar(32765))");
    execute(statement);
    block
      statement := prepare(testDb, "INSERT INTO " & tableName &
                           " (varcharField) VALUES (?)");
     # insert(statement, "09876543210987654321",  expect &:= "09876543210987654321");
     # insert(statement, "123456789012345678901",  expect &:= "123456789012345678901");
      insert(statement, "x" mult 32765, expect &:= "x" mult 32765);
(*
      insert(statement, NULL,         expect &:= "");
      insert(statement, "",           expect &:= "");
      insert(statement, "X",          expect &:= "X");
      insert(statement, "Ab2",        expect &:= "Ab2");
      insert(statement, "abcdefghij", expect &:= "abcdefghij");
      insert(statement, "ÄäÖöÜüß",    expect &:= "ÄäÖöÜüß");
      insert(statement, "€µ¹²³¼½«»¬", expect &:= "€µ¹²³¼½«»¬");
      insert(statement, "x" mult 32,  expect &:= "x" mult 32);
      insert(statement, "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                        \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                        \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;",
                        expect &:= "\1;\2;\3;\4;\5;\6;\7;\8;\9;\
                        \\10;\11;\12;\13;\14;\15;\16;\17;\18;\19;\20;\
                        \\21;\22;\23;\24;\25;\26;\27;\28;\29;\30;\31;");
      statement := prepare(testDb, "INSERT INTO " & tableName &
                           " (varcharField) VALUES (?)");
      insert(statement,          0,   expect &:= "0");
      insert(statement,          1,   expect &:= "1");
      insert(statement, 1234567890,   expect &:= "1234567890");
      statement := prepare(testDb, "INSERT INTO " & tableName &
                           " (varcharField) VALUES (?)");
      insert(statement,          0_,  expect &:= "0");
      insert(statement,          1_,  expect &:= "1");
      insert(statement, 1234567890_,  expect &:= "1234567890");
*)
#      statement := prepare(testDb, "INSERT INTO " & tableName &
#                           " (varcharField) VALUES (N'" <&
#                           "\128;\129;\130;\131;\132;\133;\134;\135;\
#                           \\136;\137;\138;\139;\140;\141;\142;\143;\144;\145;\146;\147;\148;\
#                           \\149;\150;\151;\152;\153;\154;\155;\156;\157;\158;\159;" & "')");
#      statement := prepare(testDb, "INSERT INTO " & tableName &
#                           " (varcharField) VALUES (\
#                           \CHAR(128) + CHAR(129) + CHAR(130) + CHAR(131) + CHAR(132) + CHAR(133) + CHAR(134) + CHAR(135) + CHAR(136) + CHAR(137) + \
#                           \CHAR(138) + CHAR(139) + CHAR(140) + CHAR(141) + CHAR(142) + CHAR(143) + CHAR(144) + CHAR(145) + CHAR(146) + CHAR(147) + \
#                           \CHAR(148) + CHAR(149) + CHAR(150) + CHAR(151) + CHAR(152) + CHAR(153) + CHAR(154) + CHAR(155) + CHAR(156) + CHAR(157) + \
#                           \CHAR(158) + CHAR(159))");
#      execute(statement);
#      expect &:= "\128;\129;\130;\131;\132;\133;\134;\135;\
#                 \\136;\137;\138;\139;\140;\141;\142;\143;\144;\145;\146;\147;\148;\
#                 \\149;\150;\151;\152;\153;\154;\155;\156;\157;\158;\159;";
      statement := prepare(testDb, "SELECT * FROM " & tableName);
      execute(statement);
      while fetch(statement) do
        stringColumn := column(statement, 1, string);
        # writeln("testVarcharField: Row: " <& row <& ": " <& stringColumn);
        writeln("testVarcharField: Row: " <& row <& " length: " <& length(stringColumn));
        incr(row);
      end while;
    exception
      catch RANGE_ERROR:
        writeln(" *** RANGE_ERROR was raised");
      catch FILE_ERROR:
        writeln(" *** FILE_ERROR was raised");
      catch DATABASE_ERROR:
        writeln(" *** DATABASE_ERROR was raised");
    end block;
    statement := prepare(testDb, "DROP TABLE " & tableName);
    execute(statement);
  end func;


const proc: testDb (in database: testDb, in connectData: dbConnectData) is func
  local
    var dbCategory: databaseKind is NO_DB;
  begin
    databaseKind := dbConnectData.databaseKind;
    testPrepareAndExecute(testDb, databaseKind);
    testFieldNames(testDb, databaseKind);
    testAutoCommit(testDb, dbConnectData);
    testTransactions(testDb, dbConnectData);
    testBooleanField(testDb, databaseKind);
    testInt8Field(testDb, databaseKind);
    testInt16Field(testDb, databaseKind);
    testInt32Field(testDb, databaseKind);
    testInt64Field(testDb, databaseKind);
    testBigIntField(testDb, databaseKind);
    testFloatField(testDb, databaseKind);
    testDoubleField(testDb, databaseKind);
    # testBigRatField(testDb, databaseKind);
    testDecimalIntField(testDb, databaseKind);
    testNumericIntField(testDb, databaseKind);
    testDecimalField(testDb, databaseKind);
    testNumericField(testDb, databaseKind);
    testChar1AsciiField(testDb, databaseKind);
    testChar1Latin1Field(testDb, databaseKind);
    testCodePageField(testDb, 1250, databaseKind);
    testCodePageField(testDb, 1252, databaseKind);
    testChar1Field(testDb, databaseKind);
    testCharField(testDb, databaseKind);
    testVarcharField(testDb, databaseKind);
    testBlobField(testDb, databaseKind);
    testClobField(testDb, databaseKind);
    testDateField(testDb, databaseKind);
    testTimeField(testDb, databaseKind);
    testDateTimeField(testDb, databaseKind);
    testTimeStampField(testDb, databaseKind);
    testTimeStampTzField(testDb, databaseKind);
    testDurationField(testDb, databaseKind);
    # testFloatField2(testDb, databaseKind);
    # testBigRatField2(testDb, databaseKind);
    # testCharField2(testDb, databaseKind);
    # testBlobField2(testDb, databaseKind);
    # testTimeField2(testDb, databaseKind);
    # testDurationField2(testDb, databaseKind);
    # testNumericField2(testDb, databaseKind);
    # testVarcharField2(testDb, databaseKind);
  end func;


const func boolean: failed (in proc: statement) is func
  result
    var boolean: failed is FALSE;
  begin
    block
      statement;
    exception
      catch RANGE_ERROR:
        failed := TRUE;
      catch FILE_ERROR:
        failed := TRUE;
      catch DATABASE_ERROR:
        failed := TRUE;
    end block;
  end func;


const proc: testDatabase (in connectData: dbConnectData) is func
  local
    var database: testDb is database.value;
  begin
    writeln("Test " <& dbConnectData.dbName <& " with driver " <&
            dbConnectData.driver);
    block
      testDb := openDatabase(dbConnectData.driver,
                             dbConnectData.dbName,
                             dbConnectData.user,
                             dbConnectData.password);
    exception
      catch DATABASE_ERROR:
        writeln(" *** Cannot open database " <& dbConnectData.dbName <&
                " with driver " <& dbConnectData.driver);
        writeln(" *** Database error: " <& errMessage(DATABASE_ERROR));
      otherwise:
        writeln(" *** Cannot open database " <& dbConnectData.dbName <&
                " with driver " <& dbConnectData.driver);
    end block;
    if testDb <> database.value then
      testDb(testDb, dbConnectData);
      close(testDb);
    end if;
  end func;


const proc: main is func
  local
    const array connectData: dbConnectDataList is [] (
        connectData(DB_ODBC,       "test",             "", "", DB_ODBC),
        connectData(DB_SQL_SERVER, "test",             "test", "test", DB_SQL_SERVER),
        connectData(DB_FIRE,       "test",             "test", "test", DB_FIRE),
        # connectData(DB_MYSQL,      "penguin/test",     "test", "test", DB_MYSQL),
        # connectData(DB_ODBC,       "penguin_mysql",    "test", "test", DB_MYSQL),
        # connectData(DB_POSTGRESQL, "penguin/test",     "test", "test", DB_POSTGRESQL),
        # connectData(DB_ODBC,       "penguin_postgres", "test", "test", DB_POSTGRESQL),
        connectData(DB_MYSQL,      "test",             "test", "test", DB_MYSQL),
        connectData(DB_SQLITE,     "test",             "test", "test", DB_SQLITE),
        connectData(DB_POSTGRESQL, "test",             "test", "test", DB_POSTGRESQL),
        # connectData(DB_OCI,        "XE",               "test", "test", DB_OCI),
        # connectData(DB_OCI,        "192.168.2.99/XE",  "test", "test", DB_OCI),
        connectData(DB_ODBC,       "wurx",             "test", "test", DB_MYSQL),
        connectData(DB_ODBC,       "my",               "test", "test", DB_MYSQL),
        connectData(DB_ODBC,       "lite",             "test", "test", DB_SQLITE),
        connectData(DB_ODBC,       "post",             "test", "test", DB_POSTGRESQL));
    var integer: index is 0;
    var string: driverName is "";
    var boolean: okay is TRUE;
    var integer: paramNum is 0;
    var string: databaseKindName is "";
    var connectData: dbConnectData is connectData.value;
  begin
    OUT := STD_CONSOLE;
    IN := openEditLine(KEYBOARD, OUT);
    if length(argv(PROGRAM)) = 0 then
      writeln("usage: chkdb driver [-d databaseKind] [dbName [user [password]]]");
      writeln("       chkdb all");
    elsif length(argv(PROGRAM)) = 1 and argv(PROGRAM)[1] = "all" then
      for key index range dbConnectDataList do
        testDatabase(dbConnectDataList[index]);
      end for;
    else
      driverName := argv(PROGRAM)[1];
      dbConnectData.driver := dbCategory(driverName);
      if dbConnectData.driver = NO_DB then
        writeln("*** " <& literal(driverName) <& " is not a valid database driver.");
      else
        paramNum := 2;
        if length(argv(PROGRAM)) >= paramNum then
          if argv(PROGRAM)[paramNum] = "-d" then
            incr(paramNum);
            if length(argv(PROGRAM)) >= paramNum then
              databaseKindName := argv(PROGRAM)[paramNum];
              dbConnectData.databaseKind := dbCategory(databaseKindName);
              if dbConnectData.databaseKind = NO_DB then
                writeln("*** " <& literal(databaseKindName) <& " is not a valid database kind.");
                okay := FALSE;
              end if;
              incr(paramNum);
            else
              writeln("*** Database kind parameter missing.");
              okay := FALSE;
            end if;
          end if;
        end if;
        if dbConnectData.databaseKind = NO_DB then
          if (dbConnectData.driver = DB_ODBC or dbConnectData.driver = DB_TDS) then
            writeln("** For the " <& dbConnectData.driver <& " driver a database kind must be specified.");
            okay := FALSE;
          else
            dbConnectData.databaseKind := dbConnectData.driver;
          end if;
        end if;
        if okay then
          dbConnectData.dbName := "test";
          dbConnectData.user := "test";
          dbConnectData.password := "";
          if length(argv(PROGRAM)) >= paramNum then
            dbConnectData.dbName := argv(PROGRAM)[paramNum];
            incr(paramNum);
            if length(argv(PROGRAM)) >= paramNum then
              dbConnectData.user := argv(PROGRAM)[paramNum];
              incr(paramNum);
              if length(argv(PROGRAM)) >= paramNum then
                dbConnectData.password := argv(PROGRAM)[paramNum];
              end if;
            end if;
          end if;
          if dbConnectData.password = "" then
            write("Password: ");
            flush(OUT);
            dbConnectData.password := readPassword(IN);
          end if;
          if dbConnectData.databaseKind <> NO_DB then
            testDatabase(dbConnectData);
          end if;
        end if;
      end if;
    end if;
  end func;
