Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

COBOL / DB2 cursor help please

139 views
Skip to first unread message

razor

unread,
Aug 29, 2014, 6:32:24 AM8/29/14
to
I have migrated a system from Object COBOL v4.0 to Netexpress 5.1. I am having a problem with some cursor processes.

Originally the system used to have ISAM files and was converted to use DB2. Now the way this was done, to me, seems a complete waste of time as all that was done is the START statements were replaced by OPEN CURSOR statements and the READ NEXT by FETCH statements. All ok and it works.

Each table has it's own file handler program that handles all of the input / output for one table at a time.

Now in Netexpress I have some loops that process table A using aforementioned cursors and for each entry another table is processed using a different cursor. When completion of the inner loop is reached the program then attempts to read the next record from the outer loop. In Netexpress I receive a 501 error indicating that the cursor is not open.

Now I'm not looking for anybody to start debugging the code as I'm quite sure it's not that. It feels to me as though Netexpress is not allowing me to have more than one cursor open at a time, although I can't find any compiler setting for this.

Does anybody know if there is a setting I need?

Many thanks for reading

Ian

Wiggy

unread,
Aug 29, 2014, 8:26:03 AM8/29/14
to
Hi Ian,

You may be best off speaking with Micro Focus Customer Support, but I'm
curious as to how you're accessing DB2 - either via ODBC through
OpenESQL (using the SQL directive) or using the DB2 ECM (using the DB2
directive), or precompiling with IBM's command line precompiler (db2
prep...) and compiling the output?

Could you provide a list of directives that you're using please?

If you're using OpenESQL, enabling ODBC tracing should show whether the
cursor has been erroneously closed.

thanks,
SimonT.

docd...@panix.com

unread,
Aug 29, 2014, 11:05:54 AM8/29/14
to
In article <d5969355-daaf-4abe...@googlegroups.com>,
razor <razor...@gmail.com> wrote:

[snip]

>Originally the system used to have ISAM files and was converted to use
>DB2. Now the way this was done, to me, seems a complete waste of time as
>all that was done is the START statements were replaced by OPEN CURSOR
>statements and the READ NEXT by FETCH statements.

This won't help you with your particular difficulty... but I cannot recall
the number of DB2 systems I've worked on where this can be seen. The
company started with flat files, then moved to indexed datasets and then
got dragged, kicking and screaming, into DB2.

Since the Most Senior Programmers were proficient with indices - and the
Most Senior Programmers had the most say in the architecture of the DB2
installation - then the architecture resembled that with which they were
most comfortable.

DD

Bill Gunshannon

unread,
Aug 29, 2014, 11:22:34 AM8/29/14
to
In article <ltq4si$m0p$1...@reader1.panix.com>,
Well, that last COBOL gig I did a couple years ago had gone through this
same thing. Was using VSAM and then databases came into vogue. Brought
in contractors to do the conversion. A simple read of the code they wrote
easily shows that the contractors had no idea how to program COBOL for
database use and the result is some really bad programs that perform poorly,
don't really do what the user wants and are nearly impossible to fix. But,
no problem, just blame COBOL like everyone else does.

Some of them actually do nothing but read the database data into flat files
and then process the files. Try working with that that when the database
structure changes and you need things like UNIONS and JOINS with new tables
that weren't even thought of at the time of the conversion.

bill

--
Bill Gunshannon | de-moc-ra-cy (di mok' ra see) n. Three wolves
bill...@cs.scranton.edu | and a sheep voting on what's for dinner.
University of Scranton |
Scranton, Pennsylvania | #include <std.disclaimer.h>

docd...@panix.com

unread,
Aug 29, 2014, 11:33:55 AM8/29/14
to
In article <c6bk5q...@mid.individual.net>,
Bill Gunshannon <bill...@cs.uofs.edu> wrote:
>In article <ltq4si$m0p$1...@reader1.panix.com>,
> docd...@panix.com () writes:
>> In article <d5969355-daaf-4abe...@googlegroups.com>,
>> razor <razor...@gmail.com> wrote:
>>
>> [snip]
>>
>>>Originally the system used to have ISAM files and was converted to use
>>>DB2. Now the way this was done, to me, seems a complete waste of time as
>>>all that was done is the START statements were replaced by OPEN CURSOR
>>>statements and the READ NEXT by FETCH statements.
>>
>> This won't help you with your particular difficulty... but I cannot recall
>> the number of DB2 systems I've worked on where this can be seen. The
>> company started with flat files, then moved to indexed datasets and then
>> got dragged, kicking and screaming, into DB2.
>>
>> Since the Most Senior Programmers were proficient with indices - and the
>> Most Senior Programmers had the most say in the architecture of the DB2
>> installation - then the architecture resembled that with which they were
>> most comfortable.
>>

[snip of similar experience]

>Some of them actually do nothing but read the database data into flat files
>and then process the files. Try working with that that when the database
>structure changes and you need things like UNIONS and JOINS with new tables
>that weren't even thought of at the time of the conversion.

It may not have been available when it was needed... but DFSORT now
supports some options that are utterly stunning.

DD

razor

unread,
Aug 29, 2014, 11:58:39 AM8/29/14
to
Hi Simon

I think I will try that.

These are the Project properties within Netexpress:

%FILENAME COBIDY(%TARGETDIR) WB3 WB CSI ANIM EDITOR(MF2) ENSUITE(3) CHANGE-MESSAGE"0837 N 0011 N" /CONSTANT VN(1700) /CONSTANT GOGO(0) REMOVE "SELF" DB2(DBMAN=DB2) DB2(BIND=%BASENAME.BND) DB2(DB=HMS1700) SPZERO STICKY-LINKAGE OOCTRL(-G+N-P+Q-W);

I'm afraid it's not ESQL unfortunately.

The COBOL code is very, very complicated. It's nothing like any COBOL I've maintained in 30 years experience. Basically, the program reads a list of Sites and for each Site it then reads all location codes for THAT Site. In between, the program allocates memory to store these location entries. I have actually narrowed down the problem to some code that is executed for each Site.

INVOKE OSMEMORY "newtable" USING
BY VALUE LENGTH OF WS-LOC-KEY
BY VALUE WS-OBJ-DIALOG
BY REFERENCE WS-OSMEMORY-ADDRESS
BY REFERENCE WS-OBJ-SLLIST
RETURNING WS-OSMEMORY-REPLY.

OSMEMORY.CBL is a class program that starts doing things like:

METHOD-ID. "newtable".

LOCAL-STORAGE SECTION.

01 WS-REPLY USAGE LONG.

LINKAGE SECTION.

01 LK-ENT-SIZE USAGE LONG.
01 LK-OBJ-PARENT USAGE OBJECT REFERENCE.
01 LK-MEM-POINTER USAGE POINTER.
01 LK-OBJ-MEMORY USAGE OBJECT REFERENCE.
01 LK-REPLY USAGE LONG.

INVOKE SUPER "new" RETURNING LK-OBJ-MEMORY.

INVOKE LK-OBJ-MEMORY "initializetable" USING
BY VALUE LK-ENT-SIZE
BY VALUE WS-ENT-TABLEMAX
BY VALUE LK-OBJ-PARENT
BY REFERENCE LK-MEM-POINTER
RETURNING LK-REPLY.

IF LK-REPLY NOT = WS-OSCLASS-OK
INVOKE LK-OBJ-MEMORY "finalize" USING
BY REFERENCE LK-OBJ-MEMORY
RETURNING WS-REPLY
END-IF.

EXIT METHOD.

-----------------------


METHOD-ID. "initializetable".

LOCAL-STORAGE SECTION.

LINKAGE SECTION.

01 LK-ENT-SIZE USAGE LONG.
01 LK-ENT-MAX USAGE LONG.
01 LK-OBJ-PARENT USAGE LONG.
01 LK-MEM-POINTER USAGE POINTER.
01 LK-REPLY USAGE LONG.

PROCEDURE DIVISION USING
BY VALUE LK-ENT-SIZE
BY VALUE LK-ENT-MAX
BY VALUE LK-OBJ-PARENT
BY REFERENCE LK-MEM-POINTER
RETURNING LK-REPLY.

MULTIPLY LK-ENT-SIZE BY LK-ENT-MAX GIVING WS-ENT-MEMSIZE.
COMPUTE WS-ENT-MEMSIZE =
((WS-ENT-MEMSIZE / WS-ENT-INCREMENT) + 1).
MULTIPLY WS-ENT-MEMSIZE BY WS-ENT-INCREMENT
GIVING WS-ENT-MEMSIZE.

INVOKE SELF "initialize" USING
BY VALUE WS-ENT-MEMSIZE
BY VALUE WS-OSCLASS-FALSE
BY VALUE LK-OBJ-PARENT
BY REFERENCE WS-ENT-CURRPTR
RETURNING WS-REPLY.
IF WS-REPLY NOT = WS-OSCLASS-OK
MOVE WS-REPLY TO LK-REPLY
EXIT METHOD
END-IF.

MOVE WS-TYPE-MEMORY TO WS-TYPE.

MOVE LK-ENT-SIZE TO WS-ENT-ENTSIZE.
MOVE LK-ENT-MAX TO WS-MAX-RECNO.

MOVE 0 TO WS-ENT-COMMITED
WS-ENT-RECSINENQ
WS-ENT-NEXTREC.

SET LK-MEM-POINTER TO WS-ENT-CURRPTR.

MOVE WS-OSCLASS-OK TO LK-REPLY.

EXIT METHOD.

END METHOD "initializetable".

*>*********************************************
*> Instance method - initialize * PRIVATE
*>*********************************************

METHOD-ID. "initialize".

LOCAL-STORAGE SECTION.

LINKAGE SECTION.

01 LK-MEM-SIZE USAGE LONG.
01 LK-MEM-COMMIT USAGE LONG.
01 LK-OBJ-PARENT USAGE OBJECT REFERENCE.
01 LK-MEM-POINTER USAGE POINTER.
01 LK-REPLY USAGE LONG.

PROCEDURE DIVISION USING
BY VALUE LK-MEM-SIZE
BY VALUE LK-MEM-COMMIT
BY VALUE LK-OBJ-PARENT
BY REFERENCE LK-MEM-POINTER
RETURNING LK-REPLY.

MOVE "VirtualAlloc" TO WS-LAST-FUNCTION.

IF LK-MEM-COMMIT = WS-OSCLASS-TRUE
MOVE WS-MEMRESCOMMIT TO WS-MEMFLAGS
ELSE
MOVE WS-MEMRESERVE TO WS-MEMFLAGS
END-IF.

CALL OSAPI "VirtualAlloc" USING
BY VALUE 0
BY VALUE LK-MEM-SIZE
BY VALUE WS-MEMFLAGS
BY VALUE WS-MEMREADWRITE
RETURNING LK-MEM-POINTER.
IF LK-MEM-POINTER = NULL
CALL OSAPI "GetLastError" RETURNING WS-LAST-ERROR
MOVE WS-OSCLASS-FAILED TO LK-REPLY
EXIT METHOD
END-IF.

MOVE WS-TYPE-MEMORY TO WS-TYPE.

MOVE LK-MEM-SIZE TO WS-MEM-SIZE.
SET WS-MEM-POINTER TO LK-MEM-POINTER.

SET WS-OBJ-PARENT TO LK-OBJ-PARENT.

IF WS-OBJ-PARENT NOT = NULL
INVOKE WS-OBJ-PARENT "register" USING
BY VALUE SELF
RETURNING WS-REPLY
END-IF.

MOVE 0 TO WS-LAST-ERROR.
MOVE WS-OSCLASS-OK TO LK-REPLY.

EXIT METHOD.

END METHOD "initialize".

---------------------------------

Hey, I have 20,000,000 lines of code just like this to maintain on my own. :-)

I'm afraid the OO stuff here is so over my head without anybody there to ask. All long gone.

Ian

docd...@panix.com

unread,
Aug 29, 2014, 9:49:40 PM8/29/14
to
In article <d8864fc4-2dea-4345...@googlegroups.com>,
razor <razor...@gmail.com> wrote:

[snip]

>In between, the program allocates memory to store these
>location entries.

'(T)he program allocates memory'? This sounds like someone is trying to
make COBOL do something that COBOL was not designed to do. GETMAIN was
developed for the same reason (CICS is a patch on the operating system
more than an extension of the language) but if a COBOL load module needed
more core - and *any* programmers worth their salaries didn't need more
than 16K! - then the Systems jockies would modify the Prod JCL and
increase the REGION= parameter.

If you have COBOL that's allocating and freeing memory then you are ripe
for things like memory leaks and core-hogging.

[snip of horrors]

>Hey, I have 20,000,000 lines of code just like this to maintain on my own. :-)

Unless the money earned is needed for medical procedures - such as
radiation therapy for one of the more virulent forms of cancer - then
continuing to work with this code will almost guarantee that the money
earned *will be* needed for medical procedures, such as the treatment of
ulcers.

>I'm afraid the OO stuff here is so over my head without anybody there to
>ask. All long gone.

On the brighter side... there's no one to second guess your work!

DD

Pete Dashwood

unread,
Sep 3, 2014, 10:52:25 PM9/3/14
to
razor wrote:
> Hi Simon
>
> I think I will try that.

Yes, Micro Focus support would be the best place to go.

>
> These are the Project properties within Netexpress:
>
> %FILENAME COBIDY(%TARGETDIR) WB3 WB CSI ANIM EDITOR(MF2) ENSUITE(3)
> CHANGE-MESSAGE"0837 N 0011 N" /CONSTANT VN(1700) /CONSTANT GOGO(0)
> REMOVE "SELF" DB2(DBMAN=DB2) DB2(BIND=%BASENAME.BND) DB2(DB=HMS1700)
> SPZERO STICKY-LINKAGE OOCTRL(-G+N-P+Q-W);

This is why I don't really use Micro Focus; far too much is NOT "under the
covers"... Having said that, they DO give you the option of working at a
very low level if that is what you want to do.

I'm taking a break from real work for an hour or so and I decided to see if
I can help with some of this... I have annotated comments ([Pete] [/Pete])
which might help you with understanding how it works.

>
> I'm afraid it's not ESQL unfortunately.
>
> The COBOL code is very, very complicated.

"complicated" is, of course, relative. In the code you posted I see nothing
"complicated"...

>It's nothing like any COBOL
> I've maintained in 30 years experience.

That's because you didn't pick up the OO skills you would need for this,
along the way. Never mind, MOST COBOL guys didn't... It was much easier to
pretend that OO was an unnecessary re-invention of structured modular
programming (it isn't...) or to decide it was a fad that would quickly pass.
(The whole world runs on it now...)


>Basically, the program reads
> a list of Sites and for each Site it then reads all location codes
> for THAT Site. In between, the program allocates memory to store
> these location entries.

There, you see, you're not as bad as you think you are... you sussed what it
does pretty well... :-)


> I have actually narrowed down the problem to
> some code that is executed for each Site.
>
> INVOKE OSMEMORY "newtable" USING
> BY VALUE LENGTH OF WS-LOC-KEY
> BY VALUE WS-OBJ-DIALOG
> BY REFERENCE WS-OSMEMORY-ADDRESS
> BY REFERENCE WS-OBJ-SLLIST
> RETURNING WS-OSMEMORY-REPLY.
>
> OSMEMORY.CBL is a class program that starts doing things like:

Yes, it is a Class which, like most Classes, has methods (behaviours).
Sadly, someone (probably a sometime Assembler programmer) has decided to
have a go at doing stuff that really should be left to the OS.

"Why did you decide to write a class that re-invents what the OS already
does very well?"

"Because I can...
(Besides, I really wanted to be a system programmer and they're making me
maintain this bloody boring COBOL so I need to have a bit of fun...)"

>
> METHOD-ID. "newtable".
>
> LOCAL-STORAGE SECTION.
>
> 01 WS-REPLY USAGE LONG.
>
> LINKAGE SECTION.
>
> 01 LK-ENT-SIZE USAGE LONG.
> 01 LK-OBJ-PARENT USAGE OBJECT REFERENCE.
> 01 LK-MEM-POINTER USAGE POINTER.
> 01 LK-OBJ-MEMORY USAGE OBJECT REFERENCE.
> 01 LK-REPLY USAGE LONG.
>
> INVOKE SUPER "new" RETURNING LK-OBJ-MEMORY. [Pete] This is a
> low level constructor that inherits from the base class (SUPER is the
> Class that this Class derives from) and creates a new instance of the
> Class. It returns a pointer to the area of memory where the new instance
> resides. From then on, you can reference LK-OBJ-MEMORY as if it was the
> Class, so you can invoke methods on it and get/set properties for
> it.[/Pete]
>
> INVOKE LK-OBJ-MEMORY "initializetable" USING [Pete] As noted,
> having got an instance of the table it invokes a method to initialize it.
> Note that it returns a return code (LK-REPLY) that states whether the
> initialization was successful or not. If it wasn't, it invokes the
> finalize method to destroy the instance, release the resources and make
> them available for garbage collection.[/Pete]
> BY VALUE LK-ENT-SIZE
> BY VALUE WS-ENT-TABLEMAX
> BY VALUE LK-OBJ-PARENT
> BY REFERENCE LK-MEM-POINTER
> RETURNING LK-REPLY.
>
> IF LK-REPLY NOT = WS-OSCLASS-OK
> INVOKE LK-OBJ-MEMORY "finalize" USING
> BY REFERENCE LK-OBJ-MEMORY
> RETURNING WS-REPLY
> END-IF.
>
> EXIT METHOD.
>
> -----------------------
>
>
> METHOD-ID. "initializetable". [Pete] Don't get sidetracked
> by the details unless you HAVE to. It is enough to know that the
> "initializetable" method initializes the memory claimed by the Class
> instance.[/Pete]
> CALL OSAPI "VirtualAlloc" USING [Pete] Oh, Great! Let's use
> the OS API functions to explicitly manage the memory allocation, now that
> we have set up all the parameters for it...
The system is using "initialize" to allocate memory dynamically and
"initializetable" to create the table it needs in the newly acquired
space.[/Pete]
> BY VALUE 0
> BY VALUE LK-MEM-SIZE
> BY VALUE WS-MEMFLAGS
> BY VALUE WS-MEMREADWRITE
> RETURNING LK-MEM-POINTER.
> IF LK-MEM-POINTER = NULL
> CALL OSAPI "GetLastError" RETURNING WS-LAST-ERROR
> MOVE WS-OSCLASS-FAILED TO LK-REPLY
> EXIT METHOD
> END-IF.
>
> MOVE WS-TYPE-MEMORY TO WS-TYPE.
>
> MOVE LK-MEM-SIZE TO WS-MEM-SIZE.
> SET WS-MEM-POINTER TO LK-MEM-POINTER.
>
> SET WS-OBJ-PARENT TO LK-OBJ-PARENT.
>
> IF WS-OBJ-PARENT NOT = NULL
> INVOKE WS-OBJ-PARENT "register" USING
> BY VALUE SELF
> RETURNING WS-REPLY
> END-IF.
>
> MOVE 0 TO WS-LAST-ERROR.
> MOVE WS-OSCLASS-OK TO LK-REPLY.
>
> EXIT METHOD.
>
> END METHOD "initialize".

[Pete] All of the above is actually quite straightforward to an OO
programmer. (And it isn't badly written...) My criticism would be that there
was no need to do it in the first place, but the author would counter, that,
as COBOL does not provide for dynamic memory and table allocation, there
was... (Really, it is just a lot more "fun" (for some people...) to do
something low-level. And if it is "complicated"... well, that works towards
ensuring job security... :-) )

There are a few fundamentals you need to keep in mind while you are dealing
with this stuff.... ( Due to time/space restrictions I can't give you a
brain dump on OO programming here, but I can give you enough to help you
out) COBOL examples below are a guide and may not work exactly with your
specific COBOL implementation. (I believe they will be close, but I have
neither time nor inclination to check the exact details of NetExpress
syntax...)

1. The structures you are dealing with consist of: "Classes".

Classes can "contain" (actually "implement" is a better word):

1. Methods. (These are the behaviours that the Class can exhibit. They are
like procedures, but there is a little more to it than that because it isn't
just strictly procedural. You can think of Methods as what the Class
"knows"...)
2. Interfaces. (These are portals that the Class provides for communication
with the outside world. A "method signature" (the name of the method plus
any parameters it accepts and returns) is an example of an interface.
Classes are sealed off from the outside world (encapsulated) and can ONLY be
manipulated using their provided interfaces.
3. Properties. (Sometimes called "attributes". These are data fields that
the Class makes public, through an interface which allows you to get and set
them. Sometimes the behaviour of a method can be modified if a certain
property is set before invoking the method.)
4. Events. (These are the events that the Class is interested in and will
respond to. Could be a mouse click or may be nothing at all...)

2. A Class cannot be executed. You cannot even execute its methods or check
its properties. You have to create an INSTANCE of it first. (This is just
like making a copy of it and then doing everything with the copy. ) This is
such a fundamental thing that most classes will either inherit or provide
their own "constructor" method. The constructor creates an instance of the
class and returns to you an address to it. From then on, you reference this
returned address as if it were the Class itself. The returned address is
called an "OBJECT REFERENCE" and an object reference represents an instance
of a Class. The phrase "instance of a Class"can be replaced with "OBJECT".
Sadly, some programmers use these terms loosely and it can lead to
confusion. Classes and objects are intimately related, but they are NOT the
same thing...

3. In most programming languages you reference things by using the object
followed by a dot. ("dog.sit()" would invoke the "sit" METHOD of the "dog"
object. The parentheses tell us this is a method, and would contain
parameters if the sit method required them. "dog.collartype" would return
the "collartype" PROPERTY and tell us whether it was leather or chain or
whatever . In OO COBOL the otherwise standard dot notation is not used.
COBOL qualification is used instead, so the two examples become"

INVOKE dog "sit" USING/RETURNING etc. and... MOVE "collartype" OF "dog"
TO WS-COLLAR... etc. (You could also access the "collartype" property with:
INVOKE dog "GET" using "collartype" RETURNING WS-COLLAR ...)

The above is a very quick look around the ballpark and the most-used
features.

Don't worry too much about things like "instantiation" (creating an instance
of - returns an object reference), "polymorphism" (allowing a method to
have more than one signature by providing different interfaces to the same
method, and the other "Computer Science" stuff.

And don't try to read the details of EVERY method... Understand that methods
are encapsulated. They do what they do; get your head around the function
they perform and visualize them as little LEGO blocks...

It is perfectly safe to take a copy of a method then fiddle with it.
Encapsulation ensures that you can't directly destroy anything up or
downstream. If your change doesn't work then replace the original.
>
> ---------------------------------
>
> Hey, I have 20,000,000 lines of code just like this to maintain on my
> own. :-)
>
> I'm afraid the OO stuff here is so over my head without anybody there
> to ask. All long gone.
>

If you have any further specific questions on OO programming, post them here
and I'll try to respond. (I don't come here so often these days but I'll do
what I can.)

Pete.
--
"I used to write COBOL...now I can do anything."


docd...@panix.com

unread,
Sep 4, 2014, 10:16:12 AM9/4/14
to
In article <c6q2f5...@mid.individual.net>,
Pete Dashwood <dash...@removethis.enternet.co.nz> wrote:
>razor wrote:

[snip]

>> OSMEMORY.CBL is a class program that starts doing things like:
>
>Yes, it is a Class which, like most Classes, has methods (behaviours).
>Sadly, someone (probably a sometime Assembler programmer) has decided to
>have a go at doing stuff that really should be left to the OS.
>
>"Why did you decide to write a class that re-invents what the OS already
>does very well?"
>
>"Because I can...
>(Besides, I really wanted to be a system programmer and they're making me
>maintain this bloody boring COBOL so I need to have a bit of fun...)"

It seems that those pesky Space Aliens are, once again, stealing my
brain-waves and beaming them into unsuspecting skulls on the other side of
the world. Contrast the abovequoted text with
<https://groups.google.com/forum/#!original/comp.lang.cobol/IqP2e-hxlA4/amXSWF0qhFYJ>

--begin quoted text:

>In between, the program allocates memory to store these
>location entries.

'(T)he program allocates memory'? This sounds like someone is trying to
make COBOL do something that COBOL was not designed to do. GETMAIN was
developed for the same reason (CICS is a patch on the operating system
more than an extension of the language) but if a COBOL load module needed
more core - and *any* programmers worth their salaries didn't need more
than 16K! - then the Systems jockies would modify the Prod JCL and
increase the REGION= parameter.

--end quoted text

... and notice the similarities between 'should be left to the OS' and
'something that COBOL was not designed to do' along with mention of 'a
systems programmer' and 'Systems jockies'.

DD

Pete Dashwood

unread,
Sep 4, 2014, 8:09:38 PM9/4/14
to
I read and smiled at your previous post Doc.

The OO COBOL code posted is, indeed, doing pretty much what used to be
achieved with GETMAIN on mainframes (and not just for CICS, either... I
worked in places where we called an Assembler subroutine to do it as a
matter of course...)

There is very little new under the sun.

iruddo...@gmail.com

unread,
Sep 25, 2014, 6:35:55 AM9/25/14
to
Thank you for your message and help Pete. Appreciated.

Suffice to say, I still have an issue. Knowing MF support, this is just too big a problem to give to them. It would take me so long to produce a cut-down version of the system/program to give to them that, for now, I will attempt to resolve myself (along with your help of course).

So, the problem I have is that I have a loop which processes a cursor and for each entry then processes another cursor. In between, memory is allocated in order to store the entries. It is this memory allocation routine that is causing the original cursor to be closed. I have proved this by commenting out the memory allocation/update routine and the two cursors work correctly.

The WIN API call it performs is VirtualAlloc. I've googled it and on it's own it doesn't mean a lot to me. It isn't anything new to the system and is functioning correctly in OC v4.0.

One thing I did notice, but it is probably a red herring is that the CBL_ALLOC_MEM routine now has changed parameters within Netexpress. Now whilst I am not using these routines I do wonder if there is something different within Netexpress regarding memory allocation.

When running through Netexpress I do get messages in the 'debug messages' tab such as:

HEAP[runw.exe]:
HEAP: Free Heap block 2f69b90 modified at 2f6ad2c

I google this and it appears the system is doing something wrong with memory but I don't understand what that is. I'm starting to suspect it is this that is 'breaking' my cursor.

I'm an apps developer. If you want VAT or National Insurance split by cost-centre based on if there is a full moon or not, then I'm your man. But allocating memory????? Heaps???? How did I get here?

I think I need to try and replicate in a very small program and ship off to Micro Focus.

Razor

Pete Dashwood

unread,
Sep 26, 2014, 5:37:59 AM9/26/14
to
iruddo...@gmail.com wrote:
> Thank you for your message and help Pete. Appreciated.
>
> Suffice to say, I still have an issue. Knowing MF support, this is
> just too big a problem to give to them. It would take me so long to
> produce a cut-down version of the system/program to give to them
> that, for now, I will attempt to resolve myself (along with your help
> of course).
>
Good for you!

Happy to help.


> So, the problem I have is that I have a loop which processes a cursor
> and for each entry then processes another cursor. In between, memory
> is allocated in order to store the entries. It is this memory
> allocation routine that is causing the original cursor to be closed.
> I have proved this by commenting out the memory allocation/update
> routine and the two cursors work correctly.
>
> The WIN API call it performs is VirtualAlloc. I've googled it and on
> it's own it doesn't mean a lot to me. It isn't anything new to the
> system and is functioning correctly in OC v4.0.
>
> One thing I did notice, but it is probably a red herring is that the
> CBL_ALLOC_MEM routine now has changed parameters within Netexpress.
> Now whilst I am not using these routines I do wonder if there is
> something different within Netexpress regarding memory allocation.

If it works correctly in Open COBOL but not in NE, then the way that NE is
implementing the low level functions must be different. But that doesn't
mean it is "wrong"... see below.
>
> When running through Netexpress I do get messages in the 'debug
> messages' tab such as:
>
> HEAP[runw.exe]:
> HEAP: Free Heap block 2f69b90 modified at 2f6ad2c
>
> I google this and it appears the system is doing something wrong with
> memory but I don't understand what that is. I'm starting to suspect
> it is this that is 'breaking' my cursor.
>
> I'm an apps developer. If you want VAT or National Insurance split by
> cost-centre based on if there is a full moon or not, then I'm your
> man. But allocating memory????? Heaps???? How did I get here?

You are echoing what most of us have felt at some point in our careers.

Don't decide you can't solve it; it is called "being extended" :-)
>
> I think I need to try and replicate in a very small program and ship
> off to Micro Focus.

Pretty easy to replicate: Allocate some memory. Free it. Then reference it
again.

That is what is wrong.

It would be embarrassing to ship something off to them suggesting a problem
with their system software, if it is actually an application logic
problem...

One of your cursors is referencing the allocated memory after it has been
"released" (technically, "deleted")


This message occurs when you have attempted to reference memory which has
already been freed.

First step: find where the dynamically allocated memory (table) is freed. Is
it at the end of the inner cursor processing? If it is, and the outer cursor
is still running, it will go to try again and raise precisely this error.
Logical EOF on the inner cursor needs to raise logical EOF on the outer
cursor and only when the outer cursor has recognized it is finished should
the memory be de-allocated. (once you have located the memory de-allocation
move it outside of both the cursor loops...).

Get your head around this, then look through the code again (trace it with
the COBOL Animator and step each instruction from the time you allocate the
memory and get a returned pointer, to the time when that pointer is either
set to null or deleted through an API call. (in other words, it is no longer
referenced. Implicitly or explicitly.) then see where it is being
referenced again. Also, try checking every reference to the field returned
from the memory allocation (the instance of the table).

It has to be a subtle, but findable, logic error.

You can do this and you can find it.

Don't get sidetracked or overwhelmed because it is territory you're not used
to.

Hang on to the fundamental concept: "Memory is being referenced after it has
been freed." You know the "names" of the table references and the address
returned by the memory allocation so you can watch them.

The memory in question is either freed explicitly by your application
program or freed implicitly by the garbage collector because nothing is
using it any more. Either way, you need to find where that happens, then
look for the application reference to it which follows that.

It really is that basic.

Let us know how you get on...
0 new messages