Displaying SQLite table via "Sql Table Control" inside Form
Posted: Wed Feb 11, 2015 5:20 pm
Hello,
This message is specially directed to:
- Helmut Zinn, author of BlackBox CPC-1.7-RC5 --> Module SqlControls
- Peter Cushnir and Ivan A. Kuzmitskiy, authors of the SQLite subsystem --> Module SQLiteDriver
First of all, excuse me for the length of the post.
I am using BlackBox CPC-1.7-RC5.
I want to access a SQLite table and display its rows in a Form via a "Sql Table Control", and I have found two problems:
1. The rows of the SQLite table are not displayed.
2. The "Sql Table Control" inside the form causes BB to trap when I open the form (after having saved and closed it).
To put the SQLite table inside a Form, I use the menu "Sql > Insert Table". This creates a "Sql Table Control" (SqlControls.Table). I edit its properties and link the new control to an interactor of type SqlDB.Table. (Also, to give scrollbars to the table, menu "Tools > Add Scroller")
To access the SQLite table via Sql subsystem, I copied things from modules SQLiteObx and DragoncityKarinReport:
The two problems are:
1. The rows of the SQLite table are not displayed.
To display the rows of the DB table via the "Sql Table Control" of the form, BB seems to call t.Read(i, ro) (t: SqlDB.Table; ro: SqlDB.Row). Note that SqlDB.Row is a very generic type. t.Read calls to SqlDB.ReadItem and this to SQLiteDriver.ReadVarString. An here is where I have the problem. SQLiteDriver.ReadVarString only works if the column read from Database is a String, but not if it is an integer, for example. Perhaps ReadVarString should make a type conversion and return always a string.
2. The "Sql Table Control" inside the form causes BB to trap when I open the form (after having saved and closed it).
This happens only with CPC-1.7-RC5 edition, and as far as I can see it is related to a change made to admits more than 40 columns. I have very little knowledge about how SqlControls module works. I only see that a variable t of type SqlControls.Table has a field named columns, and its value is cero when I save the form (and the control is externalized). Later when I open the form, the method SqlControls.Table.Internalize tries to allocate space to the dynamic arrays t.width and t.mode via NEW(t.width, t.columns), but t.columns is cero and traps. t.columns only seems to be incremented when the format (width o alignment) of a column is changed with the mouse (see method FormatOp.Do).
If I add the statement "c.columns := 10" to method StdDirectory.NewTable (see below) then the problem is partially solved, but a trap occurs if my SqlDB.Table (t.table) has more than 10 columns. Perhaps the two dynamic arrays t.width and t.mode, should be allocated like now (in Internalize), but also in procedure OpenLink, when t.table is set; there the number of columns of the new t.table could be compared with t.columns, and re-allocate the two arrays if necessary.
Regards,
Manuel
This message is specially directed to:
- Helmut Zinn, author of BlackBox CPC-1.7-RC5 --> Module SqlControls
- Peter Cushnir and Ivan A. Kuzmitskiy, authors of the SQLite subsystem --> Module SQLiteDriver
First of all, excuse me for the length of the post.
I am using BlackBox CPC-1.7-RC5.
I want to access a SQLite table and display its rows in a Form via a "Sql Table Control", and I have found two problems:
1. The rows of the SQLite table are not displayed.
2. The "Sql Table Control" inside the form causes BB to trap when I open the form (after having saved and closed it).
To put the SQLite table inside a Form, I use the menu "Sql > Insert Table". This creates a "Sql Table Control" (SqlControls.Table). I edit its properties and link the new control to an interactor of type SqlDB.Table. (Also, to give scrollbars to the table, menu "Tools > Add Scroller")
To access the SQLite table via Sql subsystem, I copied things from modules SQLiteObx and DragoncityKarinReport:
Code: Select all
MODULE PrivTestBd;
...
CONST
gMiBd = "C:\bla\bla\bla\segsenso.db3";
gDriver = 'SQLiteDriver';
gUser = 'any';
gPassword = 'any';
...
TYPE
TiposSensor* = RECORD
id*: INTEGER;
descri*: POINTER TO ARRAY OF CHAR;;
numord*: INTEGER
END;
...
VAR
gDB: SqlDB.Database;
t*: SqlDB.Table;
...
PROCEDURE Do*()
VAR res, k: INTEGER; r: TiposSensor; ro: SqlDB.Row;
BEGIN
SqlDB.OpenDatabase(gDriver, gUser, gPassword, gMiBd, SqlDB.sync, SqlDB.showErrors, gDB, res);
ASSERT(gDB # NIL, 20);
t := gDB.NewTable();
t.Exec("SELECT ID, DESCRI, NUMORD FROM TIPOS_SENSOR ORDER BY NUMORD");
ASSERT(t.res = 0, 21);
(*
FOR k := 0 TO t.rows - 1 DO
t.Read(k, r);
ASSERT((t.res = 0) OR (t.res = SqlDB.converted) OR (t.res = SqlDB.truncated), 22);
Log.String("r = "); Log.Int(r.id); Log.Tab; Log.String(r.descri); Log.Tab; Log.Int(r.numord); Log.Ln;
t.Read(k, ro);
ASSERT((t.res = 0) OR (t.res = SqlDB.converted) OR (t.res = SqlDB.truncated), 22);
Log.String("ro = " + ro.fields[0]); Log.Tab; Log.String(ro.fields[1]); Log.Tab; Log.String(ro.fields[2]); Log.Ln
END;
*)
END Do;
...
BEGIN
Do
End PrivTestBd.
1. The rows of the SQLite table are not displayed.
To display the rows of the DB table via the "Sql Table Control" of the form, BB seems to call t.Read(i, ro) (t: SqlDB.Table; ro: SqlDB.Row). Note that SqlDB.Row is a very generic type. t.Read calls to SqlDB.ReadItem and this to SQLiteDriver.ReadVarString. An here is where I have the problem. SQLiteDriver.ReadVarString only works if the column read from Database is a String, but not if it is an integer, for example. Perhaps ReadVarString should make a type conversion and return always a string.
Code: Select all
MODULE SQLiteDriver
PROCEDURE (t: Table) ReadVarString (row, column: INTEGER; OUT str: SqlDrivers.String);
VAR res: Value;
BEGIN
ASSERT(row >= 0, 20); ASSERT(row < t.rows, 21);
ASSERT(column >= 0, 22); ASSERT(column < t.columns, 23);
res := t.rset.Value(row, column);
IF res # NIL THEN
WITH res: TextValue DO
str := res.content; t.res := converted;
| res: IntValue DO <-- I added this
NEW(str, 40);
Strings.IntToString(res.content, str); t.res := converted;
| res: RealValue DO <-- I added this
NEW(str, 40);
Strings.RealToString(res.content, str); t.res := converted;
| res: BinaryValue DO <-- ...
...
ELSE
str := NIL; t.res := incompatible;
END
END
END ReadVarString;
2. The "Sql Table Control" inside the form causes BB to trap when I open the form (after having saved and closed it).
This happens only with CPC-1.7-RC5 edition, and as far as I can see it is related to a change made to admits more than 40 columns. I have very little knowledge about how SqlControls module works. I only see that a variable t of type SqlControls.Table has a field named columns, and its value is cero when I save the form (and the control is externalized). Later when I open the form, the method SqlControls.Table.Internalize tries to allocate space to the dynamic arrays t.width and t.mode via NEW(t.width, t.columns), but t.columns is cero and traps. t.columns only seems to be incremented when the format (width o alignment) of a column is changed with the mouse (see method FormatOp.Do).
If I add the statement "c.columns := 10" to method StdDirectory.NewTable (see below) then the problem is partially solved, but a trap occurs if my SqlDB.Table (t.table) has more than 10 columns. Perhaps the two dynamic arrays t.width and t.mode, should be allocated like now (in Internalize), but also in procedure OpenLink, when t.table is set; there the number of columns of the new t.table could be compared with t.columns, and re-allocate the two arrays if necessary.
Code: Select all
MODULE SqlControls
PROCEDURE (d: StdDirectory) NewTable (p: Controls.Prop): Views.View;
VAR c: Table;
BEGIN
NEW(c); OpenLink(c, p); InitStdProp(c.sprop);
c.columns := 10; <-- I added this, but it is not a real solution
NEW(c.width, 10); FillArray(c.width, 0, 10, defColW); (* extended on demand *)
NEW(c.mode, 10); FillArray(c.mode, 0, 10, center);
SetupTable(c);
RETURN c
END NewTable;
Manuel