Using dynamic cursors
Implementing a dynamic dialog based on the database schema.
Using column information from base.SqlHandle
To write generic code accessing a database, implement the dynamic dialog with field names and
types coming from a base.SqlHandle
cursor.
The following code example builds a list of fields based on the database table passed as first parameter.
The function scans the result set column names and types of the
base.SqlHandle
cursor, to build the list of field definitions, that can then be used for the dynamic dialog
creation:TYPE t_dd_fields DYNAMIC ARRAY OF RECORD
name STRING,
type STRING
END RECORD
FUNCTION build_field_list(dbtable STRING, fields t_dd_fields) RETURNS ()
DEFINE h base.SqlHandle
DEFINE x INTEGER
LET h = base.SqlHandle.create()
CALL h.prepare("SELECT * FROM " || dbtable)
CALL h.open()
CALL h.fetch()
CALL fields.clear()
FOR x=1 TO h.getResultCount()
LET fields[x].name = h.getResultName(x)
LET fields[x].type = h.getResultType(x)
END FOR
END FUNCTION
Code example
The following code example implements a DISPLAY ARRAY
dynamic dialog by using a
base.SqlHandle
object:
The form.per file:
LAYOUT
TABLE table1
{
[c11 |c12 ]
[c11 |c12 ]
[c11 |c12 ]
[c11 |c12 ]
}
END
END
ATTRIBUTES
EDIT c11 = FORMONLY.pkey, TITLE="Num";
EDIT c12 = FORMONLY.name, TITLE="Name";
END
INSTRUCTIONS
SCREEN RECORD sr(FORMONLY.*);
END
The program code:
TYPE t_dd_fields DYNAMIC ARRAY OF RECORD
name STRING,
type STRING
END RECORD
MAIN
DEFINE fields t_dd_fields
DEFINE d ui.Dialog
DEFINE t STRING
CONNECT TO "test1"
OPEN FORM f1 FROM "form"
DISPLAY FORM f1
CALL create_database_table()
CALL build_field_list("tab1",fields)
LET d = ui.Dialog.createDisplayArrayTo(fields, "sr")
CALL d.addTrigger("ON ACTION accept")
CALL d.addTrigger("ON ACTION cancel")
CALL fill_array("SELECT * FROM tab1 ORDER BY name",fields,d)
WHILE (t := d.nextEvent()) IS NOT NULL
CASE t
WHEN "BEFORE DISPLAY"
CALL d.setSelectionMode("sr", 2)
CALL d.setCurrentRow("sr",1)
WHEN "ON ACTION cancel"
LET int_flag = TRUE
EXIT WHILE
WHEN "ON ACTION accept"
CALL d.accept()
END CASE
END WHILE
END MAIN
FUNCTION create_database_table() RETURNS ()
WHENEVER ERROR CONTINUE
DROP TABLE tab1
WHENEVER ERROR STOP
CREATE TABLE tab1 ( pkey INTEGER, name VARCHAR(30) )
INSERT INTO tab1 VALUES ( 101, 'aaaa' )
INSERT INTO tab1 VALUES ( 102, 'bbbbbbb' )
INSERT INTO tab1 VALUES ( 103, 'ccccccccc' )
END FUNCTION
FUNCTION build_field_list(dbtable STRING, fields t_dd_fields) RETURNS ()
DEFINE h base.SqlHandle
DEFINE x INTEGER
LET h = base.SqlHandle.create()
CALL h.prepare("SELECT * FROM " || dbtable)
CALL h.open()
CALL h.fetch()
CALL fields.clear()
FOR x=1 TO h.getResultCount()
LET fields[x].name = h.getResultName(x)
LET fields[x].type = h.getResultType(x)
END FOR
END FUNCTION
FUNCTION fill_array(sqlcmd STRING, fields t_dd_fields, d ui.Dialog) RETURNS ()
DEFINE h base.SqlHandle
DEFINE r, x INTEGER
LET h = base.SqlHandle.create()
CALL h.prepare(sqlcmd)
CALL h.open()
LET r = 0
WHILE TRUE
CALL h.fetch()
IF sqlca.sqlcode == NOTFOUND THEN
EXIT WHILE
END IF
CALL d.appendRow("sr")
CALL d.setCurrentRow("sr",r:=r+1)
FOR x=1 TO fields.getLength()
CALL d.setFieldValue(fields[x].name, h.getResultValue(x))
END FOR
END WHILE
END FUNCTION