Geeting Values from Browse and Create Temp Table - progress-4gl

I have a dynamic Browser.It will populate values dynamicaly based on some input given through UI.
Now i wan to get the values displayed in that Browse and make a temp-table for that.
please help

To add new values you first insert a new row into the temp-table and then arrange to update that row. The following code is ugly but it may serve to illustrate:
define temp-table tt_simple no-undo
field id as integer
field name as character
index id_idx is unique id
.
define variable r as integer no-undo.
define query q for tt_simple.
define browse b query q display tt_simple.name with 5 down.
form b with frame easy.
form
tt_simple.name
with
frame updEasy
column 30
row 1
.
procedure newRecord:
define input parameter initName as character no-undo.
create tt_simple.
assign
r = r + 1
id = r
name = initName
.
end.
run newRecord( "abc" ).
run newRecord( "xyz" ).
on "enter" of b in frame easy do:
apply "entry" to tt_simple.name in frame updEasy.
return no-apply.
end.
on "insert-mode", "CTRL-I" anywhere do:
run newRecord( "" ).
close query q.
open query q for each tt_simple.
get last q.
apply "entry" to tt_simple.name in frame updEasy.
return no-apply.
end.
on "go" of tt_simple.name in frame updEasy do:
tt_simple.name = self:screen-value.
close query q.
open query q for each tt_simple.
apply "entry" to b in frame easy.
return no-apply.
end.
on "value-changed" of b in frame easy do:
display tt_simple.name with frame updEasy.
end.
open query q for each tt_simple.
enable tt_simple.name with frame updEasy.
enable b with frame easy.
apply "entry" to b in frame easy.
wait-for "close" of this-procedure.

Related

Access table content from a return table function

I have a probleme where a user have to lookup a trajectory to go from point A to point B.
What i have to do is look up a way to go from point A to B via other points, like maybe A>C>B.
To do this i basically take the first point which is A and then check all the available point to go towards from this point.
Ex : maybee from point A, i can go to C, D and E
Then i look if one of the result is equal to B. If not, i then call this function again from the next points, in this case : C then D then E and this recursively until i find a way to go from A to B
I first made a recursive function function(A, B) that returns a table od points i've been too like explained above but the problem was, the point A could go to C and C could go to A so it was recursively looping from A to C and then C to A over and over again. So now i have to find a way to check if a point have alreay been travelled to.
so my function returns table(start, finish). If i to the trajectory A>C>D>E>B for example, then in the table i'll have the lines :
START FINISH
A > C
C > D
D > E
E > B
now I have NO IDEA how to check in this table that i'm returning to see if a value is in this table or not example : to check on the third iteration if i've already been in point C so that i don't go from D to C.
I'm really sorry if this is not clear enough, it's not super clear in my head also.
create or replace function findConnection(starting, ending) RETURNS TABLE (v_starting, v_ending)
as $$
declare
temp record;
begin
for temp in select start, end from trip where start = starting
loop
if temp.end = ending then
v_starting := temp.start;
v_ending := temp.end;
else
/* here i should check if i've already been threw this point
something like : if select * from table where v_starting = temp.end != null then */
v_starting := temp.start;
v_ending := temp.end;
return next;
findConnection(temp.end, ending); /*recursive call for the next points*/
end if;
end loop;
end;
language plpgsql;

How to get the field name dynamically and update it to main table in progress

Program:It is a just maintenance program, in this one it displays the Item Code in one frame and it prompt for the input. if you enter the item code it has to displays what are the blank fields for that record in pt_mstr and display in one frame(No need to display all blank fields, just first 4 or 5 fields enough). and also in that frame only if user want to update it update directly to main table pt_mstr.
What i tried is, i just write the code for getting blank fields using buffer handle and after that i create one temp table and displaying the fields, i strucked there itself, i am unable to update fields.
My code:
/*Sample Item master Maintenance Program*/
/* DISPLAY TITLE */
{us/mf/mfdtitle.i "3+ "}
DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE VARIABLE hField AS HANDLE NO-UNDO.
define variable fldnm as character extent 10 no-undo.
define temp-table tt_temp no-undo
field tt_part like pt_part
field field1 as char extent 10.
form
pt_part colon 25
with frame a side-labels width 80.
setFrameLabels(frame a:handle).
/* DISPLAY */
view frame a.
repeat with frame a:
prompt-for pt_part
editing:
/* FIND NEXT/PREVIOUS RECORD */
{us/mf/mfnp.i pt_mstr pt_part "pt_mstr.pt_domain = global_domain and pt_part" pt_part pt_part pt_part }
if recno <> ? then
do:
display pt_part.
find pt_mstr where pt_part = input pt_part and pt_domain=global_domain no-lock no-error.
ASSIGN hBuffer = BUFFER pt_mstr:HANDLE.
empty temp-table tt_temp.
j = 1.
DO i = 1 TO 10:
ASSIGN hField = hBuffer:BUFFER-FIELD(i).
IF ((hField:BUFFER-VALUE = "" )) THEN
do:
/* message hField:NAME "test" view-as alert-box.*/
find first tt_temp where tt_part = pt_part no-lock no-error.
if not avail tt_temp then
do:
create tt_temp.
assign
tt_part = pt_part
field1[j] = hField:NAME.
j = j + 1.
end.
else do:
assign
field1[j] = hField:NAME.
j = j + 1.
end.
end.
end.
end.
for each tt_temp:
display field1[1] field1[2] field1[3] field1[4].
end.
end.
end.
Are you sure you need your temp-tables to do this? I've created an example using only the actual table (but created a fake temp-table instead). You would have to look into data error handling, data validation, transaction, locking etc before putting this into production of course.
/*First we need some fake data */
DEFINE TEMP-TABLE ttMockedData NO-UNDO
FIELD id AS INTEGER
FIELD dataName AS CHARACTER FORMAT "x(8)"
FIELD dataType AS CHARACTER FORMAT "x(8)"
FIELD dataDescrioption AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE iId AS INTEGER NO-UNDO.
DEFINE VARIABLE iSearch AS INTEGER NO-UNDO LABEL "Search".
PROCEDURE createData:
DEFINE INPUT PARAMETER pcName AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcType AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER pcDesc AS CHARACTER NO-UNDO.
iId = iId + 1.
CREATE ttMockedData.
ASSIGN
ttMockedData.id = iId
ttMockedData.dataName = pcName
ttMockedData.dataType = pcType
ttMockedData.dataDesc = pcDesc.
END PROCEDURE.
RUN createData("Test 1", "TESTTYPE", "A TEST").
RUN createData("Test 2", "", "ANOTHER TEST").
RUN createData("", "TESTTYPE 2", "").
RUN createData("4", "", "").
/* Program starts here */
updating:
REPEAT:
UPDATE iSearch WITH FRAME x0.
IF iSearch > 0 THEN DO:
FIND FIRST ttMockedData NO-LOCK WHERE ttMockedData.id = iSearch NO-ERROR.
IF NOT AVAILABLE ttMockedData THEN DO:
MESSAGE "Not found" VIEW-AS ALERT-BOX ERROR.
RETURN ERROR.
END.
ELSE DO:
DISP ttMockedData WITH FRAME x1 1 COLUMNS SIDE-LABELS.
/* Is there an empty field? - Then we update! */
IF ttMockedData.dataName = ""
OR ttMockedData.dataType = ""
OR ttMockedData.dataDescrioption = "" THEN DO:
DISPLAY
ttMockedData.dataName
ttMockedData.DataType
ttMockedData.dataDesc
WITH FRAME x2 1 COLUMN SIDE-LABELS TITLE "Complete the data...".
/* This isn't working with temp-tables of course! */
/* Just here to make sure you handle locking! */
FIND CURRENT ttMockedData EXCLUSIVE-LOCK.
UPDATE
ttMockedData.dataName WHEN ttMockedData.dataName = ""
ttMockedData.DataType WHEN ttMockedData.DataType = ""
ttMockedData.dataDesc WHEN ttMockedData.dataDesc = ""
WITH FRAME x2.
/* This isn't working with temp-tables of course! */
/* Just here to make sure you handle locking! */
FIND CURRENT ttMockedData NO-LOCK.
END.
END.
END.
ELSE LEAVE updating.
END.

Using frames in progress 4gl

Can anyone help me understand how to display the following pattern using a Progress 4gl frame:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5.
I have tried like this:
DEFINE VARIABLE a AS INTEGER NO-UNDO.
DEFINE VARIABLE b AS INTEGER NO-UNDO.
DO
a =1 TO 5 WITH FRAME f:
DO
b = 1 TO a WITH FRAME f:
DISPLAY a SPACE SKIP.
PAUSE.
END.
END.
/* while displaying the answer is overwritten, how do I display the answer side by side? */
If you were sending your output to a file you could do it like this:
define variable a as integer no-undo.
define variable b as integer no-undo.
output to "output.txt".
do a = 1 to 5:
do b = 1 to a:
put b.
end.
put skip.
end.
output close.
Using DISPLAY and FRAME is not like text files or printers. When you create a frame and DISPLAY "A" in it you are defining a single position where the variable will be displayed.
Every time that you DISPLAY A the value will be placed in the same position.
You can make it a DOWN frame and move to a new line with each iteration of the outer loop but you will still only have one position per line.
define variable a as integer no-undo.
define variable b as integer no-undo.
do a = 1 to 5 with frame f:
do b = 1 to a:
display b with frame f.
end.
down with frame f.
end.
To have multiple positions you need multiple variables or an array or you can build a string (doydoy44's solution). Here is an example with an array:
define variable a as integer no-undo.
define variable b as integer no-undo.
define variable c as integer no-undo extent 5 format ">>>>".
do a = 1 to 5 with frame f:
do b = 1 to a:
c[b] = b.
end.
display c with frame f.
down with frame f.
end
I'm not sur to understand what is the problem.
May be this can help you:
DEFINE VARIABLE a AS INTEGER NO-UNDO.
DEFINE VARIABLE b AS INTEGER NO-UNDO.
DEFINE VARIABLE woutput AS CHARACTER NO-UNDO.
DO
a =1 TO 5 WITH FRAME f:
woutput = "".
DO
b = 1 TO a WITH FRAME f:
woutput = woutput + " " + string(b).
END.
DISPLAY TRIM(woutput) SKIP .
PAUSE.
END.
The behaviour you are talking about is what I call a down frame. ABL creates a frame automatically for any output, and if you are displaying a series of records from a table, it knows to make that frame a down frame, for example:
for each customer no-lock:
display customer.
end.
But in your example you aren't using for each. To get the down frame behaviour you are going to have to make it happen yourself.
Here is the simplest code that will give you that:
def var v-i as int no-undo.
do v-i = 1 to 10 with down:
display v-i.
down.
end.
It's actually clearer what is going on, though, if you spell things out a bit further. Let's define a named frame, make it a down frame, and then use it:
def var v-i as int no-undo.
def frame f-x
v-i
with down.
do v-i = 1 to 10:
display v-i with frame f-x.
down with frame f-x.
end.
It's almost always worth defining a frame if you are outputting something, I find.
define variable a as int no-undo.
define variable b as int no-undo.
define variable res as char no-undo.
update a.
b = 1.
repeat while(b <= a):
res = res + " " + string (b).
b = b + 1.
disp res format "x(20)".
end.

Progress 4GL: Buffer handle attribute for all fields

I am fairly new to Progress and even newer to handles so apologies if I have missed anything obvious, I've looked online but am yet to find what I'm looking for.
I am running a dynamic query similar to the below, in this example after then query is run, the "age" field of the corrresponding record is displayed on screen, I understand how this is done from the buffer-field attribute-method, but my question is how do I display the entire record, is there an equivalent attribute method, or have I misunderstood something crucial?. Thank you for your time. :
def var tbl as character no-undo.
def var fld as character no-undo.
def var qh as handle no-undo.
def var bh as handle no-undo.
def var fh as handle no-undo.
assign tbl = "customer".
assign fld = "age".
create buffer bh for table tbl.
create query qh.
qh:set-buffers( bh ).
qh:query-prepare( "for each " + tbl + " where name = 'tom'" ).
qh:query-open.
do transaction:
qh:get-first( no-lock ).
fh = bh:buffer-field( fld ).
display fh:buffer-value.
end.
delete object bh.
delete object qh
There's no "easy" way to display the entire record in one statement the way you can with a static "DISPLAY table-name" statement. You can get the count of fields (buffer-handle:NUM-FIELDS) and then step through the individual fields and display their values using
DO i = 1 to bh:NUM-FIELDS:
DISPLAY bh:BUFFER-FIELD(i):BUFFER-VALUE WITH DOWN.
DOWN.
END.
create query qh.
qh:set-buffers( bh ).
qh:query-prepare( "for each " + tbl + " where name = 'tom'" ).
qh:query-open.
qh:GET-FIRST().
DO while qh:QUERY-OFF-END = False:
DO i = 1 TO bh:NUM-FIELDS:
display bh:BUFFER-FIELD (i):NAME STRING(bh:BUFFER-FIELD(i):BUFFER-VALUE) with down.
down.
END.
qh:GET-NEXT ().
END.

command to find the number of entries in a temp table

What is the command to find the number of entries/rows in a temp table? version 10.2b
/* create a temp-table so that we can test this technique
*/
define temp-table ttTest
field id as int
.
create ttTest.
id = 1.
create ttTest.
id = 2.
/* how many records?
*/
define query q for ttTest cache 0.
open query q preselect each ttTest.
display num-results( "q" ).
or you can use clasic FOR EACH:
DEFINE VARIABLE iCount AS INT NO-UNDO.
FOR EACH ttTest:
iCount = iCount + 1.
END.
DISPLAY iCount.
Here's mine, that works for any temp-table :
FUNCTION TT_NBREC RETURNS INTEGER ( INPUT pr_hd_temptable AS HANDLE ) :
DEFINE VARIABLE in_nbrec AS INTEGER NO-UNDO INITIAL 0.
DEFINE VARIABLE hd_buffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hd_query AS HANDLE NO-UNDO.
DEFINE VARIABLE ch_query AS CHARACTER NO-UNDO.
DEFINE VARIABLE ch_table AS CHARACTER NO-UNDO.
DEFINE VARIABLE lg_error AS LOGICAL NO-UNDO.
ASSIGN
ch_table = pr_hd_temptable:NAME
ch_query = "FOR EACH " + ch_table + " NO-LOCK".
CREATE BUFFER hd_buffer FOR TABLE ch_table.
CREATE QUERY hd_query.
hd_query:ADD-BUFFER( hd_buffer ).
lg_error = hd_query:QUERY-PREPARE( ch_query ) NO-ERROR.
hd_query:QUERY-OPEN().
hd_query:GET-FIRST().
DO WHILE NOT hd_query:QUERY-OFF-END :
ASSIGN in_nbrec = in_nbrec + 1.
hd_query:GET-NEXT().
END.
hd_query:QUERY-CLOSE().
DELETE OBJECT hd_query.
DELETE OBJECT hd_buffer.
ASSIGN
hd_query = ?
hd_buffer = ?.
RETURN in_nbrec.
END FUNCTION.
Just pass it the handle of your temp-table and you get the number of records.
It can certainly be improved, but it works fast enough for me.