Monday, 15 March 2021

Version control for Priority procedures

Someone asked how to maintain previous versions of procedures written in Priority; I answered that I had written a procedure that outputs the text to a text file that I store in a given directory. Someone else pointed out that Priority does have support for procedure versions, but when I looked into this, it appeared that this support is connected directly to a module that prepares 'update' files. These files are used when one develops on one machine and wants to install on another machine. I don't think that this was what the original question was about.

But this reply started me thinking: how hard would it be to develop a table (or two) that stores program text? The answer: fairly easy. I needed to define a table, a form and an interface. Procedures are maintained via a form called EPROG that is based on the EXEC table; this form has a child form called PROG that presents the procedure stages, and the text for each stage is shown in a form called PROGTEXT (not that this is important). The base table of PROG is PROGRAMS, whose primary key (or in Priority-speak, its auto-unique A index) is PROG. So I would need to define a table whose key included PROG.

The definition of my new table TEST_PROGVERSION is as follows

Field name Type Description Key
TPV Int Auto-increment A
PROG Int Pointer to procedure U
VERSION Int Text version U
CURDATE Date Date of version

On the basis of this table, I defined a form with the same name; this form is a child form of the PROG form, and PROG in my form is equal to :$$.PROG, i.e. the PROG is the parent form. TPV and PROG are hidden fields, and the form is sorted by VERSION descending, i.e. the newest version is first. Originally I defined the form to be query only (i.e. type Q) but this led to problems with the interface, so the form is now of type N (no deletions) and the two visible fields are read-only.

After I had a table and form, I used the built-in procedure for defining a text form; this created a table and form with the name TEST_PROGVERSIONTEXT and added this new form as a child form to the TEST_PROGVERSION form.

An interface has to be designed in order to insert data into these tables; this is required because of the text form that has special requirements, otherwise I could simply insert the required data into the tables. The interface has to be four levels deep: first EPROG, then PROG, then TEST_PROGVERSION and finally TEST_PROGVERSIONTEXT. 

How does one store a version? I wrote a procedure that appears as a direct activation from form PROG. Here it is
LINK PROGRAMS TO :$.PAR; SELECT PROG INTO :$.PRG FROM PROGRAMS WHERE PROG > 0; UNLINK PROGRAMS; :VERSION = 0; SELECT MAX (VERSION) INTO :VERSION FROM TEST_PROGVERSION WHERE PROG = :$.PRG; :PAR1 = '$'; LINK GENERALLOAD TO :$.GEN; ERRMSG 1 WHERE :RETVAL <= 0; INSERT INTO GENERALLOAD (LINE, RECORDTYPE, TEXT6) SELECT 1, '1', EXEC.ENAME FROM EXEC, PROGRAMS WHERE EXEC.EXEC = PROGRAMS.EXEC AND PROGRAMS.PROG = :$.PRG; INSERT INTO GENERALLOAD (LINE, RECORDTYPE, INT1) VALUES (2, '2', :$.PRG); INSERT INTO GENERALLOAD (LINE, RECORDTYPE, INT1, DATE1) VALUES (3, '3', :VERSION + 1, SQL.DATE8); INSERT INTO GENERALLOAD (LINE, RECORDTYPE, TEXT) SELECT 3 + SQL.LINE, '4', TEXT FROM PROGRAMSTEXT WHERE PROG = :$.PRG; EXECUTE INTERFACE 'TEST_PROGVERSION', SQL.TMPFILE, '-L', :$.GEN; GOTO 1 WHERE NOT EXISTS (SELECT 1 FROM ERRMSGS WHERE USER = SQL.USER AND TYPE = 'i'); EXECUTE WINACTIV '-R', 'INTERFACEERR'; LABEL 1;
UNLINK GENERALLOAD;
The entire process would have taken about twenty minutes, had I foreseen the problem of defining the new form not of type Q but of type N. A further waste of time happened when I looked at the text that was stored in the text form: it was aligned to the right. I tried to insert a line into the GENERALLOAD table to correct this, but I must have forgotten the correct commands. In the end, I realised that I can leave the text as it is, and if I need it left aligned, then I can use the command in the in-built HTML editor of the form that performs the switch and keeps the result.