MODULE SqlDrivers;
(**
project = "BlackBox"
organization = "www.oberon.ch"
contributors = "Oberon microsystems"
version = "System/Rsrc/About"
copyright = "System/Rsrc/About"
license = "Docu/BB-License"
changes = ""
issues = ""
**)
IMPORT Meta, Dates, Dialog;
CONST
noDriverMod = 1;
noDriverProc = 2;
wrongDriverType = 3;
connectionsExceeded = 4;
outOfTables = 5;
notExecutable = 6;
cannotOpenDB = 7;
wrongIdentification = 8;
tooManyBlobs = 9;
converted = 1;
truncated = 2;
overflow = 3;
incompatible = 4;
noData = 5;
TYPE
Driver* = POINTER TO ABSTRACT RECORD
blobStr-: ARRAY 8 OF CHAR;
open: BOOLEAN;
tables: INTEGER; (* number of currently open tables for this driver *)
END;
Table* = POINTER TO ABSTRACT RECORD
(** an open table must anchor its driver; a closed table must not anchor it **)
res*: INTEGER; (** sticky result, replaced by higher values only **)
open: BOOLEAN;
driver: Driver (* only used to prevent too early garbage collection of driver *)
END;
String* = POINTER TO ARRAY OF CHAR;
Blob* = POINTER TO RECORD
len*: INTEGER;
data*: POINTER TO ARRAY OF BYTE; (** not 0X terminated **)
next*: Blob
END;
DriverAllocator = PROCEDURE (id, password, datasource: ARRAY OF CHAR;
async, showErr: BOOLEAN; OUT d: Driver; OUT res: INTEGER);
(* Post: res = 0 <=> connection has started and should be completed later with EndOpen
res = 0 <=> d # NIL
~async & (res = 0) => d.Ready() *)
PROCEDURE (d: Driver) Ready* (): BOOLEAN, NEW, ABSTRACT;
PROCEDURE (d: Driver) EndOpen* (OUT res: INTEGER), NEW, ABSTRACT;
(** Pre: d.Ready() 20 **)
PROCEDURE (d: Driver) BeginExec* (IN statement: ARRAY OF CHAR; data: Blob;
async, showErrors: BOOLEAN; OUT res: INTEGER), NEW, ABSTRACT;
(** asynchronous execution is optional, a driver may legally execute synchronously if async is TRUE **)
(** Pre: statement # "" 20
no other execution started 21 **)
(** Post: res = 0 <=> execution has started and should be completed later with EndExec
~async => d.Ready() **)
PROCEDURE (d: Driver) EndExec* (VAR t: Table; OUT rows, columns, res: INTEGER), NEW, ABSTRACT;
(** Pre: execution must have been started successfully with BeginExec 20
d.Ready() 21 **)
(** Post: res = 0<=>(t # NIL) OR (rows = 0) & (columns = 0) **)
PROCEDURE (d: Driver) Commit* (accept: BOOLEAN; OUT res: INTEGER), NEW, ABSTRACT;
PROCEDURE (d: Driver) Cleanup-, NEW, EMPTY;
PROCEDURE (d: Driver) Close*, NEW;
BEGIN
IF d.open THEN
IF d.tables = 0 THEN
d.Cleanup (* release driver info *)
END;
d.open := FALSE;
END
END Close;
PROCEDURE (d: Driver) Init* (blobStr: ARRAY OF CHAR), NEW;
BEGIN
d.blobStr := blobStr$;
d.open := TRUE
END Init;
PROCEDURE (d: Driver) FINALIZE-;
BEGIN
d.Close
END FINALIZE;
PROCEDURE (t: Table) ReadInteger* (row, column: INTEGER; OUT val: INTEGER), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadReal* (row, column: INTEGER; OUT val: REAL), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadDate* (row, column: INTEGER; OUT val: Dates.Date), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadTime* (row, column: INTEGER; OUT val: Dates.Time), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadCurrency* (row, column: INTEGER; OUT val: Dialog.Currency), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadString* (row, column: INTEGER; OUT str: ARRAY OF CHAR), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadVarString* (row, column: INTEGER; OUT str: String), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadBlob* (row, column: INTEGER; OUT len: INTEGER;
OUT data: POINTER TO ARRAY OF BYTE), NEW, ABSTRACT;
(** Pre: row >= 0 20
row < rows 21
column >= 0 22
column < columns 23 **)
PROCEDURE (t: Table) ReadName* (column: INTEGER; OUT str: String), NEW, ABSTRACT;
(** Pre: column >= 0 20
column < columns 21 **)
PROCEDURE (t: Table) ReadType* (column: INTEGER; OUT str: String), NEW, ABSTRACT;
(** Pre: column >= 0 20
column < columns 21 *)
PROCEDURE (t: Table) Cleanup-, NEW, EMPTY;
PROCEDURE (t: Table) Close*, NEW;
BEGIN
IF t.open THEN
t.Cleanup; (* release table info *)
DEC(t.driver.tables);
IF (t.driver.tables = 0) & ~t.driver.open THEN
t.driver.Cleanup (* release driver info *)
END;
t.driver := NIL; (* allow for garbage collection of driver *)
t.open := FALSE
END
END Close;
PROCEDURE (t: Table) Init* (d: Driver), NEW;
BEGIN
ASSERT(d.open, 20);
t.driver := d; INC(d.tables);
t.open := TRUE
END Init;
PROCEDURE (t: Table) FINALIZE-;
BEGIN
t.Close
END FINALIZE;
PROCEDURE Open* (protocol, id, password, datasource: ARRAY OF CHAR;
async, showErrors: BOOLEAN; OUT d: Driver; OUT res: INTEGER);
VAR ok: BOOLEAN; m, p: Meta.Item; mod: Meta.Name;
v: RECORD (Meta.Value)
Open: DriverAllocator
END;
BEGIN
ASSERT(protocol # "", 20);
mod := protocol$; Meta.Lookup(mod, m); d := NIL; res := 0;
IF m.obj = Meta.modObj THEN
m.Lookup("Open", p);
IF p.obj = Meta.procObj THEN
p.GetVal(v, ok);
IF ok THEN
v.Open(id, password, datasource, async, showErrors, d, res);
ELSE res := wrongDriverType
END
ELSE res := noDriverProc
END
ELSE res := noDriverMod
END
END Open;
END SqlDrivers.