I'm a COBOL programmer , and my latest project is to connect a COBOL application to a SQLite3 database.
I have been following this guide, and their solution is exactly what I would need in my COBOL application. I have successfully managed to create, connect, insert data and close the database, but the problem arises when I try to select data from the database.
In the tutorial, they use a callback with double pointers.
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
My solution in COBOL is the following
WORKING-STORAGE SECTION.
*----------------------------------------------------------------*
01 sqlite3-db pointer.
01 err_msg pointer.
01 sqlite pointer.
01 res pointer.
01 notused pointer.
01 argc pic 99 comp-5.
01 argv pointer.
01 azColName pointer.
01 Writefunction-Ptr procedure-pointer.
procedure division.
set Writefunction-Ptr to entry "sqlite-callback".
*>Random code.
call "sqlite3_exec" using
by value sqlite3-db
by reference sqlQuery
by value Writefunction-Ptr
by value 0
by reference err_msg
returning rc
end-call
*>Random code.
stop run.
entry "sqlite-callback" using
by value notused
by value argc
by reference argv
by reference azColName.
display argc
goback.
Entry-Termination.
The callback works because it is called the number of rows that is returned from the database, and the integer argc contains the number of columns that the table contains.
The questions is:
Double pointers in COBOL, how are they represented? In my solution I declare a pointer and call the callback with "by reference" on the pointer. Don't know if this is the correct way to represent double pointers in COBOL?
How do I display the content of the azColName and argv, and not just the memory address which the pointer points to?
I hove now tried to use SET ADDRESS OF, but I still don´t get it to work. Must be something i´ve missed. My solution at the moment looks like:
WORKING-STORAGE SECTION.
01 argv pointer.
Linkage Section.
01 link-area pic x.
procedure division using link-area.
*> RANDOM CODE
set address of link-area to argv
call "sqlite3_exec" using
by value sqlite3-db
by reference z"SELECT * FROM Cars"
by value Writefunction-Ptr
by value 0
by reference err_msg
returning rc
end-call
*> RANDOM CODE
entry "sqlite-callback" using
by value notused
by value argc
by reference argv
by reference azColName.
display argc.
if address of link-area not = null
display "Contents of new argv: " link-area
else
display "empty"
end-if
goback.
Entry-Termination.
The result I get is that the if statement is always false, so the string "empty" is displayed. But still argc is set to the number of colums in the table.
The working solution:
WORKING-STORAGE SECTION.
01 argv.
03 firstColumn pointer.
03 secondColumn pointer.
03 thirdColumn pointer.
01 azColName pointer.
01 argc pic 99 comp-5.
01 notused pointer.
01 Writefunction-Ptr procedure-pointer.
*-----------------------------------------------------------------
Linkage Section.
01 Cars_Id pic 9(2).
01 Cars_Name pic X(20).
01 Cars_Price pic 9(10).
/-----------------------------------------------------------------
procedure division.
//code
set Writefunction-Ptr to entry "sqlite-callback".
initialize sqlQuery
move z"SELECT * FROM Cars;" to sqlQuery
call "sqlite3_exec" using
by value sqlite3-db
by reference sqlQuery
by value Writefunction-Ptr
by value 0
by reference err_msg
returning rc
end-call
//code
stop run.
entry "sqlite-callback" using
by value notused
by value argc
by reference argv
by reference azColName.
set address of Cars_Id to firstColumn
set address of Cars_Name to secondColumn
set address of Cars_Price to thirdColumn
display Cars_Id "|" Cars_Name "|" Cars_Price
goback.
Entry-Termination.
We really need to know the compiler you are using.
Your SET statement is in the wrong place. argv
only has an address when the ENTRY
is called. Before the entry is called, it will be binary zero, or some unpredictable rubbish.
If you move the SET to after the ENTRY, you should then be able to use the value of LINK-AREA. argv
will still only be an address, but LINK-AREA (give it a better name, please) will be pointing to that address, so define it as argv should be defined, and then LINK-AREA can be used to get the actual content of argv.
When using BY REFERENCE
the compiler generates code to pass a pointer with the address of the data-item.
On the PROCEDURE DIVISION USING
or ENTRY USING
the item should also be BY REFERENCE and the compiler generates code to map your LINKAGE SECTION definition to the address passed.
This is similar if you use BY CONTENT
, but the compiler takes a copy of the data within your program and passes a pointer which references that instead. On the USING of the PROCEDURE DIVISION or ENTRY that is still defined as BY REFERENCE.
With BY VALUE
the compiler "passes" the actual value, although there are limits, either those specified in the Standard or extensions to the Standard with your actual compiler. The USING of the PROCEDURE DIVISION or ENTRY should specify BY VALUE as well.
On all the USINGs, BY REFERENCE/CONTENT/VALUE are propagated, you don't need to specify BY at all if all are the same and you want BY REFERENCE, it is the default.
If you "pass" a POINTER
(USAGE POINTER
) then you can access the data pointed to by using SET ADDRESS OF
. The SET ADDRESS OF item must be in the LINKAGE SECTION
.
You can also use an implicit pointer with SET ADDRESS OF. SET ADDRESS OF a TO ADDRESS OF b will change the address mapped in the LINKAGE SECTION to the address of b, an item that is defined somewhere in your program's DATA DIVISION
(any SECTION other than the FILE SECTION
).
If you want to see the data pointed-to by a POINTER, define an item which has the correct size and type and use SET ADDRESS OF item TO pointer-name.
The POINTER can of course be pointing to a simple data-item or a group data-item (a structure).
All items in the LINKAGE SECTION must have an address before they are referenced. Those on a USING are given addressability by the compiler (and the compiler assumes that the correct number of addresses/items are passed). All other LINKAGE SECTION items must have addressability established by SET ADDRESS OF or by passing ADDRESS OF in the USING of a CALL
and having the CALLed program set the address.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With