SQL cursor management
This topic describes differences between I4GL and Genero BDL in SQL cursor management.
OPEN USING followed by FOREACH
FOREACH
instruction had no
USING
clause to pass SQL parameters to the prepared statement. SQL Parameters could
be specified in a OPEN cursor-name USING
variable-list
instruction preceding the FOREACH
instruction:PREPARE st1 FROM "SELECT * FROM tab WHERE col>?"
DECLARE cu1 CURSOR FOR st1
OPEN cu1 USING var
FOREACH cu1 INTO rec.*
DISPLAY rec.*
END FOREACH
This feature is supported by Genero Business Development Language, but can lead to defects with
some versions of the Informix database client. Review
your code to avoid the OPEN
statement by moving the USING
clause
to the FOREACH
instruction.
With Genero BDL, avoid having an OPEN ... USING
instruction.
DECLARE might throw unexpected errors
DECLARE ... CURSOR
instrucion does not throw an SQL error
when using a table that does not exist. With Genero BDL, the DECLARE
instruction
will fail:DECLARE c1 CURSOR FOR SELECT * FROM tt1
CREATE TEMP TABLE tt1 ( pkey INTEGER, name VARCHAR(50) )
Such code needs to be fixed: An SQL table must exist before it is used.
MAIN
DATABASE test1
CALL declare_cursor()
CALL create_table()
CALL open_cursor()
END MAIN
FUNCTION create_table()
CREATE TEMP TABLE tt1 ( pkey INTEGER, name VARCHAR(50) )
END FUNCTION
FUNCTION declare_cursor()
DECLARE c1 CURSOR FOR SELECT * FROM tt1
END FUNCTION
FUNCTION open_cursor()
OPEN c1
END FUNCTION
To fix the above code, switch the lines calling the create_table()
and
declare_cursor()
functions.
FREE before DECLARE
The IBM Informix
4GL compiler accepts the FREE
instrucion before the DECLARE
instruction, for example:
FREE c_cust
DECLARE c_ust CURSOR FOR SELECT * FROM customer
With Genero BDL, the above code will produce a compiler error.
This use case is not common and must be avoided. The DECLARE
cursor instruction
must appear first in the module, before any other cursor instruction such as OPEN
,
CLOSE
, FETCH
.
FUNCTION c_cust_open()
OPEN c_cust
END FUNCTION
FUNCTION c_cust_close()
CLOSE c_cust
END FUNCTION
FUNCTION c_cust_free()
FREE c_cust
END FUNCTION
FUNCTION c_cust_declare()
DECLARE c_cust CURSOR FOR SELECT * FROM customer
END FUNCTION
Such source code must be fixed to move the c_cust_declare
function at the
top.
The CURSOR_NAME() function
With IBM Informix 4GL, the CURSOR_NAME()
function is available, to map the 4GL cursor
name to the the underlying cursor identifier procuded by the compiler, which is the real cursor id
used by the Informix database server. This function is typically used in UPDATE / DELETE
WHERE CURRENT OF
. See Informix 4GL documentation for more details.
MAIN
DEFINE cn VARCHAR(50)
DATABASE test1
DECLARE mycursor CURSOR FOR SELECT * FROM customer
LET cn = CURSOR_NAME("mycursor")
DISPLAY cn
END MAIN
Genero BDL does not support the CURSOR_NAME()
function: It is useless, because
the runtime mangles cursor names automatically.
The scope of an SQL cursor name or prepared statement name is the module. The underlying database client API does not know about modules: The scope of cursor names is the SLQ connection. While I4GL compiler mangles cursor names and statement names at compile time, FGL handles this by mapping module cursor names to unique program-wide cursor names at runtime.
Note that if you do not use IMPORT FGL
and strick -Wimplicit
compilation options of Genero fglcomp, since CURSOR_NAME()
is a
function, it will not be detected at compile time, and it usage will only be detected with a runtime
error when this function is called.
FUNCTION cursor_name(name STRING) RETURNS STRING
RETURN name
END FUNCTION