next up previous contents
Next: Konstantendeklarationen Up: Beispielprogramme Previous: Addresses - SQL

ODBCBench

 

ODBCBench ist ein portables Beispielprogramm. Es funktioniert ohne Änderungen auf den Oberon-Systemen V4 und V3. Um das Programm auch unter Oberon/F übersetzen zu können sind lediglich Änderungen aufgrund der anderen Schnittstelle des Moduls Files notwendig.

Die wesentlichen Schritte, um Portabilität zu erreichen sind das Ermitteln der von der jeweiligen Datenbank unterstützten Datentypen und das Umsetzen der gewünschten auf die unterstützten Datentypen. Weiters wird in diesem Programm gezeigt, wie man lange (dateibasierte) Daten in eine Tabelle einfügen und wieder auslesen kann.

MODULE ODBCBench;

IMPORT SQL, SQLExt, In, Out, Files, Strings;

CONST
  nofRows = 100;

VAR
  conn: SQL.Connection;
  connStr: ARRAY 255 OF CHAR;
  mapType, mapScale: ARRAY 3 OF INTEGER; mapPrec: ARRAY 3 OF LONGINT;
  f: Files.File;

PROCEDURE LongIntValueOf (f: SQL.Field): LONGINT;
  VAR i, tmp: LONGINT;
BEGIN
  WITH f: SQL.IntField DO RETURN f.i
  | f: SQL.StringField DO i := 0; tmp := 0;
      REPEAT
        tmp := tmp * 10 + ORD(f.str[i]) - ORD("0"); INC(i)
      UNTIL f.str[i] = 0X;
      RETURN tmp
  | f: SQL.RealField DO RETURN ENTIER(f.r)
  END
END LongIntValueOf;

PROCEDURE Disconnect*;
BEGIN conn := NIL END Disconnect;

PROCEDURE Connect*;
BEGIN
  IF conn # NIL THEN Disconnect END ;
  conn := SQL.OpenUI(connStr, connStr);
  IF ~SQL.Map(conn, SQL.OberonLongInt, 0, 0, mapType[0], mapPrec[0], mapScale[0]) OR
    ~SQL.Map(conn, SQL.OberonChar, 32, 0, mapType[1], mapPrec[1], mapScale[1]) OR
    ~SQL.Map(conn, SQL.SQLLVarChar, 50000, 0, mapType[2], mapPrec[2], mapScale[2]) THEN
    HALT(44)
  END
END Connect;

PROCEDURE DropTables*;
  VAR stat: SQL.Statement;
BEGIN
  stat := SQL.PrepareStatement(conn, "DROP table Bench1"); 
  SQL.Execute(stat);
  stat := SQL.PrepareStatement(conn, "DROP table Bench2"); 
  SQL.Execute(stat);
  stat := SQL.PrepareStatement(conn, "DROP table Bench3"); 
  SQL.Execute(stat);
END DropTables;

PROCEDURE CreateTables*;
  VAR stat: SQL.Statement; str: ARRAY 256 OF CHAR;
BEGIN
  str := "CREATE TABLE Bench1 (i ";
  SQLExt.AppendType(conn, str, mapType[0], mapPrec[0], mapScale[0]);
  Strings.Append(", firstName ", str);
  SQLExt.AppendType(conn, str, mapType[1], mapPrec[1], mapScale[1]);
  Strings.Append(", val ", str);
  SQLExt.AppendType(conn, str, mapType[0], mapPrec[0], mapScale[0]);
  Strings.Append(")", str);
  stat := SQL.PrepareStatement(conn, str);
  SQL.Execute(stat);
  Out.Ln; Out.String(str);
  IF stat.ret # SQL.Success THEN Out.String(" not") END ;
  Out.String(" created.");
  str := "CREATE TABLE Bench2 (i ";
  SQLExt.AppendType(conn, str, mapType[0], mapPrec[0], mapScale[0]);
  Strings.Append(", lastName ", str);
  SQLExt.AppendType(conn, str, mapType[1], mapPrec[1], mapScale[1]);
  Strings.Append(")", str);
  stat := SQL.PrepareStatement(conn, str); 
  SQL.Execute(stat);
  Out.Ln; Out.String(str);
  IF stat.ret # SQL.Success THEN Out.String(" not") END ;
  Out.String(" created.");
  str := "CREATE TABLE Bench3 (i ";
  SQLExt.AppendType(conn, str, mapType[0], mapPrec[0], mapScale[0]);
  Strings.Append(", longData ", str);
  SQLExt.AppendType(conn, str, mapType[2], mapPrec[2], mapScale[2]);
  Strings.Append(")", str);
  stat := SQL.PrepareStatement(conn, str); 
  SQL.Execute(stat); 
  Out.Ln; Out.String(str);
  IF stat.ret # SQL.Success THEN Out.String(" not") END ;
  Out.String(" created.")
END CreateTables;

PROCEDURE GenerateName(i: INTEGER; VAR s: ARRAY OF CHAR);
BEGIN
  s[2] := CHR((i MOD 10) + ORD("0"));
  s[1] := CHR((i DIV 10 MOD 10) + ORD("0"));
  s[0] := CHR((i DIV 100 MOD 10) + ORD("0"));
  s[3] := 0X
END GenerateName;

PROCEDURE InsertIntoBench1*;
  VAR types: ARRAY 3 OF SQL.ParamDesc; stat: SQL.Statement;
    i: INTEGER; idx, firstName, value: SQL.Field;
BEGIN
  types[0].oberonType := SQL.OberonLongInt; types[0].sqlType := mapType[0];
  types[0].precision := mapPrec[0]; types[0].scale := mapScale[0];
  types[0].inOut := SQL.InParam; types[0].name := "idx";
  types[1].oberonType := SQL.OberonChar; types[1].sqlType := mapType[1];
  types[1].precision := mapPrec[1]; types[1].scale := mapScale[1];
  types[1].inOut := SQL.InParam; types[1].name := "firstName";
  types[2] := types[0]; types[2].name := "value";
  stat := SQL.PrepareStatement(conn, 
    "INSERT INTO Bench1 (i, firstName, val) values (?, ?, ?)");
  SQL.BindParameters(stat, types, 3);
  SQL.FindField(stat.params, "idx", idx);
  SQL.FindField(stat.params, "firstName", firstName);
  SQL.FindField(stat.params, "value", value);
  FOR i := 0 TO nofRows DO
    idx(SQL.IntField).i := i;
    GenerateName(i, firstName(SQL.StringField).str);
    value(SQL.IntField).i := LONG(i) * i;
    SQL.Execute(stat);
    IF stat.ret # SQL.Success THEN RETURN END
  END
END InsertIntoBench1;

PROCEDURE AppendToBench1*;
  VAR types: ARRAY 3 OF SQL.ParamDesc; stat: SQL.Statement;
    i: INTEGER; idx, firstName, value: SQL.Field;
BEGIN
  stat := SQL.PrepareStatement(conn, "SELECT MAX(i) FROM Bench1");
  SQL.Execute(stat);
  SQL.FirstField(stat.results, idx);
  SQL.Fetch(stat);
  i := SHORT(LongIntValueOf(idx)); INC(i);
  types[0].oberonType := SQL.OberonLongInt; types[0].sqlType := mapType[0];
  types[0].precision := mapPrec[0]; types[0].scale := mapScale[0];
  types[0].inOut := SQL.InParam; types[0].name := "idx";
  types[1].oberonType := SQL.OberonChar; types[1].sqlType := mapType[1];
  types[1].precision := mapPrec[1]; types[1].scale := mapScale[1];
  types[1].inOut := SQL.InParam; types[1].name := "firstName";
  types[2] := types[0]; types[2].name := "value";
  stat := SQL.PrepareStatement(conn, 
    "INSERT INTO Bench1 (i, firstName, val) values (?, ?, ?)");
  SQL.BindParameters(stat, types, 3);
  SQL.FindField(stat.params, "idx", idx);
  SQL.FindField(stat.params, "firstName", firstName);
  SQL.FindField(stat.params, "value", value);
  REPEAT
    idx(SQL.IntField).i := i;
    GenerateName(i, firstName(SQL.StringField).str);
    value(SQL.IntField).i := LONG(i) * i;
    SQL.Execute(stat);
    IF stat.ret # SQL.Success THEN RETURN END ;
    INC(i)
  UNTIL i MOD nofRows = 0
END AppendToBench1;

PROCEDURE InsertIntoBench2*;
  VAR types: ARRAY 2 OF SQL.ParamDesc; stat: SQL.Statement;
    i: INTEGER; idx, lastName: SQL.Field;
BEGIN
  types[0].oberonType := SQL.OberonLongInt; types[0].sqlType := mapType[0];
  types[0].precision := mapPrec[0]; types[0].scale := mapScale[0];
  types[0].inOut := SQL.InParam; types[0].name := "idx";
  types[1].oberonType := SQL.OberonChar; types[1].sqlType := mapType[1];
  types[1].precision := mapPrec[1]; types[1].scale := mapScale[1];
  types[1].inOut := SQL.InParam; types[1].name := "lastName";
  stat := SQL.PrepareStatement(conn, 
    "INSERT INTO Bench2 (i, lastName) values (?, ?)");
  SQL.BindParameters(stat, types, 2);
  SQL.FindField(stat.params, "idx", idx);
  SQL.FindField(stat.params, "lastName", lastName);
  FOR i := 0 TO nofRows DO
    idx(SQL.IntField).i := i;
    GenerateName(i, lastName(SQL.StringField).str);
    SQL.Execute(stat);
    IF stat.ret # SQL.Success THEN RETURN END
  END
END InsertIntoBench2;

PROCEDURE PutField* (VAR field: SQL.Field);
  VAR r: Files.Rider; ch: CHAR; f: SQL.Field;
BEGIN
  IF field.len = SQL.NullData THEN Out.String("NULL")
  ELSE
    f := field;
    WITH f: SQL.IntField DO Out.Int(f.i, 0)
    | f: SQL.StringField DO Out.String(f.str)
    | f: SQL.RealField DO
      CASE field.sqlType OF
        SQL.SQLFloat, SQL.SQLDouble: Out.LongReal(f.r, 16)
      | SQL.SQLReal: Out.Real(SHORT(f.r), 16)
      END
    | f: SQL.DateField DO Out.Int(f.year, 0); Out.Char(\-"); 
      Out.Int(f.month, 0); Out.Char(\-"); Out.Int(f.day, 0)
    | f: SQL.TimeField DO Out.Int(f.hour, 0); Out.Char(":"); 
      Out.Int(f.minute, 0); Out.Char(":"); Out.Int(f.second, 0)
    | f: SQL.TimeStampField DO Out.Int(f.year, 0); Out.Char(\-"); 
      Out.Int(f.month, 0); Out.Char(\-"); Out.Int(f.day, 0); 
      Out.Char(" "); Out.Int(f.hour, 0); Out.Char(":");
      Out.Int(f.minute, 0); Out.Char(":"); Out.Int(f.second, 0); 
      Out.Char("."); Out.Int(f.fraction, 0)
    | f: SQL.BooleanField DO
      IF f.b THEN Out.String("TRUE") ELSE Out.String("FALSE") END
    | f: SQL.FileField DO
      Out.String("Length of data: "); Out.Int(Files.Length(f.f), 0);
      IF field.sqlType = SQL.SQLLVarChar THEN
        Files.Set(r, f.f, 0); Files.Read(r, ch);
        WHILE ~r.eof DO Out.Char(ch); Files.Read(r, ch) END
      END
    ELSE (* SQL.BinaryField *)
    END
  END
END PutField;

PROCEDURE ShowResults* (s: SQL.Statement);
  VAR field: SQL.Field; rows: LONGINT;
BEGIN
  IF s.ret = SQL.Success THEN
    IF s.results # NIL THEN
      Out.Ln; SQL.FirstField(s.results, field);
      WHILE field # NIL DO 
        Out.String(field.name); Out.Char(9X); SQL.NextField(field)
      END ;
      REPEAT
        SQL.Fetch(s); 
        IF s.ret = SQL.Success THEN
          Out.Ln;
          SQL.FirstField(s.results, field);
          WHILE field # NIL DO
            PutField(field); Out.Char(9X);
            SQL.NextField(field)
          END
        END
      UNTIL s.ret # SQL.Success
    ELSE
      SQL.RowCount(s, rows);
      IF rows # -1 THEN 
        Out.Ln; Out.String("Number of rows affected: "); Out.Int(rows, 0)
      END
    END
  ELSE
    SQL.ShowError(s.ret, "ShowResults", SQL.env, conn.dbc, s.stmt)
  END ;
END ShowResults;

PROCEDURE Execute*;
  VAR stat: SQL.Statement; str: ARRAY 256 OF CHAR;
BEGIN
  In.Open; In.String(str);
  stat := SQL.PrepareStatement(conn, str);
  SQL.Execute(stat);
  ShowResults(stat)
END Execute;

PROCEDURE ExecuteIntParam*;
  VAR stat: SQL.Statement; str: ARRAY 256 OF CHAR;
    types: ARRAY 1 OF SQL.ParamDesc; par1: SQL.Field;
BEGIN
  In.Open; In.String(str);
  types[0].oberonType := SQL.OberonLongInt; types[0].sqlType := mapType[0];
  types[0].precision := mapPrec[0]; types[0].scale := mapScale[0];
  types[0].inOut := SQL.InParam; types[0].name := "par1";
  stat := SQL.PrepareStatement(conn, str);
  SQL.BindParameters(stat, types, 1);
  SQL.FindField(stat.params, "par1", par1);
  In.LongInt(par1(SQL.IntField).i);
  SQL.Execute(stat);
  ShowResults(stat)
END ExecuteIntParam;

PROCEDURE ExecuteStringParam*;
  VAR stat: SQL.Statement; str: ARRAY 256 OF CHAR;
    types: ARRAY 1 OF SQL.ParamDesc; par1: SQL.Field;
BEGIN
  In.Open; In.String(str);
  types[0].oberonType := SQL.SQLVarChar; types[0].sqlType := mapType[1];
  types[0].precision := mapPrec[1]; types[0].scale := mapScale[1];
  types[0].inOut := SQL.InParam; types[0].name := "par1";
  stat := SQL.PrepareStatement(conn, str);
  SQL.BindParameters(stat, types, 1);
  SQL.FindField(stat.params, "par1", par1);
  In.String(par1(SQL.StringField).str);
  SQL.Execute(stat);
  ShowResults(stat)
END ExecuteStringParam;

PROCEDURE CreateLongData*;
  VAR r: Files.Rider; i: INTEGER;
BEGIN
  f := Files.New(""); Files.Set(r, f, 0);
  FOR i := 0 TO 19999 DO Files.Write(r, CHR((i MOD 32) + ORD(" "))) END ;
END CreateLongData;

PROCEDURE VerifyLongData(f: Files.File);
  VAR r: Files.Rider; ch: CHAR; i: INTEGER;
BEGIN
  Files.Set(r, f, 0);
  FOR i := 0 TO 19999 DO
    Files.Read(r, ch);
    IF ch # CHR((i MOD 32) + ORD(" ")) THEN 
      Out.String("wrong character in file");
      RETURN 
    END
  END
END VerifyLongData;

PROCEDURE CopyFile(fIn, fOut: Files.File);
  VAR r, w: Files.Rider; buffer: ARRAY 1024 OF CHAR; pos: LONGINT;
BEGIN
  Files.Set(r, fIn, 0); Files.Set(w, fOut, 0);
  REPEAT
    Files.ReadBytes(r, buffer, 1024); 
    Files.WriteBytes(w, buffer, 1024 - r.res)
  UNTIL r.eof;
END CopyFile;

PROCEDURE InsertLongData*;
  VAR types: ARRAY 2 OF SQL.ParamDesc; stat: SQL.Statement;
    i: INTEGER; idx, longData: SQL.Field;
BEGIN
  types[0].oberonType := SQL.OberonLongInt; types[0].sqlType := mapType[0];
  types[0].precision := mapPrec[0]; types[0].scale := mapScale[0];
  types[0].inOut := SQL.InParam; types[0].name := "idx";
  types[1].oberonType := SQL.SQLLVarChar; types[1].sqlType := mapType[2];
  types[1].inOut := SQL.InParam; types[1].name := "longData";
  types[1].precision := mapPrec[2]; types[1].scale := mapScale[2];
  stat := SQL.PrepareStatement(conn, 
    "INSERT INTO Bench3 (i, longData) values (?, ?)");
  SQL.BindParameters(stat, types, 2);
  SQL.FindField(stat.params, "idx", idx);
  SQL.FindField(stat.params, "longData", longData);
  FOR i := 0 TO 10 DO
    Out.Ln; Out.String("Inserting row number "); Out.Int(i, 0);
    idx(SQL.IntField).i := i;
    CopyFile(f, longData(SQL.FileField).f);
    SQL.Execute(stat);
    IF stat.ret # SQL.Success THEN RETURN END
  END
END InsertLongData;

PROCEDURE GetLongData*;
  VAR stat: SQL.Statement;
    i: INTEGER; idx, longData: SQL.Field;
BEGIN
  stat := SQL.PrepareStatement(conn, "SELECT * FROM Bench3");
  SQL.FindField(stat.results, "i", idx);
  SQL.FindField(stat.results, "longData", longData);
  SQL.Execute(stat);
  IF stat.ret = SQL.Success THEN
    i := 0;
    REPEAT
      SQL.Fetch(stat);
      IF stat.ret = SQL.Success THEN
        Out.Ln; Out.String("Fetching row number "); Out.Int(i, 0);
        IF idx(SQL.IntField).i # i THEN 
          Out.String("wrong index: "); Out.Int(idx(SQL.IntField).i, 0)
        END ;
        VerifyLongData(longData(SQL.FileField).f);
        INC(i)
      END
    UNTIL stat.ret # SQL.Success;
  END
END GetLongData;

BEGIN
  connStr := ""
END ODBCBench.



Christoph Steindl
Thu Jul 24 14:37:19 MET DST 1997