progress 4gl :i want to avoid error messages while running the program - progress-4gl

DEFINE TEMP-TABLE ttservice NO-UNDO
FIELD ad-num AS CHARACTER
INDEX ttprimary AS UNIQUE ad-num .
ASSIGN ttservice.ad-num = vehicles.ad-num NO-ERROR
In this, how to avoid error messages when i am adding duplicate records,
situation is:
when i try to add the duplicate records in temp table it doesnot accept,it is ok ,but it display error messages while running a program,iwant to suppres that error messages.,and avoid the duplicate adding records

You can test for the existence of a duplicate key before you try to create it.
(Filling in the blanks.)
DEFINE TEMP-TABLE ttservice NO-UNDO
FIELD ad-num AS CHARACTER /* you have a "num" field defined as character? that's misleading */
INDEX ttprimary AS UNIQUE ad-num .
for each vehicle no-lock: /* perhaps ad-num is non-unique in the vehicle table? */
find ttservice where ttservice.ad-num = vehicles.ad-num no-error.
if available ttservice then
do:
message "oops!". /* or whatever it is you want when a duplicate occurs... */
end.
else
do:
create ttservice.
ASSIGN ttservice.ad-num = vehicles.ad-num.
end.
end.

Here's another way to get unique ad-num values from the vehicles table:
DEFINE TEMP-TABLE ttservice NO-UNDO
FIELD ad-num AS CHARACTER
INDEX ttprimary AS UNIQUE ad-num .
FOR EACH vehicles NO-LOCK
BREAK BY vehicles.ad-num:
IF FIRST-OF(vehicles.ad-num) THEN
DO:
CREATE ttservice.
ASSIGN ttservice.ad-num = vehicles.ad-num.
END.
END.

Two valued answers have already been added by great professionals but i would like to add mine with minor changes.
def TEMP-TABLE ttservice NO-UNDO
FIELD iservid AS INT
INDEX tt-primary AS UNIQUE iservid.
VEHICLELOOP:
for each vehicles use-index <index-name>
NO-LOCK:
IF CAN-FIND(first ttservice
where ttservice.iservid = vehicles.iservid)
THEN
NEXT VEHICLELOOP.
ELSE DO:
create ttservice.
ASSIGN ttservice.iservid = vehicles.iservid.
END. /* VEHICLELOOP */

So I read the answers and think they're sufficient to fix your particular issue. But here's the general way of thinking you should assume when coding for Progress OpenEdge:
Adding no-error to statements (when they allow it) will "suppress errors", though sometimes they're inevitable and suppressing does no good to the stability of your application, always think of treating them (and displaying errors is a part of this).
Whether you choose to check for existence of a record prior to creation or just set your query to not iterate for undesired (repeated) records is up to you. I advise you to check for performance with different approaches (especially in doing a for each for a large table) to see which one is more satisfactory.
So here's my personal suggestion:
for each vehicles no-lock:
if can-find(first ttService where ttService.ad-num = vehicles.ad-num) then
next.
create ttService.
assign ttService.ad-num = vehicles.ad-num no-error.
if error-status:error then
message "Something went horribly wrong:" + error-status:get-message(1)
view-as alert-box error.
end.
In my example above, the error will only be shown if the assign actually fails. It is not likely to happen, I just wanted to show how the usage of no-error (and its treatment) works.
Anyway, hope it helps!

Related

OpenEdge Progress 4GL Query returns (MISSING) after % sign

DEFINE TEMP-TABLE tt_pay_terms NO-UNDO
FIELD pt_terms_code LIKE payment_terms.terms_code
FIELD pt_description LIKE payment_terms.description.
DEFINE VARIABLE htt AS HANDLE NO-UNDO.
htt = TEMP-TABLE tt_pay_terms:HANDLE.
FOR EACH platte.payment_terms
WHERE (
active = true
AND system_id = "000000"
)
NO-LOCK:
CREATE tt_pay_terms.
ASSIGN
pt_terms_code = payment_terms.terms_code.
pt_description = payment_terms.description.
END.
htt:WRITE-JSON("FILE", "/dev/stdout", FALSE).
I have written this query and it returns data like this
[pt_terms_code] => 0.4%!N(MISSING)ET46
[pt_description] => 0.4%! (MISSING)DAYS NET 46
While I believe (from using a SQL query) that the data should be
0.4%45NET46
0.4% 45 DAYS NET 46
I'm making an assumption that the % is probably some special character (as I've run into similar issues in the past). I've tried pulling all the data from the table, and I get the same result, (ie, not creating a temp table and populating it with all the only the two fields I want).
Any suggestions around this issue?
I'm still very new to 4gl, so the above query might be terribly wrong. All comments and criticisms are welcome.
I suspect that if you try this:
FOR EACH platte.payment_terms NO-LOCK
WHERE ( active = true AND system_id = "000000" ):
display
payment_terms.terms_code
payment_terms.description
.
END.
You will see what the query actually returns. (WRITE-JSON is adding a layer after the query.) You will likely discover that your data contains something unexpected.
To my eye the "%" looks more like formatting -- the terms are likely 0.4%.
You then seem to have some issues in the contents of the description field. My guess is that there was a code page mismatch when the user entered the data and that there is gibberish in the field as a result.

What is the code to create unposted (upost-order) orders in progress 4gl language?

What is the code to create unposted (upost-order) orders in progress 4gl language?
This is the code to find upost orders.
FIND upost-order WHERE
upost-order.company = company AND
upost-order.order-number = order.order-number
NO-ERROR.
IF NOT AVAILABLE upost-order THEN
FIND upost-order WHERE
upost-order.company = company AND
upost-order.order-number =
STRING(INTEGER(SUBSTRING(order.order-number,3,6)))
NO-LOCK NO-ERROR.
I'll assume you mean you want to know how to create a new record for this entity.
That would be
DO TRANSACTION:
CREATE upost-order.
/* Now if you want to assign arbitrary values to the key, */
ASSIGN upost-order.company = company /* supposing you want to create for the same one you found */
upost.order-number = cOrderNumber NO-ERROR. /* Whatever character value you want to assign to the number. */
/* If you want to ask the user to input the values, on a GUI environment you could do this, instead of the ASSIGN above*/
UPDATE upost-order NO-ERROR.
/* You'll notice I used no-error in both. Now if an error happened, display it to the user */
IF ERROR-STATUS:ERROR THEN DO:
MESSAGE ERROR-STATUS:GET-MESSAGE(1) VIEW-AS ALERT-BOX.
UNDO, LEAVE.
END.
END.
Since I'm addressing more your question on how to create, of course the code above is not thorough or at its best. You could have more than one message, and in a transaction block, I'd probably name it, and prompt for the fields before creating and assigning, thus keeping the transaction at minimal time and as little as possible.
I hope this helps with your question.

how to replace all the email id records with progress 4gl

The problem here is I want to update the email ids, I want to update like user#abc.com to user#xyz.com
I have selected all the email ids like this,
for each table where
table.email matches "*" + "#abc.com" + "*" no-lock :
Display
I can't use replace function, since each email ids will be of different length.
Is it possible to change email ids like this ? Please share with me.
Replacing exactly "abc" with "xyz" is done like this:
/* You need to change NO-LOCK to EXCLUSIVE-LOCK if you want to update or change! */
FOR EACH table WHERE table.email MATHES"*" + "#abc.com" + "*" EXCLUSIVE-LOCK:
ASSIGN
table.email = REPLACE(table.email, "#abc.com", "#xyz.com").
END.
But maybe you need to elaborate your question or is this all you want to do?
About performance
This query wont be very fast. Matches does not utilize any indices so the entire table will be scanned.
On later versions of Progress you can add a TABLE-SCAN option. This will increase speed but not by a lot. If you do this you will have to remove the MATCHES expression in the query and do like this:
FOR EACH table EXCLUSIVE-LOCK TABLE-SCAN:
IF table.email MATCHES etcetera
END.
END.
If this is a one time thing to fix e-mail addresses perhaps it doesn't need to be that fast? If not I suggest you add a logical field to the table (table.fixed) and create an index with the field in it. Then you can very fast go through all not fixed records.
I tried myself, and I wrote like this, and it worked.
def var cmail1 as char.
def var cmail2 as char.
assign
cmail1 = "#abc.com"
cmail2 = "#xyz.com".
for each table where
exclusive-lock :
Assign
table.email = REPLACE(table.email, cmail1, cmail2).
but the performance is low. If you any alternate for this, please post.

Progress 4GL BUFFER-COPY FAILS

DO ON ENDKEY UNDO, LEAVE:
FIND FIRST STUDENT NO-LOCK WHERE ST-ID = "TEST" NO-ERROR.
IF AVAILABLE STUDENT THEN
DO:
CREATE SCHOOL no-error.
BUFFER-COPY STUDENT EXCEPT STUDENT.Location
SCHOOL ASSIGN SCHOOL.Location = "MY LOCATION" NO-ERROR.
IF ERROR-STATUS:ERROR THEN
DO:
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
MESSAGE
" Error no " ERROR-STATUS:GET-NUMBER(i)
" txt: " ERROR-STATUS:GET-MESSAGE(i) VIEW-AS ALERT-BOX.
STOP.
END.
END.
END.
END.
This query is working fine but some time it was creating Empty Record. buffer-copy through some error that why it create empty record but i am not able verify the error because code was happen in LIVE. please help me how to FIX the problem. what type of error buffer-copy will through. 1000 times working fine 1 time it will FAIL. i know this is data defect but how to FIX. otherwise what type of errors BUFFER-COPY through.
Since you really don't know what errors occur - you need to start there.
To track general errors after a NO-ERROR statement you can do something like:
IF ERROR-STATUS:ERROR THEN DO:
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
/* Replace MESSAGE with some kind of logging */
MESSAGE
"Error number " i
" error no " ERROR-STATUS:GET-NUMBER(i)
" txt: " ERROR-STATUS:GET-MESSAGE(i) VIEW-AS ALERT-BOX.
END.
END.
Once you have the specific error number(s) you can search the Progress Knowledge Base for more information.
I would write the code as follow. If you use no-error always handle the error. When assigning/buffer copy check if no error then do a validate to confirm that triggers fire correctly. The error handling code can be put in its own procedure and then just called every time you wish to process error messages. (amended it a bit as I would write it, I do not always trap all errors, but error handling depends on various things, but it is a good way during testing to make sure code is setup correctly. Afterwards can remove error handling where not needed before deploying.)
FIND FIRST STUDENT NO-LOCK WHERE ST-ID = "TEST" NO-ERROR.
IF AVAILABLE STUDENT THEN
DO:
CREATE SCHOOL.
BUFFER-COPY STUDENT EXCEPT STUDENT.Location
TO SCHOOL ASSIGN SCHOOL.Location = "MY LOCATION"
NO-ERROR.
IF ERROR-STATUS:ERROR THEN
DO:
/* insert error handling - for example as as per #Jensd */
/* this is in case there is something wrong with buffer copy */
/* maybe a required field is left empty? */
END.
ELSE DO:
VALIDATE SCHOOL NO-ERROR. /* good idea as it raises any issues with triggers */
IF ERROR-STATUS:ERROR THEN
DO:
/* insert error handling - for example as as per #Jensd */
END.
END.
END.
I will not make a buffer-copy from one to other table stright, you might have index issues as i think you are having.
Better define a temp-table like the target table.
Then make a buffer copy to the temp-table.
Set the rigth key into the temp-table.
Then make a buffer copy from the temp table with the right key fields to the target table.
Try as follow:
Define temp-table t-school like school.
find first student no-lock and so on.
buffer-copy student to t-school.
Assign t-school.location = "whatever".
buffer-copy t-school to school.
Voila!
One possible way to debug the issue is to use "Recent Messages" under Help in AppBuilder provided you are able to run the code directly from it.

Dynamically reference temp-table column values in Progress

I am using Progress 4GL
I have a spreadsheet of data containing several columns called data1....50.
I have created a temp table which holds all the values.
Now I would like to loop through the temp table columns and do various calculations
So I need something like this:
for each record loop thru cols_in_temp_table .
if col_value = "XYZ" then
do calcs and stuff
end.
So how do I reference the temp_table cols ?
Ok, didn't resolve the original query, but found a workaround. Split the data up and put into separate tables, long winded, but does the trick.
Depending on your version, this is one way to do it:
DEFINE VARIABLE h-cols AS HANDLE NO-UNDO.
h-cols = tt-cols:BUFFER-HANDLE.
FOR EACH tt-cols
NO-LOCK:
IF h-cols::col-name = "some value" THEN
RUN do-something.
END.
For versions that can't do the "::" operator, do this:
FOR EACH tt-cols
NO-LOCK:
IF h-cols::buffer-field("col-name"):buffer-value = "some value" THEN
RUN do-something.
END.