PSDN LIVE 2008 – OpenEdge, Sonic, 10.2A, ESB And More

July 8, 2008 · Filed Under Community · Comment 

PSDN LIVE 2008 is the premier North American conference for Progress users.  It’s being held in Boston September 7 – 9, 2008 at the Renaissance Boston Waterfront Hotel.

Topics will include: OpenEdge 10.1C and 10.2,  Sonic ESB, Structured Exception Handling in OpenEdge, O-O, new on-line database maintenance utilities, OpenEdge Architect and more.

We hope to see you there!

OpenEdge performance issues with Windows 2003 Server SP3 with Broadcom NICs

June 6, 2008 · Filed Under Performance Tuning, Reliability · 1 Comment 

Progress KBase entry P128141 may be of note to Progress users on Windows 2003 Server if you are running into intermittent performance problems.

Windows 2003 SP3 deploys with the incorrect version of a Broadcom NIC driver causing potentially severe performance problems. As many IBM blade centers ship with Broadcom NICs, and newer ones particularly with the NetExtreme II this kbase entry is worthy of review especially if your planning on going to SP3 of Windows 2003 Server or have and are noticing any performance degradation post patch.

Additionally the SP3 release of Windows Server 2003 releases an entirely new network protocol architecture which attempts to off load the TCP protocol stack (among others) onto the NIC. We are reviewing the effect of this on performance, particularly in regards to short lived TPC connections (WebSpeed, AppServer, HTTP, etc).

OpenEdge BUFFER-COPY from INT64 to INT Causes Index Corruption

March 24, 2008 · Filed Under Reliability · Comment 

A kbase entry P129814 regarding code that can cause database index corruption affects all V10 versions and service packs. The index corruption occurs when an INT64 field is buffer-copied to an INT field. Our testing shows that this also corrupts temp-table indexes and only manifests when the INT64 value is greater than MAX_INTEGER (about 2.1 billion).

What makes this more concerning is that the index corruption will go undetected until the record is accessed as the code below shows. In addition with shops migrating from 9 to 10 it is likely that INT64 and INT fields will co-exist for some time in the database and temp-table as new code and fields are added in the normal evolutionary process.

We recommend caution when writing code that mixes INT64 with INT fields.

Some simple code to manifest the bug:

/*
BUFFER-COPY from INT64 to INT Causes Index Corruption */
DEFINE TEMP-TABLE ttTest NO-UNDO FIELD iIdxNorm AS INTEGER
   FORMAT "z,zzz,zzz,zz9" INDEX idxPrime IS PRIMARY UNIQUE iIdxNorm ASC.
DEFINE TEMP-TABLE ttTest2 NO-UNDO
FIELD iIdxNorm AS INT64 INDEX idxPrime IS PRIMARY UNIQUE iIdxNorm ASC.
/* The value of the copy from int64 must be greater than MAX_INTEGER (32 bit)
(about 2.147 billion) to cause the error. */
DO cnt = 1 TO 2:
    CREATE ttTest2.
    ASSIGN iIdxNorm = 2400000000 + cnt.
END.
FOR EACH ttTest2:
    /* The first ttTest2 record creates a new ttTest. The 2nd ttTest2
    record is copied over the ttTest which modifies the existing ttTest
    index record and corrupts it. */
    BUFFER-COPY ttTest2 TO ttTest.
END.
/* No errors thrown to this point, the creates appear to have succeeded */
/* Attempting to access the ttTest index throws the error */
FOR EACH ttTest NO-LOCK:
    DISPLAY ttTest.iIdxNorm.
END.

OpenEdge 4GL Unknown Value and the LITERAL-QUESTION Attribute

December 21, 2007 · Filed Under Development · Comment 

Sometimes a cigar is just a cigar, and sometimes a question mark is just a question mark.

You frequently need to assign character values to a buffer-field. Sometimes that value may be a question mark.

        bh:BUFFER-FIELD('c1'):BUFFER-VALUE = '?'.

When you query the buffer-value, Progress reports that the value is unknown.

        MESSAGE
            bh:BUFFER-FIELD('c1'):BUFFER-VALUE = '?'
            bh:BUFFER-FIELD('c1'):BUFFER-VALUE = ?
            VIEW-AS ALERT-BOX.

If this behavior is not what you intended or you need to keep the Unknown Value distinct for a “?” character, then you have a bug in your program.

How do you get Progress to treat the “?” appropriately? The trick is the LITERAL-QUESTION attribute.

When LITERAL-QUESTION = FALSE, “?” and ? will both evaluate to the unknown value.
When LITERAL-QUESTION = TRUE, “?” is a question mark, and ? is the unknown value.

        bh:BUFFER-FIELD('c1'):LITERAL-QUESTION = TRUE.
        bh:BUFFER-FIELD('c1'):BUFFER-VALUE = '?'.
        MESSAGE bh:BUFFER-FIELD('c1'):BUFFER-VALUE = '?' VIEW-AS ALERT-BOX.

Sadly, there is no single-step way to make it always be true for all fields in a temp-table, but something like this may work for you:

        FUNCTION SetLiteralQuestion RETURNS LOGICAL
          ( INPUT bh AS HANDLE ):
          DEFINE VARIABLE i AS INTEGER NO-UNDO.
          IF NOT VALID-HANDLE(bh) THEN RETURN FALSE.
          IF bh:TYPE EQ 'TEMP-TABLE':U THEN bh = bh:DEFAULT-BUFFER-
        HANDLE.
          IF bh:TYPE NE 'BUFFER':U THEN RETURN FALSE.
          DO i = bh:NUM-FIELDS TO 1 BY -1:
            bh:BUFFER-FIELD(i):LITERAL-QUESTION = TRUE.
          END.
          RETURN TRUE.
        END FUNCTION.  /** SetLiteralQuestion() **/

You can then invoke the SetLiteralQuestion function using either a table-handle or a buffer-handle.

        SetLiteralQuestion(TEMP-TABLE ttFoo:HANDLE).
        SetLiteralQuestion(bh).
        SetLiteralQuestion(INPUT BUFFER customer:HANDLE).

Since this does some looping and other processing, you’ll want to make sure you’re not calling SetLiteralQuestion() in a loop.

A September ‘08 US Progress OpenEdge Technical Event? Your input needed!

December 21, 2007 · Filed Under Community · Comment 

Progress has three quick questions to ask you about a potential 1 1/2 day technical event in the US in September ‘08.    Here’s the e-mail that some of us have received:

Dear Valued Progress Customer,

Are you planning to attend Exchange 2008 in Paris?  If that’s not an option, what are your options?  Your feedback is important to us.  Please take a moment to complete a brief three-question survey that will help us determine the type and level of technical events we deliver to you in 2008.  Click here – http://www.progress.com/cgi-bin/survey.cgi/vote.w?boothId=398

If you are thinking such an event would be worthwhile or want to go on record on what coast you would prefer the event if it were held, click the above link and speak up.

PROGRESS TOOLS for YOUR PROGRESS TOOL BELT

December 3, 2007 · Filed Under Community · Comment 

Progress PSDN online: Is the Web Community used by Progress developers worldwide to find answers to technical questions. PSDN Online provides in-depth technical content – including white papers, articles, downloads, live Webinars with Progress experts, and code samples – on all Progress products and technologies.

The PEG: PEG’s mission is to enhance members’ collaborative and technical capabilities by providing autonomous communications, independent Progress oriented technical support, training, mentoring, collaboration and e-learning opportunities to the global Progress Software community.

PSDN Radio: Talking Progress brings you highlights from the floor at the Progress Exchange User Conferences. Throughout Exchange, presentations answer your questions during live interviews with key Progress technologists and users. Sponsored by Progress Software Developers Network (PSDN), all PSDN Radio recordings are available through this link.

PSDN News: PSDN News is a monthly e-mail newsletter highlighting technical content newly added to PSDN Online including product release announcements, technical white papers, articles, code examples, and technical events such as upcoming PSDN Webinars.

PSDN techTALK: Hosted by Marv Stone and Kim Mager, techTALK is a new monthly audio program geared for the technical Progress community. This program is an opportunity for Progress OED (for right now) to provide interesting technical information to both customers/partners and to the Progress technical community at large.

Customer Support: Progress customer support services are designed to provide customers and partners with world-class technical support.

Educational Services: Progress Education Services feature numerous award-winning training programs to provide you detailed instruction and hands-on experience in getting the most out of your Progress Software products. From mastering the fundamentals to learning the latest changes, there are a variety of training formats and courses to let you invest in yourself at your pace and skill level.

On-Demand Webinars: Webinars are development-oriented presentations meant to provide additional technical content to members. Delivered by Progress Development Engineers and Product Managers, each web seminar is one to two hours in length and includes time to take questions from the attendees.

Progress Exchange notes, presentations and more: The one place to stop to find and review past Progress Exchange conferences, notes and presentations.

OpenEdge ABL Phantom Error

November 30, 2007 · Filed Under Development, Reliability · Comment 

At Solvepoint we’ve coined a new term, the Phantom Error. What is a Phantom Error you ask? Well, it is an undesirable circumstance where the Progress VM decides to raise the error condition but leaves error-status:get-message() set to the empty string.

This , of course, can lead to a host of ugly sorts of bugs not the least of which is not having any idea where the error happened or why.

Here is a simple example that demonstrates a Phantom Error:

DEFINE NEW GLOBAL SHARED VARIABLE myHandle AS HANDLE NO-UNDO.
main: DO ON ERROR UNDO main, RETRY main:
  IF RETRY THEN do:
    MESSAGE RETURN-VALUE error-status:get-message(1) VIEW-AS ALERT-BOX.
    LEAVE main.
  END.
  RUN someProc IN myHandle.
END.

You’ll notice that both return-value and get-message(1) return blank.

If you happen to be in a terminal based procedure editor, however, you will receive the error message in the “message area” at the bottom. Unfortunately, this doesn’t do much good for server code.

As a consequence, server code will typically swallow these Phantom Errors at worst, or report the error out of context at best.

So, what can be done? Diligent error trapping is called for. Protect the code by always testing handles before using them.

Unfortunately, this isn’t the only type of code that will produce a Phantom Error. We will discuss other Phantom Errors under the Tag “Phantom Errors” in other posts.

Little-known OpenEdge Database _User Table Security Behavior

November 30, 2007 · Filed Under Development, Security · Comment 

Since it is not well known, I thought that I’d bring the following information to light regarding the OpenEdge _User Table Security Behaviour.

  1. OpenEdge Database security is implemented at the table level not the connection level. This means that, even with “blank user disabled”, a client may still connect. Security is only checked when that user attempts to access a table. Take careful note of the confirmation message:

    You are about to prevent the blank userid from
    accessing your database. Users who are not
    listed in the data security fields will not
    be able to compile procedures with this database
    .

    Notice it says nothing about connecting. Which brings us to point 2.

  2. Table level access is compiled into a .r. Therefore an _user without any access to that table may still run the .r successfully (even the client connected without a user id).
  3. The _user row may be modified or completely removed without affecting the running sessions (even after a STOP is raised).
  4. The _user password can only be changed when connected via that _user.
  5. The _user row , however, may be deleted by any session that has _can-delete on the _user table.
  6. The same _user row may then be created again with a different password (yikes!). (Still does not affect any running sessions).

Please keep these behaviors in mind as you plan your security strategy.

PS: Please be aware that Progress says it will be modifying security including adding run-time capabilities sometime in the near future.

OpenEdge ABL Memptr Pitfalls

November 30, 2007 · Filed Under Development, Reliability · Comment 

Memptr is a very powerful datatype in the ABL/4GL. It allows the programmer to store any type of data including binary. However, as with all dynamic objects in Progress, one must be careful when using it.

Pitfall number one: Scope. Memptrs do not follow the rules of scope to which 4GL programmers have become accustomed.

What does this mean? Why do I care? Well, I’ll tell you. Since Memptrs do not follow the rules of scope, when a variable holding a Memptr HANDLE goes out of scope the associated memory is NOT released. You care because if this happens you now have a memory leak. Every time your program is executed it will leak memory equal to the amount allocated to your memptr.

Pitfall number two is the allocation process. Probably 99% of code you find will do this:

/* define a memptr variable */
def var m as memptr no-undo.
/* Allocate the memory */
set-size(m) = 1024.
/* now go ahead and start using it... */
...

See anything wrong with the above? If not, don’t blame yourself. You are used to Progress doing this for you, but in this case, it does not. What am I referring to? You C programmers will know! The memory that has been allocated to m has not yet been “initialized”. This means the memory will contain random data: whatever happened to be in there before the allocation. If you are using put-string before your first get-string (without the numbytes parameter) then you have nothing to worry about since put-string automatically puts a NULL (0) as the next byte after the string and get-string will only read up to that NULL. But for other operations like put/get-byte or put/get-bytes or put/get-string with the numbytes parameter, grabbing random uninitialized data out of memory could bite you, so beware.

The final pitfall is also related to allocation. In your code, you may define a memptr at the beginning of a procedure and then use it in several places throughout the code. In each use you will want to allocate the appropriate amount of memory. So you may code something like this:

def var m as memptr no-undo.
set-size(m) = 128.
/* do stuff with it here... */
set-size(m) = 1024.
/* do other stuff with it here ... */
and so on...
/* now we clean up and return */
set-size(m) = 0.
return.

This looks great right? We are allocating and cleaning up just as we should, right? Well, yes and no. The pitfall is that the second set-size where we allocate 1024 bytes doesn’t actually allocate anything. It essentially does nothing at all. AND it does not raise an error condition. So now we have a potential bug if the code attempts to put more than 128 bytes into that memptr.

This is solved by setting the memptr to 0 first.

Moral of the story, memptrs need special care as they do not particpate in conventional scoping and cannot be resized until they are cleared.

Hope this helps to save you some time in your coding efforts!

OpenEdge Record Lock Anti-pattern

November 30, 2007 · Filed Under Development, Performance Tuning · Comment 

Everyone knows that if you need an exclusive lock on a database record in the 4gl you do this:

find customer exclusive-lock where customer.id eq 1 no-error.

However, this will not wait forever. It waits for lkwtmo, which defaults to 30 minutes, then raises the STOP condition. Well, what if you really want to wait longer than 30 minutes (or whatever lkwtmo is set to)? We have occasionally seen developers do this (gasp!):

find customer where customer.id eq 1 exclusive-lock no-wait no-error.
do while locked customer: 

  find customer where customer.id eq 1 exclusive-lock no-wait no-error.

end.

This will certainly work. However, if there is actually a lock on that row, this code will SLOW the database AND saturate the CPU of the client machine on which this code is running. That is an unbridled loop that will iterate thousands of times a second. Each iteration will cause the database to do work as well slowing all access (each lock attempt will show in promon as 1 Commit and as 3 DBRequests).
For example, on a 2.1ghz CPU that loop will iterate 40,000 times per second.

There are a number of good alternatives to the above design. One would be the following:

getLock: do on stop undo getLock, retry getLock:
  if retry then do:/* you may want to log something here 
                      or possibly put an upper limit on the wait time
                      by counting the number of times it hits this code
                      The below will cause an error to be returned after
                      60 minutes assuming the default lkwtmo */

     cnt = cnt + 1.
     if cnt eq 2 then return error "Unable to get a lock on customer".
  end.

  find customer exclusive-lock where customer.id eq 1 no-error.

end.

As you can see, it is much, much better to let the Progress VM deal with getting the lock in this scenario.

Next Page »