______________________________________________________________________________ ______________________________________________________________________________ Contributions ______________________________________________________________________________ ______________________________________________________________________________ Contributions for the newsletter can be sent to either of the following addresses: Editor, DATATRIEVE Newsletter Joe H. Gallagher, Ph. D. c/o DECUS U. S. Chapter DATATRIEVE Newsletter Editor 249 Northboro Road, BP02 Director, Medical and Marlboro, MA 01752 Research Computing Cleveland Clinic Foundation 9500 Euclid Avenue Cleveland, Ohio 44106 Letters and articles for publication are requested from members of the SIG. They may include helpful hints, inquiries to other users, reports on SIG business, summaries of SPRs submitted to Digital or other information for members of the DATATRIEVE SIG. Machine readable input is highly desirable and machine-to-machine transfer of material is preferred, but most anything legible will be considered. However, this newsletter is not a forum for job and/or head hunting, nor is commercialism appropriate. ______________________________________________________________________________ ______________________________________________________________________________ Table of Contents ______________________________________________________________________________ 1 Chairman's Corner 3 DATATRIEVE Wish List 7 From the Editor's Pen 8 Wombat Magic Session 54 News Briefs 55 DATATRIEVE Masters ______________________________________________________________________________ ______________________________________________________________________________ About the Cover ______________________________________________________________________________ The cover for this issue was drawn by Bart Lederman of Bankers Trust Company. Our Wombat and his girl friend are waiting for us on the beach in California. i ______________________________________________________________________________ Chairman's Corner Larry Jasmann, U. S. Coast Guard, Burke, VA ______________________________________________________________________________ First of all, I would like to welcome those of you who are new to DATATRIEVE SIG (Special Interest Group), and greet those who I haven't spoken to or writ- ten to for a long time. Up until recently, I was attending graduate school at Tulane University, and there just didn't seem to be time to write much for the Wombat Examiner. Well, now I am out of school and without any excuses, I guess I will have to do better in this area. I am now stationed in the Wash- ington Area, and welcome feedback, questions, offers to help the SIG, or just a chance to talk and get acquainted. I am usually at work from 7:00 - 3:30 Eastern Time. My work phone is (202) 426-1345. Things are really changing in DECUS and with DATATRIEVE SIG, and it may be helpful for me to tell you how I perceive those changes from my perspective. DECUS is in the final process of a massive restructuring of the leadership organization, and although the effects at the membership level may be somewhat hard to see at this point, I feel that in the long run, the effects will be significant. Here are some perceptions about DECUS as a whole: 1. The new leadership structure involves more volunteers in decision making positions, and has a much more "bottom up" orientation than previously. The new leadership structure tries to push operational decisions in the organization to the lowest practical level. As a result, small groups have more ability to do what they want to do. On the other hand, signifi- cant decisions which have to filter up through the organization may well be more difficult to get resolved. 2. The new system tries hard to create paths for people to move up through the organization. In fact, one element (LDEC) of the organization has the primary charter of facilitating this process. 3. Organization of the SIG Chairs into a formal body, the SIG Council, is a significant step in increasing the effectiveness and capability of the SIGs as a whole. The SIG Council exists to represent the needs and de- sires of the SIGs as a whole to the rest of DECUS. It also exists to provide a common body of knowledge so that SIGs can work together better, and learn from each other. Finally, it provides a place where someone can go for resolution of a problem that isn't being treated responsively at the SIG level. 4. The DECUS Communications System (DCS) has increased the effectiveness of the leadership to an extraordinary degree by enabling rapid and effective communication among the leadership. DECUS is a 3 to 5 million dollar business run by people who see each other about 4 times a year for a week or less each time. Think about that, and think of trying to run your own organization that way!! DCS has made the process much better and respon- 1 sive to the needs of the organization. Sometimes, I wonder how we did without it. Now a few perceptions about our SIG: 1. DATATRIEVE is really changing. When I first started in the SIG, DTR was on only PDP-11's, and the documentation set was one fairly small manual. DATATRIEVE was lots of fun, and for those of us who couldn't afford an army of programmers it was a Godsend, but for the most part, the DEC world didn't take it too seriously. Well, things are really different now. DTR is on ALL systems from DEC-20's to the Professional (I think that the only exceptions are the DEC-10 and the Rainbow), and it is no longer a trivial product. It is relational, it has graphics, a sophisticated report writer, and on the VAX, the ability to be used with other languages or to use functions. It has grown up, and so has the SIG. 2. When I was handed the SIG Chair job two years ago by Chuck Watson, we could see this process beginning, and a primary goal of mine has been to increase the organization of the SIG enough to handle the increase in products and sophistication, but at the same time, keep the same spirit and "fun" that has always been the trademark of this SIG. We now interact much more with other SIGs, and with the DECUS leadership than before, and the services that we provide have increased, both in scope and in number. Through all of this though, we have tried to keep things spontaneous and open. To continue to do these things, we, the Steering Committee, needs your con- tinued help. We need contributions, both to this newsletter and to the Sympo- sia. We also have a continuous need for volunteers to help us with projects. But even more than all of that, I in particular, need your ideas, your sug- gestions, your critical comments and solutions, and sometimes, just some reas- surance that we are going in the right direction. Letters are welcome, and should be addressed to DECUS to my attention. Phone calls to the number given above are also welcome. Well, I think that is enough of a sermon for one time. Have fun DATATRIEVE- ing, and we will see you in Anaheim in December. 2 ______________________________________________________________________________ DATATRIEVE Wish List Bart Z. Lederman, Bankers Trust Company, New York, NY ______________________________________________________________________________ A wish list is a method by which the users can get their requests for changes or enhancements in a product back directly to the persons in DEC who work on the product. The DATATRIEVE wish list is somewhat informal, being collected during the symposium up until Thursday night, when a copy is given to a DEC developer. DEC then responds during the SIG closing session. The answers which follow are comments only, and must not be taken as a commitment by DEC to supply any new feature, but in the past most of the suggestions from the user community which appear useful or which address a need not presently satisfied have ended up in the product. In some cases (though there were not too many of them this time), DEC will suggest an alternative solution to the same problem. DEC will also often point out that the solution to a problem depends upon some other software product, and it sometimes is necessary to go to that group and let them know there is a problem, though DEC sometimes passes the information on internally. Please note that anything labeled "Editor's note" is my opinion only, not DEC's. 1. Allow PRO/DATATRIEVE to remotely access domains on a VAX. Comment: Being seriously considered now. Editor's note: DECNet for the PRO was announced at this symposium, and is naturally a prerequisite for remote access. 2. Would like DATATRIEVE to ready "Batch Retrieval" to allow reading of records without preventing update access (when running DTR with VAX DBMS). Comment: Definitely being considered! (Some pieces in place with V3.0). 3. Provide the following: EXTRACT ALL {PROCEDURES, RECORDS} ON file.typ Comment: Good suggestion, worth considering. 4. Would like to have a DTR function to report on report statistics. This would tell, for a report generated, the number of records found, the number of report pages generated, the size of the report, etc. Comment: Good suggestion for Report Writer functionality. 5. Provide "user friendly" linkage between DECalc and DATATRIEVE. Then we would have a Lotus 1-2-3 "emulator". Comment: Good suggestion. We are aware of the problem and want to stay competitive. 3 6. Thanks for supervisor RMS. Please finish the job and make an I-and-D space DTR-11 for the PDP-11 and J-11. Comment: we will pass this along to the DTR-11 developers. 7. Support for scrolling regions in FMS would be nice. Comment: not a trivial problem to solve. We'll look at it once again. TDMS also difficult to solve. 8. Be able to insert a variable name into the SET REPORT_NAME = variable. Comment: Good suggestion for Report Writer functionality. 9. Publish more information on PLOTs once the plots have reached a stable form. Comment: Won't be done. Plots are not stable, and we don't want to limit future development by fixing the language. 10. Other than PIE chart, be able to put a title on plots. Comment: Good suggestion. Can be done with DECgraph. 11. Even though the QUADWORD (DATE) being indexed is an RMS issue, it effects DATATRIEVE. It is important that the QUADWORD be able to be a key field. Comment: it REALLY is an RMS issue, and is expected to be supported in VMS V4.0. 12. Put the space shuttle back in the CDD. We'll look at putting something other than the Wombat in the plots. Old plots can be extracted from the 2.0 kit. Editor's note: there was some discussion about plots having to be re- moved due to copyright restrictions on the subjects. A suggestion was made that a plot like the "Snoopy" plot that did something other than just plotting (like memos) would be nice, and was noted. 13. Include wildcards for the SHOW command such as SHOW AB*. Comment: Good suggestion, worth considering again. 14. Change the defaults for DEFINE FILE command so that the files are at least a little more efficient. Comment: Good suggestion. There is documentation describing usage of RMS utilities. It has been given some consideration already. 15. Improve the DELETE command in DATATRIEVE, i.e. DELETE DOMAINS. Comment: basically the same idea as the EXTRACT DOMAINS given earlier. Worth considering. 4 16. When a specific procedure with an ACL (Access Control List) is edited, that ACL is lost and a default one given. Some way of not losing the ACL after EDITing a procedure [is needed]. Comment: done in Version 3. 17. Get a better, easier to use editor for PRO/DATATRIEVE. Comment: probably won't happen. Improving the editor would probably cost pool space. Suggested work-around is to extract the definition and use your favorite editor externally. 18. PRO's are being sold as workstations in VAX environments. However, PRO/DTR and VAX DTR are not fully compatible. All efforts should be made towards moving these products closer, so data/models can be easily ported back and forth. Comment: technically not feasible. There was some work done in DTR- 11 V3 to close compatibility. Adding JOIN would eat all pool space. Editor's note: some discussion followed, where it was suggested that ADT on the VAX should produce applications which would run on the PRO. The comment was that this might degrade the VAX environment, but would be looked at. It was then suggested that the VAX have a compatibility switch as is used in some other languages, so that the VAX could be informed when it is going to target for an 11 and when it is targeting for a VAX, and this was noted by DEC. The response from the users was that they would at least like all applications which run of the PRO to move to a VAX, but not necessarily vice versa. 19. Variable length record support would be a great help in DTR. (This means without the OCCURS clause, such as having text of variable length). Comment: good suggestion, worth considering again. We are looking at this for use with other products as well. Editor's note: this is only a guess, but it sounds like they need to handle variable length text to interface to other DEC produces, which increases the chances that it will appear, but don't quote me. 20. [Allow] upper and lower case in procedure definitions. It was there prior to DTR-32 V2.0, it makes for easier-reading code, etc. Comment: Not quite true. The first time a procedure was installed, everything was converted to upper case. Subsequent EDITs could change text to lower case. The problem is quite difficult to solve. V2.0 and up requires all code to go through the parser, which converts to upper case, but also allows editing everything. 5 21. Allow logical name for node and access control in ready of remote domain: $ASSIGN NODE "user password":: DTR_NODE DTR>READY YACHTS AT DTR_NODE Comment: Good suggestion, worth considering. 22. Allow record selection expression on domain table definitions. Comment: Neat. Good suggestion, worth considering. 23. Compiled versions of procedures. Comment: Probably won't be done. Very, very difficult. 24. Support for RMS segmented keys. Comment: Tricky. We'll look at it once again. 25. TDMS validation criteria. Comment: Tough to solve. We'll look at it again. 26. Subscripted Variables. Comment: Probably won't happen. Would require a drastic alteration of DTR syntax. Has been looked at several times in the past, but other application level solutions were found. 27. I wish DATATRIEVE-11 would give more information when it is inclined now to say "Severe Error - Cannot Continue". Comment: Need more information, will pass on to DTR-11. Editor's note: some discussion from the floor indicated that it was most often encountered during initialization, and sometimes from sorting. 28. Put an index of all the examples in the documentation, so they can be easily located. Comment: Good idea, we'll pass this along to the documentation group. 29. Need capability to detect NO MATCH when crossing domains. Should produce error and display "key" (over field). Comment: We'll look at the problem. We don't think everyone wants it, but will try to come up with some way of resolving this kind of situa- tion. Maybe we need some additional levels of DEBUG [other than every- thing on or everything off]? 6 30. Add support for VT100 graphics in VAX DTR Comment: probably won't happen. Had been considered, might look at what DTR-20 does and "steal" it from them. Additional suggestions were made about having multiple forms. It was stated that this needs to be done by the forms handler, and that the suggestion has been passed on. ______________________________________________________________________________ From the Editor's Pen Joe H. Gallagher, Cleveland Clinic Foundation, Cleveland, OH ______________________________________________________________________________ The editor's pen was passed to me at the DECUS Spring Symposium. It was with some reservations that I accepted this responsibility. It is a big job, and the community of DATATRIEVE users has come to expect an informative and professional looking newsletter. We of the DATATRIEVE SIG own a great deal to the retiring editor of the Wombat Examiner, Virginia Sventek of Lawrence Berkeley Laboratory, who, along with Cynthia (Curry) Mealy, edited the newsletter for over three years from late 1981 to early 1984. During this time, the Wombat Examiner underwent significant increases in number of pages and quality of production. On behalf of the DATATRIEVE family of users, may I express our thanks and admiration to Virginia for a job well done. It is my aspiration that the Wombat Examiner will again be published on a regular basis with four issues per year. The issues will roughly correspond to the seasons and should appear just before and soon after the spring and fall symposia meetings. The activities of the semi-annual symposia generates sufficient material for two of the four issue per year; however, it is from you, the DATATRIEVE user community, that the remaining material must come. DATATRIEVE with its wide range of machine implementations and wide range of applications can not help but create interesting, unusual, and unique examples, problems, and computer solutions. It is your responsibility and duty to share your triumphs and troubles with your fellow DATATRIEVE users. 7 ______________________________________________________________________________ Wombat Magic Session Session Chairman: Bob Lott Transcriptionist: M. Iris Compton-Park Session Editor: Joe H. Gallagher ______________________________________________________________________________ Editor's note: The following is a highly edited transcription of the audio tape of the Wombat Magic Session at the 1984 Spring DECUS Symposium in Cinci- natti, Ohio, which occurred on June 7, 1984. Material which was presented on transparencies has been merged into the oral presentations. An attempt has been made to convey both the technical content of the Magic Session as well as the humor, covert intellectual swaggering, and spirited interchange of the presentations. Material which appears in the text within square brackets [] has been included to improved, I hope, the understandability of this very accelerating Magic Session. Special acknowledgement is given to Ms. Iris Compton-Park, who works with Dick Azzi, for her outstanding job in originally transcribing the audio tapes. Joe H. Gallagher, Cleveland Clinic Foundation, Cleveland, OH Here's the problem. We have a dataset which maps (in both directions) employ- ees to projects; it's a hierarchical set. But that's not the real issue. Going with each project there is an abstract, and the abstract can be three thousand to four thousand characters long. A field of over three thousand characters just can't be managed very well on a screen. Nothing in DATATRIEVE or FMS is very helpful for dealing with textual data in blocks that big. The magic is really due to our programmer analyst, Mario Guarracino. Actually this is DCL magic, not so much DATATRIEVE. Our solution goes "We do it in DATATRIEVE and if we can't figure out how to do it in DATATRIEVE we do it in DCL. If we can't do it in DCL, we beat someone about the head and ears until they do it in BASIC. If we can't do it that way, we don't do it. So here is how we got around the problem. It's a little DCL command procedure [See DCL command file below] that asks the user what project he is going to work on. But first it deletes some things. Since we did not want the user to worry about what that stupid delete error message was (when a file is not present), we turn off all the messages by saying SET MESSAGE /NO... - don't give any error messages. Delete the files, if they don't happen to be there, there is no message; then turn it back on the [error] messages. Then ask them what is the project number. If they enter a blank, a null string, or a zero, the command file exits because they are done. Otherwise it starts writing a file which happens to be a DATATRIEVE command file. [This file contains.] Set abort, ready the project domain, ready the indexed abstract domain for write, and if not any projects with project_number equal to project_number_entered_by_user then abort. If not any abstract in the index then store a dummy one there. That is, put in the number and a blank abstract because they are going to enter one. That is the end of that command - almost. Then we are going to SET COLUMNS_PAGE = 60, and we are going to print out the abstract which is a field variable in the domain abstract index 8 with an EDIT_STRING IS T(60). It will take that great big long abstract of over three thousand characters and wrap it around into manageable records in that sequential file; then we close the file. We then type something for the user (since some of these processing operations take a while), like "WE ARE WORKING FOR YOU," and "BY THE WAY, REMEMBER TO EDIT THINGS IN UPPER AND LOWER CASE." So, we now have this command file ready for doing things. Before starting up the indirect command file with the DATATRIEVE commands, we tell them 'WAIT - IT IS GOING TO TAKE A WHILE.' Then we redirect the startup of DATATRIEVE into a garbage file because we do not want them to know that they are in DATATRIEVE, and execute the file. It goes in there finds the project, finds the abstract, stuffs it out into a file. In order to make sure that there was really a file, we go out and check that there was one in case there wasn't because if it's not, we are going to branch out here to somewhere else. If there is a file there, we are going to reassign the input and the output of the editor, and pop right into the DEC Standard Editor because the editor manages large blocks of text very nicely. This lets the user edit that ab- stract of undetermined length (actually in this case about three thousand characters). Then the fun happens. They have now edited this file which consists of records (each one usually less than 80 characters long). In order to get back into DATATRIEVE, we have to go and stick it all back in one big record. Here's the little problem we couldn't easily solve [in DCL or DATA- TRIEVE] so we had to go to BASIC. 1 ! BASIC program to put text into one record open "ABSTRACT.SEQ" for input as file #1%, & organization sequential variable, recordtype any open "ABSTRACT.TMP" for output as file #2%, & organization sequential variable, recordsize 2995% on error goto 500 trec$ = "" while 1 linput #1%,rec$ rec$ = edit$(rec$,16%+128%) + " " trec$ = trec$ + rec$ next 500 if err = 11 then resume 520 else 999 520 print #2%,trec$ close #1%,#2% 999 end This one [EDIT$(...,16%)] removes all multiple spaces and this one [EDIT$(...,128%)] removes all trailing spaces and then you take the text and put it all out on one big line. Since the record size is very large that you are going to write, you just write this guy out in one BIG, LONG straight line. We could have probably done this in some other way but in this case neatness did not count, it was fast program development time that we were after. Now that we have the thing strung out in a line and edited, we go back and ask the user "DO YOU REALLY WANT TO PUT THIS BACK IN?" because they might have made a mistake and want to change their mind. If they do, we go on and actually do something - we delete a temporary command file and create another one; we ready [READY WRITE] the data base we are going to stick it back into; we ready a temporary domain which is this one long record, find that thing with that particular project number, and modify it to stick the abstract back 9 in. And BINGO... The whole command file is: $ wo :== write output ! make a shorthand notation for WRITE OUTPUT so the $ ! command file below will fit on the page. $begin: $ set message/nofacility/noident/nosever/notext $ delete ABSTRACT.SEQ;*,SEARCH.COM;*,ABSTRACT.TMP;* $ set message/facility/ident/sever/text $ inquire PROJ_NO "Enter Project Number(enter 0 to Quit)^G" $ if PROJ_NO .eqs. " " then exit $ if PROJ_NO .eqs. "" then exit $ if PROJ_NO .eqs. "0" then exit $ open/write output SEARCH.COM $ wo "SET ABORT" $ wo "READY PROJ" $ wo "READY ABSTIDX WRITE" $ wo "IF NOT ANY PROJ WITH PJ_NO =",PROJ_NO," ABORT " $ wo "IF NOT ANY ABSTIDX WITH PJ_NO=",PROJ_NO," STORE ABSTIDX USING BEGIN" $ wo "PJ_NO = ",PROJ_NO $ wo "END" $ wo "SET COLUMNS-PAGE = 60" $ wo "FOR ABSTIDX WITH PJ_NO=",PROJ_NO," PRINT ABSTRACT(-) ON ABSTRACT.SEQ" $ wo "EXIT" $ close output $ type sys$input Stand by ....I'm Trying to find the ABSTRACT. If there is one I'll display it and you may proceed to make changes. If not you may begin to enter the New abstract as soon as I put up a blank screen. While we Wait let me remind you to use UPPER + lower case Format $ assign/user GARBAGE.FIL sys$output $ assign/user GARBAGE.FIL sys$error $ dtr @SEARCH.COM $ open/read/error=noproject abstract ABSTRACT.SEQ $ close abstract $ assign/user tt: sys$input $ assign/user tt: sys$output $ edt ABSTRACT.SEQ !editing is a quick way to change the file type $ run packrec ! let the BASIC program restructure the data $ inquire ANSWER "Shall I Proceed to Update the ABSTRACT?^G^G" $ if ANSWER .eqs. "Y" then goto doit $ type sys$input NOTE: Abstract Not updated!!!!!!! $ goto begin $doit: $ delete TUPDATE.COM;* $ open/write output TUPDATE.COM $ wo "READY ABSTIDX WRITE" $ wo "READY ABSTRACT_TEMP READ" $ wo "FIND A IN ABSTRACT_TEMP" $ wo "SELECT" $ wo "FOR ABSTIDX WITH PJ_NO=",PROJ_NO," MODIFY USING ABSTRACT=TABSTRACT" $ wo "FINISH" 10 $ wo "EXIT" $ close output $ type sys$input Stand by ....I'm Updating the ABSTRACT^G $ assign/user GARBAGE.FIL sys$output $ assign/user GARBAGE.FIL sys$error $ dtr @TUPDATE.COM $ delete GARBAGE.FIL;* $ type sys$input ** Abstract Updated ** $ goto begin $noproject: $ type sys$input NOTE: You must Enter the Project Information before you will be allowed to enter an Abstract^G $ goto begin $end_job: That is the command file we have written and then we go into DATATRIEVE and actually do it and collect garbage, tell the user we have updated the file and go back and ask it for the next abstract. Now, this is not very neat; it is not very pretty; it is not very fast. How- ever, it works. Since they only have to do a few hundred [abstract updates] a year, it works well enough and the gal who enters the data in DATATRIEVE, already knows how to use the editor. Neatness does not count if it gets the job done. The idea is the most important thing, not the details. There are a bunch of possible extensions. One could have done this all inside of DATATRIEVE by writing the appropriate functions and getting it done. That would have been nice except we did not want to take the time to do it. We did this very quickly. One could also do this on multiple fields, so you are not really limited to one field, you can take a bunch of fields, write them out, and do it this way. The problem of doing it as a subprocess comes when managing that one problem of restringing all the records back together. That is the little tricky part. Chris Hines, American Board of Family Practice, Lexington, KY A little bit of anti-magic first. Basically, what happened was I had this file that I had to read; it was written from FORTRAN. This is a MORALITY TALE; if you look for trouble, you will find it. You could say that this is an object lesson in how having 32-bit virtual machines with lots of resources - basically there is no limit to the amount of time you can spend doing ex- tremely stupid things... I would like to point out to you that DATATRIEVE is usually extremely willing to help you in this quest. The problem I had was that someone presented me with this ASCII file that had been formated by FORTRAN. Right away all my years - many years of experience paid off and the alarm bell started ringing. I said "I remember about three years ago in a DATATRIEVE session some guy was saying he really had trouble reading a FORTRAN format ASCII file." I thought about it and said "Yea, you 11 are going to have trouble, because if you got an I3 format, FORTRAN blank fills those, and if you tell DATATRIEVE that it's a PIC 999, you are going to get one of your most favorite, second only I think to - what is it - '"field_name" is undefined or used out of context.'" How many people have ever gotten that.... [growns from the audience] You get our second most favorite error message which is 'Illegal ASCII numeric'." Has anyone ever seen that? [boos from the audience] I spent a lot of time trying to decide whether I like the "Illegal ASCII numeric" better or its COBOL cousin - "invalid decimal data". It is really kind of a toss up - but COBOL is kind of more spectacular when you get it because it is followed by a stack dump. In DATATRIEVE all you get is it zeros your variable - that is not particularity interesting. Anyway - I said "Yes, that is going to give you problems, same thing with an F [FORTRAN format] so that is going to be out there as -1.23, and I am going to tell DATATRIEVE that is some kind of field and it is not going to like the minus, it does not like the [decimal] point; if there are any blanks, it is not going to like those." I said "Holy Moses". I figured that surely with one of the 453,000 functions I had built into DATATRIEVE, I could handle it. Before I submit my SPR, I will first verify that I have a problem. I said "Lets just try it straight up" and the name of this variable is RVAL - short for R VALUE - that is a statistical measure used for items on a test which tells you that - depending on its value tells you that - all the smart people got the item wrong and that all the dumb people got it right. It makes you kind of -- well -- you look at those items a little bit strange. I said, "It's PIC S9V99" and sure enough, I fed that to DATATRIEVE - and I got "Illegal ASCII numeric" and not only that but the record comes out the wrong length. The V does not hold any space - that's a virtual period and in the FORTRAN format record it does indeed hold a space. At that point, I said "Ok, time to whip out the functions". I broke this thing down - I said "Ok, I'll put the sign in one variable and then I'll get my one digit another variable and I put a filler for the period and I will pick up the fraction point in a PIC 99." This looked good. Then I said "Let's put it all together here." And there it is. Isn't that a thing of beauty. 03 RVAL_STR. 05 RVAL_S pic x. 05 RVAL_1 pic 9. 05 filler pic x. 05 RVAL_2 pic 99. 03 RVAL pic s9v99 real computed by ((fn$delta(RVAL_S,'-') * -1) + fn$delta(RVAL_S,' ')) * (RVAL_1 + (RVAL_2/100)). FN$DELTA is a function I built in. I was originally a physicist by training, it was affectionately named after the Kroniker's Delta function. Since then I have wished about four million times that I had named the thing FN$EQUALS because this function, you give it two values and it returns a "1" if they are equal and a "0" if they are not. Now there has been a lot of past magic done with doing that same type of thing through tables and I thought about doing some magic with that, but, of course, that has been obsoleted by the fact that you can now do the IF-THEN-ELSE's in COMPUTED BY variables. Anyway, if the two things are equal it gives you one, if the two things are not equal it gives you zero. So here we are checking the sign and then if it is a dash [minus sign] we are going to multiply by minus one, if it is a space, we are 12 going to return a 1, so we are going to multiply by one and then the whole part of the number and then the fracture part of the number. I plugged that in there and LO AND BEHOLD. It worked, and I looked upon it, and it was GOOOOOD! I was really pleased with this because it did the job but at the same time, you know, you look at that thing and, you know, that nobody reasonably sane is going to figure out what it is doing, you know, in less than about ten man year. I was really pleased with it, but then I got to looking at it a little bit further and I said "HOLD ON, WAIT A MINUTE! I am implicitly let- ting DATATRIEVE convert a string into a number there, aren't I?" Then I thought about it a little bit more - I realize that DATATRIEVE does a real nice job of that, in fact that FN$DELTA function does a compare [of 5 char- acters] on the strings. You tell DATATRIEVE that the things coming in are strings, it does a compare character and you can pass it almost any kind of data and I have never had it not work, so I think that DATATRIEVE does a real good job with its string conversion. I decided to try something perhaps a little more simpler [sic]. I said "Let's declare this string PIC X(5), and let's take the floating point number - same definition - real just computed by a string." 03 RVAL_STR pic x(5). 03 RVAL pic s9v99 real computed by RVAL_STR. Guess what? It works. Works just great. So if you ever have any problem with formated FORTRAN - that is the way you do it. Now that was not really that great anti-magic, I'd say I only wasted a half an hour playing around with this stupid thing, but I think that the steering committee should seriously consider having an award for magic and anti-magic also because, I guess that is kinda like your basic horror story isn't it? Now this is real magic, this is pretty simple, I do not know if this has been discussed before or not - but this has to do with some of the uses of the "T" edit string. One of the nice things I found out that the "T" edit string does is that you can use it to compress white space. 03 name pic x(30). 03 address_1 pic x(30). 03 address_2 pic x(30). 03 city_state_zip pic x(30). So you have your name, address[es], city/state/zip like you put on labels, and you are going to put them in a report, and you want to squeeze all the white [blank address lines] out of them because some of them are going to be blanks, and you do not know which one[s]. Now you can do an 'IF THIS ONE IS BLANK THEN DONT PRINT" and all of that, but what worked out pretty good is if you just do this one thing print col 1, name using t(30), col 1, address_1 using t(30), col 1, address_2 using t(30), col 1, city_state_zip using t(30) and what it will wind up being is that the white space will be compressed out. I do not know why it works, but it does. You can also use it - it is real 13 nice, if you have your occurs clause because say you have this OCCURS 10 TIMES PIC X(n) EDIT_STRING T(n). When you go to print that thing out, it will com- press the white space out, so any of them that are blanks won't print up and it saves you a whole lot of paper. If you have big occurs but don't have a whole lot of elements in them. Now there's a little tiny thing that is strange there -- and that is in the case where there is only one value that is non-blank, it gives you a blank line after it. If there's two or three values, it prints two, three values and no blank line. But if there is one value there it gives you blank line after that line. I have never sent in an SPR on this because my feelings were that this was never suppose to work this way in the first place anyway, and if I ask them to fix it I know it would all go away!! [laughter for audience] This is useful on occasion. Bernice Packer, Smith, Cline, and Beckman I was placed in a difficult situation recently. I was given an application for Human Resources Employee Database and one of the major reports that had to come out of it had to appear on pre-printed forms, 15 inches across, and I was not involved at all in the planning what the report would look like. In other words, I was given boxes of paper where I had to fill in the actual blanks that were there. I had the actual inches that had to be done on there and was told to do it in DATATRIEVE for political reasons. [Laughter from audience] All the information was contained in RMS domains that were related with a common keys so that it could have been done in DATATRIEVE or any other pro- gram[ing language] that could read RMS - say BASIC. The theory was that you can do things in DATATRIEVE faster, so I used DATATRIEVE. Some of the anomalies that you will notice on this reporter is that you have some occurs - I am trying to note in the boxes the fields that are occurs clauses, for instance, for each employee you have several education records, several train- ing, previous jobs, salary history, etc, but there is no guarantee that you will have any records or more than the number of records allowed per box for any of those employees. [Editor note: The follow is a very, very rough repre- sentation of the hand drawn representation of what is obviously a very compli- cated form!] 14 ________________________________________________________________________ | Name | Employee Info | | ____________________ ___________ | _______|________|_______|______ | | First Middle Last Emp. No | Superv Pay-Type Pay-hrs Dept | | __________________________________ | | | address line 1 | Salary History | | __________________________________ | _______________________________ | | address line 2 | | Date Chg Typ %incr New sal | | | _____________ _________ ________ | | ____ ________ _____ _______ | | | city state zip | | ____ ________ _____ _______ | | | | | ____ ________ _____ _______ | | | [OTHER GENERAL FIELDS] | | ____ ________ _____ _______ | | | Education | | ____ ________ _____ _______ | | | ________________________________ | | ____ ________ _____ _______ | | | | University Year Degree | | |_______________________________| | | | _____________ _____ __________ | | Appraisal History | | | _____________ _____ __________ | | _______________________________ | | | _____________ _____ __________ | | | Date Apprtype ApprRdy Promte?| | | | _____________ _____ __________ | | | _____ ________ _______ ______ | | | |________________________________| | | _____ ________ _______ ______ | | | Training | | _____ ________ _______ ______ | | | ________________________________ | | _____ ________ _______ ______ | | | | Organization Date Duration | | | _____ ________ _______ ______ | | | | _______________ _____ ________ | | |_______________________________| | | | _______________ _____ ________ | | Succession planning history | | | _______________ _____ ________ | | _______________________________ | | | _______________ _____ ________ | | | Date due RespPer Action | | | |________________________________| | | _______ __________ _________ | | | Previous Jobs | | _________ | | | ________________________________ | | _________ | | | | Organization Pos Start End | | | _______ __________ _________ | | | | ______________ ____ ____ ____ | | | _________ | | | | ______________ ____ ____ ____ | | | _________ | | | | ______________ ____ ____ ____ | | |_______________________________| | | | ______________ ____ ____ ____ | | | | |________________________________| | [OTHER EMPLOYEE INFO] | | [OTHER EMPLOYEE INFO] | | | [ETC] | [ETC] | |________________________________________________________________________| You will also notice that as you go across the page, there is no real consis- tency between where the boxes fall on the page. For instance, I can't say PRINT THE FIRST EDUCATION RECORD AND THEN THE FIRST SALARY HISTORY RECORD. This will take - like 20 minutes to describe - but it is really magic the way it did it, and it has a lot to do with the big view over about about twelve different domains. 15 DEFINE DOMAIN EMPLOYEES_REPORT OF EMPLOYEES, EDUCATION, TRAIN, PRE_JOB, SALARY_HIST, APPRAISAL, SUCC_PLAN, SICK_DAYS USING 01 REPORT_ENTRY. 03 ENTRY FROM EMPLOYEES. 03 EDUCATION_RECORDS OCCURS FOR EDUCATION WITH EMP_NO = EMPLOYEES.EMP_NO SORTED BY DESC YEAR. 05 entry FROM EDUCATION. 03 TRAIN_RECORDS OCCURS FOR TRAIN WITH EMP_NO = TRAIN.EMP_NO SORTED BY DESC TRAIN_DATE. 05 entry FROM TRAIN etc ad nausium I define a domain called EMPLOYEES_REPORT over employees which is the name domain in the system and all the other domains like EDUCATION, TRAIN[ing], PRE_JOB, etc which all are indexed with the employee number key. And then in this view each subrecord in the view other than the first one, which is actual entry from EMPLOYEES domain contains an occurs clause of the records drawn from each of the other domains that have the employee number key matching so that you have occurs lists for each one. Also you will note that there is a SORTED BY at the end of each one. The specification was that it had to be in descending date order which makes it even more interesting. Another thing that was interesting was that there was a bug in one of the field test versions of DATATRIEVE for a while that ignored that sorted by syntax when it was within a view and that was recently corrected. That was THE bug that affected this report. So what ended up happening was that I created two sepa- rate report files, one for each half of the report [left half and right half] and then I was faced with the problem of blank lines. If there were fewer than the proper number of records to fill the box, obviously DATATRIEVE, be- cause of the problem the previous gentleman mentioned [See second part of Chris Hines's Magic], does not give you the right number of blank lines. So using the wonderful choice clause we have recently received, I would have to do a count on each occurs clause to see how many records I had and then print the proper number NOT of blank lines but of lines filled with dummy char- acters. Then I had another procedure in DATATRIEVE that concatenate the two reports together, looking for the dummy character lines to insert blank lines instead. It worked beautifully. I did twelve hundred employees. That is the entire R&D population of Smith, Cline and Beckman on these pre-printed forms. Nobody believed that it was done in DATATRIEVE. When I still show it to people, they don't believe it was DATATRIEVE. [Applause!] Stewart French from Wausen[??] Financial This is really an anti-magic. I was wondering if anybody could help me with it. Before I came here I upgraded DATATRIEVE from 2.1 to 2.2 and I looked at our TDMS forms that pull up some real numbers and all the numbers appeared multiplied by ten (10). I called DEC Software Services up and they said "Well! it looks like you found a bug." I said "Thank You". [laughter and applause] I've been going around all week trying to find out what it is - TDMS blames it on DATATRIEVE, DATATRIEVE blames it on TDMS. [The question is put to the audience for them to think about it and advise if they know what the problem is.] 16 Larry Jasmann, U. S. Coast Guard, New Orleans, LA Ok, I have a little bit of magic. Maybe I have a soap box, but basically I feel that some magic should be presented that is not really super fancy and is designed to show that some things can be done that aren't really as hard as they seem to be. About a year ago, I became stuck on the call interface and I like to play around with it. The thing that I decided to present tonight is a little call interface thing which - you guys are probably going to throw rocks at me, but there is even a BASIC program that does it. The whole point is, is that if you read the documentation and you read the stuff on the call interface and after you have read about the fifteenth stall point, you say "Good grief, how can I even do anything with the call inter- face? It seems to be awfully complicated." Well, here's the thing. What I want to show you tonight is the fact that the call interface is not compli- cated; it is really easy. If you just take a few things out of there, and follow them, it works pretty doggone nice. It can do some nice things. What I have is a situation where I want to have a totally menu driven appli- cation. I want them to NEVER see the DATATRIEVE prompt. I want it to be so that if they are inside a procedure they can't exit outside of the procedure. If they do a CONTROL C, I want it to all go away or trap it back to the pro- gram - whatever you want to do, but I just don't want them to ever get to DATATRIEVE. I just want to lead them by the nose through the whole thing. One way of doing that is with the call interface. Now, you can do menus - it does not make any difference. You can use FMS, TDMS with this; it all works the same. The big problem with just doing menus in DATATRIEVE though is, that if you want to do it without having anything to get to DATATRIEVE, you have essentially front load the whole thing and compile the whole thing right off the bat when you call the menu. That can take a long time and besides -- when you are down in the middle of a BEGIN-END loop and it gets sort of yucky try- ing to do things - not that it can't be done, but who likes to start up the procedure and then go get a cup of coffee and come back fifteen (15) minutes later before you start doing things?. [This is the BASIC program ]... and it is really pretty simple. [The BASIC program below is displayed. Growns from the audience followed.] 17 1 ! M E N S H R T . B A S & ! & ! This program demonstrates a way to do a complete menu & ! driven application in DTR using the call interface & ! & ! By: L. M. Jasmann & ! Date: 14 May 1984 100 %INCLUDE "DTR$LIBRARY:DAB" ! include the DAB 110 MAP(BUFF) STRING OPT = 10 ! buffer for the port 190 ! declare the init and terminal server calls as function & EXTERNAL INTEGER FUNCTION DTR$INIT, DTR$DTR & ! declare the exit and normal status. & EXTERNAL INTEGER CONSTANT DTR$_EXIT, SS$_NORMAL & DECLARE INTEGER INIT_OPTIONS, DTR_OPTIONS, RET_STATUS & ! assign the initial option & INIT_OPTIONS = DTR$K_SEMI_COLON_OPT & + DTR$K_UNQUOTED_LIT & + DTR$K_FORMS_ENABLE & ! initialize the interface 500 RET_STATUS = DTR$INIT(DAB BY REF, 100% BY REF, MSG_BUFF, & AUX_BUF, INIT_OPTIONS BY REF) & ! check to see if DTR was initialized & IF RET_STATUS <> SS$_NORMAL THEN & PRINT "DATATRIEVE init failed" & GOTO 7000 & ! call the terminal server 2400 ! go to the menu 2405 ! set dictionary & CALL DTR$COMMAND(DAB BY REF, "SET DIC MENTST") 2407 ! clear message for buffer & CALL DTR$DTR BY REF (DAB,DTR$M_OPT_CMD) 3910 ! call the menu & CALL DTR$COMMAND(DAB BY REF, ":MENU") 3920 ! this allows the terminal server to run the procedure & CALL DTR$DTR BY REF (DAB,DTR$M_OPT_CMD) 3921 ST$ = "STORE PT USING OPT = QST VIA TRANS_TBL" 3923 ! This puts the next procedure to be run into the port so & ! that it can be access by the program (opt) & CALL DTR$COMMAND(DAB BY REF,ST$) 3925 ! This gets the stuff put into the port into the program & CALL DTR$GET_PORT BY REF (DAB,OPT) 3926 ! This clears the message from the buffer & CALL DTR$DTR BY REF (DAB, DTR$M_OPT_CMD) 3928 ! If done, exit the subroutine else execute the procedure & IF OPT = "DONE" THEN GOTO 6000 ELSE & CALL DTR$COMMAND(DAB BY REF, OPT) 3925 ! Now call dtr$dtr to run the procedure, when done, back to menu & CALL DTR$DTR BY REF (DAB,DTR$M_OPT_CMD) 3940 GOTO 3910 6000 CALL DTR$FINISH BY REF (DAB) 7000 END 18 This statement [at 100], right here, does an INCLUDE, and what that is, is that it includes something called the DAB. And the DAB is a little buffer that tells all the little goodie things that have to happen between the pro- gram and DATATRIEVE so that they can keep themselves straight. You go down here [at 190] and you declare some options for when you are going to open up DATATRIEVE. You come down to here at this point [at 500] where it says 'RET[urn_]STATUS = DTR$INIT' - that kicks DATATRIEVE in the tail and says "Get moving, it is time to go here" - [and] gets DATATRIEVE running. [Question from Bob Lott] "Is that a performance improvement?" [Jasmann's answer] Well, that is just a little newdge [nudge] to make it go to work. At this point in the program I call DTR$COMMAND and set a dictionary into a dictionary [at 2405] and that is just because I was using a test dictionary and I did not want to muck up my regular dictionary. [Note that] every time you do a DTR$COMMAND you have to do something afterwards to clear out a buf- fer, which DATATRIEVE comes back and tells the program that I [DATATRIEVE] did what you wanted to do successfully or else I did not. The easy way to do it, although probably not the cleanest is just to call DTR$DTR [at 3920], and it will just flush it right out. So you will see this happen several times [at 3920, 3926, and 3935] where you would otherwise not think it was necessary to do anything. The next thing that it does is it calls DTR$COMMAND [at 3910] and it calls a procedure called MENU and this is the procedure that is actual- ly going to paint the menu. Here is the procedure MENU. delete menu; define procedure menu set abort declare qst pic x. ready pt write Print "This is the main menu", skip 2, col 5,"1. Option 1", col 5,"2. Option 2", col 5,"3. Option 3", col 5,"4. Done", skip 2 qst = *."1, 2, 3, or 4" end_procedure All it does is declare a variable which has a PIC X. It readies PT (now PT is a port). If you look right here it says "I have a record PT_REC and a port (DEFINE PT USING PT_REC). So all that is is a little port which just looks like a regular ol' domain only it is called a port. delete PT; define port PT using PT_REC; delete PT_REC; define record PT_REC using 01 pt_rec. 03 opt pic x(10). ; It prints the menu, and it asks "[in the variable] QST [for QueSTion] - WHICH OPTION DO YOU WANT - 1, 2, 3, OR 4" for whichever option you want to do. And then the menu goes away and that is all that it has to do. 19 After it does that, after you call DTR$COMMAND, and you tell DATATRIEVE to run the menu, and you call DTR$DTR [it] calls the terminal server and allows the menu to [be] display[ed] on the screen, and asks you for a variable - for a prompt for the value for QST. The next thing that I do, is do a DTR$COMMAND and I use the contents of this variable which says STORE PT USING OPT = QST VIA [the] TRANS_TABLE. TRANS_TABLE is a little domain table and the only thing it does is, it just relates the number that was one of those four (4) numbers in the menu to a particular procedure name. delete trans; define domain trans using trans_rec on trans.dat; delete trans_rec; define record trans_rec using 01 trans_rec. 03 num pic x. 03 pro pic x(10). ; delete trans_table; define table trans_table from trans using num : pro end_table ; ! [The following three procedures would be helpful] ! [in testing the call interface with the BASIC program] ! delete test1; define procedure test1 declare foo pic x(10). print "This is TEST1" foo = *."foo" print foo end_procedure delete test2; define procedure test2 declare foo pic x(10). Print "This is TEST2" foo = *."foo" print foo end_procedure delete test3; define procedure test3 print "This is TEST3" end_procedure After you have done that, you do a DTR$GET_PORT [at 3925] and a GET_PORT just takes that stuff which is the procedure that was referenced by the number and pulls it in the port in DATATRIEVE, actually at the DATATRIEVE end that stuffs it in the port, -- NO. The ST$ stuffs it in the port [at 3923], the GET_PORT pulls it out of the program and at that point the variable OPT equals the name of the procedure you want to call. The next thing you do is you clear the 20 message from the buffer again [at 3926]. If OPT=DONE which was the fourth option, then the thing exits, otherwise you do a DTR$COMMAND, and what you tell it to do is OPT which is the name of the procedure. Then you call DTR$DTR [at 3935] which runs the procedure or whatever it is you want to do. And when it exits, it goes back and calls the menu again. Really what you are doing is you just have a program, and the menu procedure essentially tells the program what procedure you want to run next, and the program turns around and tells DATATRIEVE to run the procedure. The program never has to know what procedure is going to be called next so you can use the same program without re-compiling essentially in any situation just as long as you have a procedure named MENU - as you put something back through the port it will do whatever you tell it to do next. The whole procedure is about 30 lines of BASIC. It is very, very simple BASIC. If you can do this with a call interface, you have done enough so that you can do just about anything else that you want to do. You can elaborate on this with UDK's [user defined keys] and all sorts of things. The main point is that it is very nice for menus and it is very easy to do and the call interface isn't all that hard. [Applause] [Question from the floor from an unidentified speaker] "I have a question pertaining to DATATRIEVE-11 concerning that. First of all due to the incred- ible speed of DEC Direct I don't have any DATATRIEVE[-11] Version 3 documen- tation, but I cannot find where I get the DATATRIEVE access block definition. I want to do this out of BASIC PLUS 2 and DATATRIEVE-11 and my question is where is the DATATRIEVE access block definition, and can I do the %INCLUDE like you did?" [Jasmann's Answer] "I don't think you are going to get this done in DATATRIEVE-11." [Questioner from the floor] "Yes, you can do it now." [Several others from the floor] "Yes, there is a call interface in DATATRIEVE-11 Version 3. [Other speaker] "You have to copy it right out of a book" [Bob Lott] For those of you who might not have heard that answer, Terry commented that he did not know exactly where the DAB was but that a call interface is on the 11. [Another unidentified questioner] "Terry, my question is can I have two DAB's in my program?" [Terry ] "I am not too sure why you want to use two DAB's but the way I use two DAB's is to have two independent record streams. You do two DTR$INIT's on the DAB's and have two independent records streams." [Questioner] "The reason why I wanted two DAB's is because I need a DAB for each node of DATATRIEVE-11." Phil Naecker I have a simple and relativity mundane magic. How many of you have tried to use callable DATATRIEVE? And have any of you tried to write function defini- tions? For those of you who haven't tried to write function definitions - the reason maybe that you cannot figure out, in every case, how to generate the function definition file, that is - how to extend the DATATRIEVE at the bottom and add functions into it. So I called my magic "Programming in VAX 11 DATA- TRIEVE or The DATATRIEVE to MACRO Code Generator" because that is what we do. As everyone well knows, it was Bell Labs that did a study awhile back that said that on the average of the time, there were two lines of codes generated in any language per man-day, or as I like to say one before lunch and after. Knowing that I have discovered that is was much easier to fill in forms. By putting in the forms with the right fields -- answering the fields and putting the right data in I could write MACRO which I cannot write in any other way. 21 I sat down and wrote a record definition for the function. I think the guys in [doing] the DATATRIEVE documentation [group] have done the same thing, it is not very difficult to do. You make a record that has all the fields in it that are required in the DTR function definition file. These are basically things like the function name that you are going to add, and the external name of that function, and the subroutine that you add, and a few other things like that like how many arguments, and what kind of arguments the are. That is not terrible difficult, you write a record definition. I will go ahead put that into the DATATRIEVE SIG library. You make a domain with functions and actual- ly you can even do a make a domain functions using functions on FUNC.DAT and put a form definition in there if you would like, which is what I like because I can type on forms very easily and make mistakes and backup when I am writing in MACRO. define domain functions using function on funct.dat; define record function using 01 data. 03 function_name pic x(32). 03 external_name pic x(32). 03 number_of_args pic 99. 03 . . . ; So - the next step is trivial - I did not put it all on the overhead, I will submit it to the SIG again, but basically you define a procedure called BUILD_DTRFND, you ready the functions domain, for those FUNCTIONS SORTED BY FUNCTION NAME BEGIN PRINT. In your print statement there is a fairly compli- cated set of IF-THENs and choices and stuff like that. It is not all that difficult and what comes out of it is what looks like MACRO. If you have ever read the DATATRIEVE-32 callable manual at the back there is an example of all the MACRO in there that one has to be a MACRO programmer to generate it. Since I do not know how to do that very well and can't reliably remember all the options, I wrote once a DATATRIEVE definition that did all the rules that they gave me and I simply program all of my DATATRIEVE functions by forms now. [Applause] Diana Washburn, Hanes Hosiery, Winston-Salem, NC This is a little bit of magic I don't know if you can read this very well now, but I will tell you real quick what it does. This one is dedicated to SPR people. This is the old problem of having a number starting with a zero in a key field even if it is PICTUREd X. There are a couple of problems here. DTR> FOR CUST WITH OUTLET = 00006,00013,90014,90017,27652 [Looking for statement] CON> PRINT OUTLET, REGION OUTLET REGION 90014 99 90017 99 27652 01 One - and you will notice that this first thing says FOR CUST WITH OUTLET = 22 and then there are 5 numbers, two of them begin with a zero. [It] says PRINT OUTLET IN REGION. We only get the three that do not begin with a zero, and it just does not show the other two at all. DTR> FOR CUST WITH OUTLET = '00006','00013',90014,90017,27652 [Looking for statement] DTR> PRINT OUTLET, REGION OUTLET REGION 00006 99 00013 99 90014 99 90017 99 27652 01 Down below that [just above here], if you put the quotes around it is just to show that you get all five - and it shows you that all of them are there. Now if you want to get real fancy and you want to put in a prompting variable and say 'all right, FOR COST WITH OUTLET = *.OUTLET' and then let them actually ask for it. It comes in and says 'Enter OUTLET', if you enter more than one there, and put commas in between them you come back with a nice DATATRIEVE prompt and no data. DTR> FOR CUST WITH OUTLET = *.OUTLETS [Looking for statement] CON> PRINT OUTLET, REGION Enter OUTLETS: 00006,00013,90014,90017,27652 DTR> ![Note that there is no output] It won't take the multiples, it does not recognize the comma, it thinks it is just one big long string. This was a problem for us and we wanted to get around that. If you do the prompt and you enter just one outlet, I put that in there just to make sure everybody knows that does work, and you do get the one guy back again. DTR> FOR CUST WITH OUTLET = *.OUTLET [Looking for statement] CON> PRINT OUTLET,REGION OUTLET REGION 00006 99 Ok, now to solve this, we wrote a procedure. Now in the procedure I simply do, and I call this [procedure] FOR_OUTLETS, so that in the case of this rather than saying FOR CUST WITH OUTLET =, they would just do :FOR_OUTLETS in this case it declares a variable, in this case 89 long, that is in order to hold 15 separate numbers. The very first that it does in the procedure after it SETS DATA_IN = a prompt, which says ENTER UP TO 15 FIVE DIGIT OUTLET NUMBERS SEPARATE BY COMMAS, it says FOR COST WITH OUTLET = and it uses the function EXTRACT and from data in it takes the first five, then it takes the next five and then the next five. 23 DEFINE PROCEDURE FOR_OUTLETS DECLARE DATA_IN PIC X(89). DATA_IN = *.'Up to 15 5-digit outlet numbers separated by commas' FOR CUST WITH OUTLET = FN$STR_EXTRACT(DATA_IN, 1,5), FN$STR_EXTRACT(DATA_IN, 7,5), . . . FN$STR_EXTRACT(DATA_IN,79,5), FN$STR_EXTRACT(DATA_IN,85,5) END_PROCEDURE DTR> :FOR_OUTLETS Enter Up to 15 5-digit outlet numbers separated by commas: 00006, 00013,90014,90017,27652 [Looking for statement] CON> PRINT OUTLET, REGION OUTLET REGION 00006 99 00013 99 90014 99 90017 99 27652 01 Now there is no problem in here as long as you do not have any spaces in those fields. If you had spaces in there, of course, if you only enter three, you would end up looking for everything that had a space in the field. If you do have an index that had spaces you can load NULL KEY and set it up with the space being the NO value so that you would not have to worry about that as long as it was an alternate index, you could do that on your file. So that is one alternative. Just to show you that it does work down here, just say :FOR OUTLETS, it comes back and prompts for up to 15 five digit outlet numbers separated by commas, you can put in however many you want to up to 15, of course, that number could be incremented also if you put in more of the functions in that particular procedure, and of course it comes back and it prints all of those for you. Now the neat thing is that you can also add to that, you can go ahead and include into the RSE, you can say :FOR_OUTLETS AND REGION = 99, in which case if you will notice here, DTR> FOR_OUTLET AND REGION = 99 Enter Up to 15 5-digit outlet numbers separated by commas: 00006, 00013,90014,90017,27652 [Looking for statement] CON> PRINT OUTLET, REGION OUTLET REGION 00006 99 00013 99 90014 99 90017 99 I put in the same outlet string and it comes back with those that were in 24 region 99, it leaves out the one that is in region 01 that was in the previous thing [example]. It is really kind of a nice thing. If you are doing something in a procedure where you have to key them all in anyway, it is no big deal, but if you are interactively sitting down doing queries and you do not want to key that in, especially if you do not want to have to worry about putting quotes around everything that has a zero (0) in the front of it, it keeps you and allows you to be able to just leave prompting kinds of things. I did it with FOR. The very same thing works with FIND. DEFINE PROCEDURE FIND_OUTLETS DECLARE DATA_IN PIC X(89). DATA_IN = *.'Up to 15 5-digit outlet numbers separated by commas' FOR CUST WITH OUTLET = FN$STR_EXTRACT(DATA_IN, 1,5), FN$STR_EXTRACT(DATA_IN, 7,5), . . . FN$STR_EXTRACT(DATA_IN,79,5), FN$STR_EXTRACT(DATA_IN,85,5) END_PROCEDURE DTR> :FIND_OUTLETS Enter Up to 15 5-digit outlet numbers separated by commas: 00006, 00013,90014,90017,27652 [5 records found] DTR> PRINT OUTLET, REGION, ISIS_FLAG OUTLET REGION ISIS 00006 99 00013 99 90014 99 90017 99 27652 01 1 DTR> :FIND_OUTLETS AND ISIS_FLAG='1' Enter Up to 15 5-digit outlet numbers separated by commas: 00006, 00013,90014,90017,27652 [1 Record found] DTR> PRINT ALL OUTLET,REGION,ISIS_FLAG OUTLET REGION ISIS 00006 99 1 It really does not slow anything down, it is a little bit slower than if you keyed them in, but for me it is faster because it takes me so long to key them in, you know, with the fact that you have to all the little goodies around it, so it is really not bad at all. Just one little thing, if you do not have the ability to load something in with a NULL KEY, for instance if it is not a key and you wanted to this kind of thing against it, you can do it another way, and this was something that 25 surprised me. I did not think that it would work until I tried it. DTR> FIND CUST WITH ACCT = PKV,202 "PKV" not field, assumed literal. Non-digit in string "PKV", ignoring character(s). Non-digit in string "PKV", ignoring character(s). Non-digit in string "PKV", ignoring character(s). Non-digit in string "PKV", ignoring character(s). [56 records found] DTR> FIND CUST WITH ACCT = 'PKV','202' [56 records found] DEFINE PROCEDURE FIND_ACCTS2 DECLARE DATA_IN PIC X(59). DATA_IN = *.'Up to 15 3-digit ACCT codes separated by commas' FIND CUST WITH ACCT = IF FN$STR_EXTRACT(DATA_IN, 1,3) NE ' ' THEN FN$STR_EXTRACT(DATA_IN, 1,3) ELSE '000' IF FN$STR_EXTRACT(DATA_IN, 5,3) NE ' ' THEN FN$STR_EXTRACT(DATA_IN, 5,3) ELSE '000' . . . IF FN$STR_EXTRACT(DATA_IN,57,3) NE ' ' THEN FN$STR_EXTRACT(DATA_IN,57,3) ELSE '000' END_PROCEDURE DTR> :FIND_ACCTS2 Enter Up to 15 3-digit ACCT codes separated by commas: PKV,202 [56 records found] DTR> PRINT ALL OUTLET, ACCT,SREP OUTLET ACCT SREP 00049 PKV EA 01558 PKV DF 00051 202 XE 00052 202 XE . . . DTR> :FIND_ACCTS2 AND SREP = 'XE','EA' Enter Up to 15 3-digit ACCT codes separated by commas: PKV,202 [55 records found] It is the very same procedure, the only thing is that when you get down to the FIND or...actually I did this one with a FIND - you can do it with a FOR. All you do is after you say the equal, in this case we are looking at an account key, this key happens to have spaces in there, it is not loaded as null value space, so it is saying 'FIND CUST WITH ACCT = ' and then put an IF. If then you do an EXTRACT, you look at that particular position, the account field is 3 rather than 5 [characters long]. If it is not equal to a space then you use the value, otherwise, in this case zero (0), zero is not a valid account so 26 there will never be any. The only purpose for that is because again, like I said, if you only entered three, you would have nulls in all of the rest of them, and if you had spaces out there the file would try to get them. In this case, by making them zero I do not have any valid accounts with zeros in it, so it does not do that. It all works just fine. Again with this you can also add to the RSE, just at the invoke procedure level. That is for the SPR team. [Applause] Jim Starkey, Digital Equipment Corporation This is one of great historical importance and significance. One of the very first Wombat Magic presentations was on restructuring a file. How many of you have ever felt the need to restructure a file? Isn't it a lot of fun? NO!! Well, I went off and I did a little bit of coding and now two, no three years later I have a way to restructure a file that is a little bit better. Here is a DATATRIEVE procedure and let me just warn you up front that there are a few restrictions, like this only works with this Rdb/ELAN. [Laughter] [Indirect pitch to buy a MICRO-VAX, with more laughter.] This is a procedure to add a field to an existing data base without doing a restructure, without leaving DATATRIEVE, and without going nuts. I am going to start by READYing three magic domains. One is called RDB$RELATIONS, one is called RDB$FIELDS and one is called RDB$RELATION_FIELDS. Very briefly, RDB$RELATIONS is a list of all of the relations in the database, RDB$FIELDS is a list of all the fields in the database, RDB$RELATION_FIELDS says which field is in which relation. define procedure add.field ready rbd$relations write, rdb$fields write, rdb$relation_fields begin declare relation pic x(31). declare field pic x(31). relation = *.relation if not any rdb$relations with rdb$relation_name eq relation store rdb$relations using rbd$relation_name = relation field = *.field if not any rbd$fields with rdb$field_name eq fields store rdb$fields using begin rdb$field_name = field rdb$field_type = *.type rdb$field_length = *.length end store rdb$relation_fields using begin rdb$field_name = field rdb$field_source = field rdb$relation_name = relation end end commit end_procedure [I've] got a BEGIN_END block there just to be neat. Declared a temporary just for a relation name, 31 name characters just like VAX names are, too long or 27 too short. Another field for field, to hold the field name that I am going to add to a relation. Okay, I am going to prompt for the relation name and store it in the field. That is simple. Just in case that relation did not exist, it is going to check to see if it existed and if that relation did not exist, it would store a record in our RDB$RELATIONS. That has the same effect as to finding the field in RMS. That will create the new relation if it does not exist. Then I get a prompt for a field name and do approximately the same thing to RDB$FIELDS - going to check to see if that field already exists - as you will learn in sessions hence, all fields in the RDB products are global to the database - you define them once in FIELDS and then you reference them in RELATIONS. If the field does not exist, it is going to store the field name, it is going to store the field type which is an VAX data type, store length and that is that -- now you have a new global field in the database. Finally it is going to store a very simple record into RDB$RELATIONS_FIELDS, do a commit. And that is it! Invoke the procedure, answer [the prompt for] two names, and you add a new field to a database. [Applause] [Bob Lott] For those of you who are new to DECUS and/or DATATRIEVE, I'd just like to comment, that Jim Starkey, was the guy that we can blame for all those damned yachts. [Laughter, followed by boos] By the way, some of the family members in some of those domains are Jim's family. He's also responsible for the wombat. [Jim] Also two cats . . . Idris M. Dawud, Technicare Corporation, Solon, OH The problem I encountered which I had to use a little bit of WOMBAT MAGIC was . . . In order to execute a number of different procedures which did similar types of things only they were different, and the differences could be re- flected very well in the way the names were made up. Procedure names such as: INV_GEN_GAGE REPCAL_GEN_GAGE MSTR_GEN_GAGE INV_SEL_GAGE REPCAL_SEL_GAGE MSTR_SEL_GAGE I am only giving six examples here and as you can see, the first part of the name and the second part of the name are different, but in actuality all three of the names were different. It took a cumbersome procedure first of all, a cumbersome procedure filled with IF statements -- IF such and such do this, IF such and such do that. I had a little help with a CHOICE statement that came out in the last release. Basically this is what it called for. DEFINE PROCEDURE ---- . FORM = *."WHICH FORM TYPE [1, 2, OR 3]?" CARD = CHOICE OF FORM = 1 THEN "INV" FORM = 2 THEN "REPCAL" ELSE "MSTR" END_CHOICE METHOD = *."WHICH METHOD TO USE [GEN,SEL]?" 28 TYPE = CHOICE OF METHOD = "GEN" THEN "GEN" METHOD = "SEL" THEN "SEL" . . END_CHOISE . . . DO_THIS = CARD|"_"||TYPE|"_"|"GAGE FN$CREATE_LOG("PROC","DO_THIS") . . . END_PROCEDURE The user was prompted for a method they wanted to modify a record, for example, either a general modification which would keep going on through every record in the database until they hit CONTROL C or whatever or a selective modify which is they would prompt for a specific key. They were also prompted for whether they wanted form 1, 2, OR 3 which turned it out to be either an inventory card, a repcal card, or a master gauge control card. So after re- ceiving this information in the form of variable 1 and variable 2, you issue a choice statement which basically says if the form = 1,2 or 3 then the card (card being another variable) would equal either inventory, repcal, or master; and card is a symbol [variable] and form is a symbol [variable]. You have similar choice statements to do the same thing. For example if a person selected 1, then card would equal inventory - INV. Then for the second vari- able you would say if method equal either general or selective then you give the second variable with either equal general or selective. You can do this on and on and on for a number of variables. I do not know what limit DATA- TRIEVE puts on procedure names, but that would be the the limit at which you could do this. Afterwards, you'd make a third symbol [variable] I'd just call for simplicity DO_THIS equals CARD which is one variable or symbol concate- nated to an underscore, concatenated to TYPE which is the second variable, concatenated to to an underscore, concatenated to either a literal like this ["GAGE"] or another variable. Like I said you can go on and on. For the purpose of making our procedure names which are written in this form once again. So DO_THIS ended up equalling, in my example, INV_SEL_GAGE, Inventory Select gauge, concatenated together to a DATATRIEVE symbol which you can exe- cute as a procedure or domain or anything else. Then you use the DATATRIEVE function FN$CREATE_LOG, then you give a logical name to the symbol name which makes it now executable whereas the symbol wasn't executable in the past and then the end result is you can execute any one of your procedure names by just - well, essentially just patched variable short words together to make a long procedure name and this saves you a lot of time and makes it more readable if someone goes through your code. I found it very useful. Also I found it useful to - once you have that logical inside your procedure you can also do FN$TRANS_LOG and you find out where it is and go on and play with logicals back and forth between the create and the translate back and forth to do a number of other things. Like you can READY it as a domain also and anything else you can do with DATATRIEVE elements in the dictionary you can do with the logical. [Applause] Jay Vander Wall, Dow Chemical The problem here is to get some input from a user and provide data validation and HELP without the use of the form because we have to support dumb terminals 29 like ADM30's and that type thing. So what I did is I declared a variable HOLD_MANAGER and I made a VALID IF the manager was in a table OR if it was equal to a question mark. Then I went down where I wanted to get my input and put in set HOLD_MANAGER = "?", went into a WHILE LOOP and said 'WHILE HOLD_MANAGER = "?", and inquire the managers name or ?(question mark) for HELP. Then I went into an IF statement which said IF HOLD_MANAGER = "?" then it printed all the names of the managers that were in the table and provided them help, went back up and repeated the query. declare hold_manager pic x(14) valid if (hold_manager in mgr_tbl) or (hold_manager = "?"). hold_manager = "?" while hold_manager = "?" begin hold_manager = *."manager's name ( for help)" if hold_manager = "?" then print all name of managers end Wade Scannell, Ship Analytics I was up in the DATATRIEVE SIG earlier and they said that they wanted to see some real simple magic, so my magic is quite simple. There is a little story behind it, but what I am going to talk about is DATATRIEVE data retrieval. We all know DATATRIEVE does data retrieval but I am going to do it without files, without RDB, without tables, without any of that crap. The story behind this is that somebody came up to me one day a couple of months ago and they wanted to know something about days of the week and they were looking for a perpetual calender. I said, "Hech, I've got a perpetual calender right on my desk." They wanted to know what day of the week they were born or something like that. So I said, "Here, I'll find out for you." I logged into DATATRIEVE and typed DTR> PRINT "14-SEP-54" USING W(9) and it says "Tuesday". So we have the DATATRIEVE perpetual calender. [Laughter and applause] Bob Lott, E. I. DuPont, Wilmington, DE This one I've titled AUTOMATIC LOGIN. It is really sort of VMS and DATATRIEVE magic. It is really VMS, but because I manage it with DATATRIEVE it sort of comes under DATATRIEVE magic too. This is an undocumented feature but when you log in, that procedure or process first looks to see if there is a file on your system called SYSUAF.DAT. If that file exist, it will do the login based on entries in that file. Let me demonstrate what I am talking about. 30 define domain alfs using alf_rec on sys$system:sysalf.dat; define record alf_rec using 01 alf_rec. 05 tt pic is x(63). 05 user pic is x(65). ; First of all the file is an indexed file with a domain definition for which I have shown SYS$SYSTEM:SYSALF.DAT and the ALF stands for automatic login file or auto login file or whatever. I have also shown a record definition for that file, two fields within a record and the first one is the terminal number and it is a sixty-three byte record [field]. The second record [field] is the - what I have shown as user - I really define these down below. But TT is the terminal I. D. with the underscores as I have shown - underscore TT1 colon (_TT1:) in example. The user is actually the account name. Now I work for a chemical company and we have operators that are very unfamiliar with computers, we would like to have them log into what we call a slave account which is really captive, and so the account name that we use is SLAVE so when the guy walks up to the terminal and hits a return he is logged into a captive command procedure which is specified in the user authorization file for account SLAVE, so he never enters account name, he never enters a password. I manage this file again with DATATRIEVE because it is an indexed file and it is a very simple way to manage an index file. This is not documented but it works. [Applause] [Editor's Note: An article, How To Create "TIED" Terminals Under VMS, by Jay Wooten, which appeared in Volume 6, Number 2, pages 3 to 11, of the August, 1984, PAGESWAPPER, very carefully explains this undocumented feature of VMS. That article uses seven pages to show how to manage this file without DATA- TRIEVE. As we all know, with DATATRIEVE it's a snap.] Pat Scopelliti, Corning Glass Works This is actually not DATATRIEVE magic, this is actually magic being done on DATATRIEVE. Sort of getting back at it. What this is, is making a plots function on your VT240, more or less. [Scattered applause] This works on Version 1.3 and also Version 2.0. Problems on a VT240 are two. First as it draws a plot, it starts scrolling. Bummer ... Second, [laughter] and even worse is that one your very next entry it erases the screen. It actually does not do that, it just turns it off, which is even worse. The reasons are quite simple if you think about it, and it is all due to wonderful DEC and I will not call them Digital until they quit selling DECSlide, and DECGraph, and DECWriters and whatever else they sell. First of all, the VT240 has both its graphics and its text in the same plane. So that when you scroll, everything scrolls -- problem. Second, DTR actually turns off the four mapping graphics registers - it just simply turns off the lights, and that is why the screen goes blank. What it actually does is it issues the command at the bottom. Pps(m0(l0)1(l0)2(l0)3(l0))\ Two things to do. First keep it from scrolling and second keep it on the screen. First one is pretty easy. You get in [CDD$TOP.]DTR$LIB.VT125 - you EXTRACT every single plot with one little line, you then get in there and edit that file whatever it was and change every single PRINT EXIT_REGIS line to 31 PRINT EXIT_REGIS,"[H" DTR> set dictionary cdd$top.dtr$lib.vt125 DTR> extract all on vt240.com DTR> exit $ EDIT vt240.com * s /print exit_regis/print exit_regis,'[H'/ %wh ! [in concept] * exit $dtr DTR> set dictionary cdd$top.dtr$lib DTR> define dictionary vt240 DTR> set dictionary vt240 DTR> @vt240.com That at the end of every single plot [it] leaves your cursor at the top of the screen. Scrolling is solved. Of course on the next line, it still blanks out the screen. By the way, you then put this all back in into a separate area called VT240 that way you can easily pick am I at a VT125 or a VT240 and set your plots to the correct spot. If you can't figure that out, the rest of this will really bore you. The next part is you sort of have to close one eye and not think too much about what is going to happen. [Tittering from the audience] DEC sort of has problems with this, but this works and DEC won't fix it until version 3.0. What you have to do is simply get in.... [Bob Lott] "There not going to fix it then." [Pat] They aren't? Version 3 is not fixed? No answer from the crowd! [Editor's note: The problem of VT240 graphics support from DATATRIEVE is a very complex issue. VAX-DATATRIEVE can't properly support VT240 graphics until VMS properly supports the VT2XX terminals. If DATATRIEVE V3.0 is re- leased before VMS 4.0, then support for a VT240 in DATATRIEVE will not appear until VAX-DATATRIEVE V3.1. Thus, Pat's unconventional and daring "patch" is of considerable practical interest to VAX-DATATRIEVE users with VT240 and VT2401 terminals.] No problem, I don't care; I'll just fix it!! [Laughter] Get into the image file, find that little Pps(l0 . . .and so forth, and just eliminate it. [Laughter] And this works! Keeping in mind that VMS does not know what is in the image, thank goodness, and it simply loads in what is there. Luckily DEC has stored this in ASCII text - it is easy to find - methods are you can use DUMP and go looking through the ASCII portion until you find the right code - m0(l0)1(l0 and on and on and on. What you do is get out your hex calculator and you get in there and you simply NAIL THE SUCKERS! [Amazed laughter and applause] Now that was "Version 1.0" [Pat's solutions, first version] that I came out here with. 32 $! THIS PATCH IS FOR DTR V1.3 ONLY $! It enables DTR plots to function properly on VT240 terminals $! by replacing the ReGIS command $! Pps(m0(l0)1(l0)2(l0)3(l0))\ $! with nulls. The above command is sent to the terminal after any $! response to the DTR> prompt after a plot and causes all four output $! mapping registers to be set to lightness=zero. $! $ PATCH DTRV240.EXE SET MODE DECIMAL,BYTE DELETE 25254 = 27 ! DELETE 25255 = 80 ! P DELETE 25256 = 112 ! p DELETE 25257 = 115 ! s DELETE 25258 = 40 ! ( DELETE 25259 = 109 ! m DELETE 25260 = 48 ! 0 DELETE 25261 = 40 ! ( DELETE 25262 = 108 ! l [lower case L, not 1 (one)] DELETE 25263 = 48 ! 0 DELETE 25264 = 41 ! ) DELETE 25265 = 49 ! 1 [digit one] DELETE 25266 = 40 ! ( DELETE 25267 = 108 ! l DELETE 25268 = 48 ! 0 DELETE 25269 = 41 ! ) DELETE 25270 = 50 ! 2 DELETE 25271 = 40 ! ( DELETE 25272 = 108 ! 1 DELETE 25273 = 48 ! 0 DELETE 25274 = 41 ! ) DELETE 25275 = 51 ! 3 DELETE 25276 = 40 ! ( DELETE 25277 = 108 ! l DELETE 25278 = 48 ! 0 DELETE 25279 = 41 ! ) DELETE 25280 = 41 ! ) DELETE 25281 = 27 ! DELETE 25282 = 92 ! \ UPDATE EXIT $ or 33 $! THIS PATCH IS FOR DTR V2.0 ONLY $! It enables DTR plots to function properly on VT240 terminals $! by replacing the ReGIS command $! Pps(m0(l0)1(l0)2(l0)3(l0))\ $! with nulls. The above command is sent to the terminal after any $! response to the DTR> prompt after a plot and causes all four output $! mapping registers to be set to lightness=zero. $! $ PATCH DTRV240.EXE SET MODE DECIMAL,BYTE DELETE 99128 = 27 ! DELETE 99129 = 80 ! P DELETE 99130 = 112 ! p DELETE 99131 = 115 ! s DELETE 99132 = 40 ! ( DELETE 99133 = 109 ! m DELETE 99134 = 48 ! 0 DELETE 99135 = 40 ! ( DELETE 99136 = 108 ! l [lower case L, not 1 (one)] DELETE 99137 = 48 ! 0 DELETE 99138 = 41 ! ) DELETE 99139 = 49 ! 1 [digit one] DELETE 99140 = 40 ! ( DELETE 99141 = 108 ! l DELETE 99142 = 48 ! 0 DELETE 99143 = 41 ! ) DELETE 99144 = 50 ! 2 DELETE 99145 = 40 ! ( DELETE 99146 = 108 ! 1 DELETE 99147 = 48 ! 0 DELETE 99148 = 41 ! ) DELETE 99149 = 51 ! 3 DELETE 99150 = 40 ! ( DELETE 99151 = 108 ! l DELETE 99152 = 48 ! 0 DELETE 99153 = 41 ! ) DELETE 99154 = 41 ! ) DELETE 99155 = 27 ! DELETE 99156 = 92 ! \ UPDATE EXIT $ This afternoon I thought of a much, much better final thing [Pat's Version 2.0 solution] and that is instead of nulling out every single one, . . . what you really, really do is simply change the first four things [characters] to [2J and that will clear off the screen in a nice simple matter and you simply blank off the rest of the stuff either with blanks or nulls. There is a nice documented way to do that, supported by Mr. DEC and everything. [Laughter] I also could have done this in a BASIC job. It worked and it was easy. This is some of the patch, I will bore you with it and it uses VMS PATCH. To put the "[2J" [in] the first four delete lines are simply changed to modifies, I think is what the statement is, get out the little PATCH MANUAL [VAX-11 Patch Utility Reference Manual, AA-H785B] and instead of saying DELETE 25254 = 27 you say that MODIFY that [25254] equals 27, whatever 34 you need. And the four ASCII characters for [2J and that is it. If you rebuild DTR you'll have to go back in and find where those parentheses L zero and on and on or and fix them again. It helps to have a hex calculator with you. [Applause] Thomas (Tim) Mahaney, Naval Air Propulsion Center, Trenton, NJ I am employed by a small naval establishment on the east coast. Being small enough, we use DATATRIEVE in a dispersing application. For those of you who are not familiar with that it's make check registers, print checks. We actually print checks to DEC to buy equipment and software on occasion. This is really a description of what might be loosely termed DEC magic. We started this application in DATATRIEVE-11 on an IAS system. It ran very nicely for a couple of years and then we got a VAX and everybody went "Ooooh, a VAX!!" We were a little bit concerned about translating our DATATRIEVE applications to the VAX, but actually it turned out that everything went quite smoothly. We had very few problems. Most of the backup procedures that go to the final printing in the dispersing application checked out really well -- until the first check run. I must preface this too with the fact that I am not a DATA- TRIEVE guru, I am sort of a system manager type and my experience with DATA- TRIEVE is mainly a tool to support system manager functions so that when some- one calls me in a panic I really do not have all the answers. In this case the dispersing clerk called me almost in tears and said "Have you seen our checks?" I said, "No, I have not seen your checks, you printed them." As a matter of fact our checks are printed on a printer that is slave to a terminal off of a terminal port - a small printer. I walked over to the building that houses the accounting office and took a look at the one check that she had a sample of and I said "looks ok with me". The stuff was there; it had name/address/social security number/security classification and on and on and on. She said, "But look at the check, look at the check." I said, "Looks ok to me." It was for $192.92. [And the amount was to be ] written out in char- acters and then it says "AND NINETY TWO CENTS". Well it did not say ["One hundred ninty-two dollars"] whatever. It was then that we found that DATATRIEVE-11 truncates -- DATATRIEVE-32 rounds. The procedure that extracted the one hundred and ninety two dollars to put over before the dollars field used the fact that DATATRIEVE-11 truncated and rounded. That was lesson number one. I guess that the magic in this might be that one of the checks was actually to DEC. The further magic in it that in the 115 checks we print- ed there, approximately 90 were mailed already and none of them came back with any complaints. [Laughter] But - that is not the end of the story. About three months later we got DATATRIEVE Version 2.0. One thing that I avoided describing was the format that our checks were in. We print checks with stubs on top and check on bottom, it is a continuous marginally punched form. As soon as we put Version 2.0 in, the first check run same accounting clerk calls and said "Have you seen the checks?" "No, you printed them." So she said, "Come over here!" And sure enough, here are the checks. "Look at the stub." [And I replied,] "That looks great." And she said, "Now look at the check." It's blank! So magic number two from DEC is AT BOTTOM for version 2.0 did not work very well. The check printing procedure was a Report Writer [procedure] which had an AT BOTTOM and a long print statement to fill out the stub and the check from the information from one record. In the middle of it, it said AT BOTTOM OF whatever PRINT NAME, ADDRESS and then it said AT TOP [PRINT] NEXT PAGE [NEW_PAGE] after that - nothing. So I do not know if that is DEC's way of trying to reduce the national debit or . . . [Laughter] That's my story. 35 Don De Palma, Digital Equipment Corporation I was at a couple of the sessions this afternoon where people complained about CDD. I don't have complaints about CDD performance, but I do have a couple of complaints. One was that Frank Willison did not take up a job offer that I made sometime last year so that meant that I had to write about 700 pages of documentation over the course of the last nine months. It was a real pain. The other thing is I really object to anal retentiveness of certain aspects of the CDD language which get carried over into DATATRIEVE in the form of path names. I don't like typing path names. And I have thousands of logicals to defined, it just gets me tired after awhile to type the abbreviated [logicals]. I have a large directory structure with a lot of things under- neath it, each of which is associated with a logical name, but even so when I log in, I want to be reminded that I gotta set my directory or my default or my dictionary to wherever I want to work. So, in order to remind myself to not try to READY things that are not there, I put that print 'SET DICTIONARY '||*.'Dictionary name' on dicto.com @dicto in my startup file for DATATRIEVE. What it does is it prompts me for the dictionary that I want and then writes out SET DICTIONARY and then the dic- tionary name to a command file called DICTO.COM and then it executes it. And then I am there. That is it. [Applause] R. J. Woodland, Technicare Corporation, Solon, Ohio This concerns a feature of DATATRIEVE which is not exactly documented but it is useful anyway. The domain definition uses a logical for the file name and actually translates logicals rather than working on a physical file name which means you can make use of that in all sorts of good ways. One of the ways is in the case of this type of database where you have two hierarchies of variable length instead of one - normally that would be a problem - normally you're are only allowed to have one at the end of a record or something like that. What you can actually do ________________________ ________________________ | | | | | SITES | | SITES | | DATABASE | | DATABASE | | | | | |________________________| |________________________| | | | | ~ Hierarchy #1 ~ | Filename #1 | ~ ~ |________________________| |________________________| | | | | | Filename #2 | ~ Hierarchy #2 ~ |________________________| ~ ~ |________________________| 36 define domain sites using sites_rec on sites fn$create_log("SITES",filename #n) is to have two fields at the very end of that record which are obviously fixed length or whatever, which are file names and smash up the two - what you are calling the two hierarchies effectively into separate files. Now you can define the domain - in this case SITES using the record definition or a logi- cal and you can create a logical name with that same name or whatever the file name is from the record definition and then you can kinda chain databases together and have as many as you like. The true congratulations should go to Digital because they answered the SPR and kind of told me how to do this. [Applause] Jerome Alterman, U. S. Coast Guard, Juneau, AK I have this boss who went out one day and bought himself one of those little machines named after a popular fruit. He came into the office and said, "Hey this is neat, I can do all sorts of graphics!" I said, "We have a VAX; we got DATATRIEVE. You know DATATRIEVE; you can do anything you want!" He said, "Prove it!" So I showed him the Wombat. Of course the Wombat comes in two sizes right, your standard plot and then your BIG. He said, "That does not really impress me." So I said, "Well, being as we are in Alaska..." I am sorry I do not have a transparency, but it wouldn't fit the screen. I [got] a plot of Alaska. What is neat about it is that when it plots it on the screen, it will plot the horizontal and the vertical lines and then you can watch it draw the outline from the map. Of course what he did not realize is what it took me to do it. [Jerome held up and then dropped out of his hand the many, many pages of ReGIS graphic code to create the plot. Laughter and applause followed.] But he's happy because when people come in he goes "LOOK!" and this little thing draws all over the screen. Well it is not magic, but I did not understand the rest of the stuff they were talking about tonight! [Laughter and applause] [Editor's note: It is unfortunate, but it is not possible to reproduce Jerome's BIG graph of Alaska. Perhaps he can be persuaded to submit the ReGIS code to the SIG Library tape.] Paul Krug, Weyerhaeuser Company, Federal Way, WA Awhile back I was - this is a little bit dated because it just occurred to me when all the version numbers started with one (1). You will have to pretend for a minute that you do not have the advantages of the choice and sign function. What I wanted to do is define a maximum of a couple of my fields and return that as another computed by field and without even thinking at all I used the maximum statistical function which of course did not work, but having some background in math I decided I could create a conditional that would have the value of one IF A > B and 0 if it wasn't using this equation. | B - A | - ( B - A) ( A > B ) <--- -------------------------- 2 | B - A | 37 05 A_B_COMPARISON. 10 A USAGE INTEGER. 10 B USAGE INTEGER. 10 A_GT_B COMPUTED BY (FN$ABS(B - A) - (B - A))/2*FN$ABS(B - A). 10 B_GT_A COMPUTED BY (FN$ABS(A - B) - (A - B))/2*FN$ABS(A - B). 10 MAX_A_B COMPUTED BY A*A_GT_B + B*B_GT_A. I had a group field which really only had data for A and B in it and then I implemented this equation in this field called A_GT_B so that thing has a value of one (1) if A is greater than B and had a corresponding field B_GT_A that was one (1) if the opposite was true and only one of those was true and my last field was MAX_A_B which was A times A_GT_B PLUS B TIMES B_GT_A. Since only one of these two things can be one it would return the value A or B. I had to modify that a little bit because there is a problem when A is equal to B, I get division by zero (0) and I did that by adding another field in here - A_EQ_B. I still got an error when A is equal to B but I found that it only printed to the screen and caused trouble for me if I printed that field, but if I printed the field MAX_A_B it never came to the screen so I got away with it and that is a bit of a klugy solution - And that is my magic. [Applause] Mary McKinzie, WABCO, Peoria, IL We had a little problem setting up a menu for several reports for our users. Our users do not really like to read at 132 columns on their VT100 unless it is absolutely necessary. We wanted to print the menu at 80 column and the report at 132 columns. So we thought that would be easy, we have these won- derful functions FN$WIDTH. So we set up with a WHILE LOOP so that as long as the option is not equal to zero (0) which is what they use to get out, it prints the menu with report options and all the choices and then do a FN$WIDTH 132 and print the report. Then in FN$WIDTH change back to 80 and reprint menu. opt = 13 while opt ne 0 begin print "Report Options" . . . fn$width(132) if opt = 1 :report1 . . . fn$width(80) end Well . . ., it did not quite work that way. DATATRIEVE has this wonderful thing called optimization. What that means is it takes the FN$WIDTH out - changes the screen to 132 columns at the beginning and that is it folks, that is the way it stays. I must give credit for the solution to my colleague because he did a lot of the work finally working it out. 38 declare c132 default value is ". . ." !["[?3h"] declare c80 default value is ". . ." !["[?3l" lower case L] opt = 13 fn$width(132) while opt ne 0 begin print c80,"Report Options" . . . print c132 if opt = 1 :report1 . . . end What we came out with, we declared two variables. One of them you put in the escape sequences for setting a VT100 to 132 columns and the other one for setting it to 80 columns and I don't happen to remember what those are. Then you print that instead of using your FN$WIDTH statement so when we print our menu we print the escape sequences to set it to 80 then print our menu, then print the escape sequence to set it to 132 columns and print the report. You still have to do the FN$WIDTH 132 at the very beginning so that DATATRIEVE knows that you are going to use 132 columns otherwise it gives you tiny char- acters but still wraps around. [Applause] Glenn Dimit, Jet Propulsion Lab At our installation we do about 95% of our DATATRIEVE work through the call interface. And for historical reasons we do it all through C. There are a couple of problems that crop up - not terrible major but rather irritating. For one, the call interface loves descriptors. C, for those of you who [don't] program in C, knows nothing of the descriptors, so every time you want to put a value into a call to DATATRIEVE you have to construct a descriptor packet which isn't difficult but it's very much a pain. The other thing is we tend a lot to generate record selection expressions on the fly and built them up in a program, and when you are trying to debug a program, if you just go to the call interface directly you can't see what the command is unless you set break points before you go on [the call to] DTR$COMMAND and generally it's a big pain. { external integer dtr_trace dtrcommand(cmd,type,p1,p2,p3,...) char *cmd, *type . . set up description depending on "type" . dtr$command(...cmd...) if(dtr_trace) { parse cmd, and print substitution directives } } 39 So what we did is we constructed a layer on top of the DTR$COMMAND routine that what it does is, you pass in the command here - this is a string variable that just indicates the type of descriptor that follow in the argument going further to the right and these are all the address of the argument. What we simply do is, we construct the command, pass it to DTR$COMMAND like you would normally, but then down here you have an option that if you set this external variable which is the same thing as a FORTRAN common block variable or some- thing, and inside here we parse the command line that you do searching out all the substitution directives, put everything back in and print out the lines so that as the program executes you can see the actual command you submit to DATATRIEVE. When you are trying to debug the program I think that is magic. [Applause] Bert Roseberry, U. S. Coast Guard, New Orleans, LA Basically one of the uses that I have found for DATATRIEVE is - I use it some- what in system tuning. What I have here is I have two record definitions. define domain ws using ws_rec on ws.dat; define record ws_rec using 01 ws_rec. 02 acct pic x(13). 02 wsize pic x(2) valid if wsize eq "MG","WO","CD","HD"," ". ; define table ws_tbl from ws using acct : acct end_table define domains wstmp using wstmp_rec on sys$system:sysuaf.lis; define record wstmp_rec using 01 wstmp_rec. 02 filler pic x(21). 02 acct pic x(13). 02 filler pic x(98). ; define table wstmp_tbl from wstmp using acct : acct end_table The bottom record definition [and the] associate[d] domain is called WSTMP. What this is, is this is used with your output when you run authorize and get a listing/brief. Up at the top I have WS_RECORD [WS_REC]. What I want to end up with in WS_RECORD [WS_REC] is the name of all the users that are in my authorize file plus another PIC two characters big called WSIZE. What WSIZE is it has five possible choices - we classify users as to how they use the system - MG would be for message, WO would be for word processing, CD would be for casual DATATRIEVE and HD for heavy DATATRIEVE use. By going ahead and classifying these people this way, I can set up working set sizes based on this and I'll show you how I do that. 40 define procedure wsout set abort print " " print " This procedure is used to generate a command file" print " that can then be invoked while in AUTHORIZE to" print " modify the working set parameters" print " " print " Is this what you want to do?" print " " if *."Yes or No" cont "N" then abort "Okay be that way!" print " " print " It is necessary to create a command file for each" print " different type of user." print " " print " Is the user a" print " " print " CD Casual DATATRIEVE User" print " HD Heavy DATATRIEVE User" print " MG User of Message System" print " WO Word Processing User" print " " declare tyus pic x(2) valid if tyus = "CD","HD","MG",WO". declare wsdef pic 9(4). declare wsquo pic 9(4). declare wsext pic 9(4). tyus = *."two letter code for type of user " wsdef = *."size of working set default " wsquo = *."size of working set quota " wsext = *."size of working set extent " for ws with wsize = tyus print "MODIFY ","acct(-),"/WSDEF=",wsdef(-),"/WSQUOTA=", wsquo(-),"/WSEXTENT=",wsext(-) on *."name of command file " print " " print " File is now generated." print " Exit DATATRIEVE. " print " SET DEFAULT SYS$SYSTEM" print " RUN AUTHORIZE" print " @filename" print " " end_procedure Basically what I do here is I generate a command file. What that command file in it says is modify the name of the account and then I prompt them for what the WSDEFAULT would be, the WSEXTENT and the WSQUOTA and using that I come up with a big command file that would say for instance, MODIFY SMITH/WSDEF=500/WSQUOTA=600/WSEXTENT=700 It puts all this information in a command file. After I do that then I get out of DATATRIEVE, I set the default to SYS$SYSTEM:, I run authorize, I execute this command file, then it will go ahead and it will modify the work- ing set based on a type of user such as that user uses heavy DATATRIEVE you would probably want to set up their working set sizes pretty big. Thank you. [Applause] 41 Joe H. Gallagher, Cleveland Clinic Foundation, Cleveland, OH I would like to turn the tables, instead of present some wizardry I would like to ask for some wizardry from the floor. There is a particular nasty problem having to do with timing in the way the VT125 works. Since I can't figure this out, it must be wizardry. Now there are some wizards out there that I would like to know - how to make this work. If you execute an indirect command file inside of DATATRIEVE, and that indirect command file contains a plot and a hard copy, there is some timing problems while it [the hardcopy printer noisily makes the copy]. Then if you try to print something [immediately] after that, there is a resynchronization problem. DTR> @FOO where !FOO.COM contains plot wombat plot hardcopy print "That was a Wombat" Now obviously, there needs to be a command which says PLOT RESYNCHRONIZE. Except, that is printer dependant. Some printers go faster than others and it depends on how it is set up and you have to say PLOT PAUSE THEN PLOT PAUSE THEN PLOT PAUSE and you waste a lot of time sometimes or you do not waste enough time in which case you blow it, because there is garbage all over the bottom of the plot. Now, the question is, what goes there [just after the plot hardcopy and before the print "This is a Wombat"] in order to resynchronize so that the next print [statement] doesn't get garbled. [Jim Starkey] What kind of printer do you have? [Answer] LA100. [Bob Lott] I don't think it makes any difference, Jim. You can do a similar thing outside of DATATRIEVE where you are taking graphic output files from the export files from DECGraph, if you don't do the necessary amount of delay, and I think it is because of the buffering that goes on in the printer, you can't do a formfeed. [Phil] What goes there is the right kind of printer cable. You tell your VT125 and your printers to X/ON,X/OFF. [Bob Lott] I have a VT241 cable for my LA100 and with DECGRAPH, that does not do it. [Gallagher] The problem is not in the printer, the problem is in the VT125 - I am absolutely convinced. [Someone else from floor] On printer cable, there is a line for DTR (data terminal ready) [which must be used] [Gallagher] And also if the LA100 is set up correctly in that mode. [Bob Lott] I have a null modem cable. [Gallagher] So if you have the correct cabling, there needs to be nothing - is that correct? [Bob Lott] What cable is it then? [From the floor] . . .there is a switch in the LA100 itself for X/ON,X/OFF. [Gallagher] The X/ON,X/OFF is already set, that is for sure. [From the floor] ....watch your null modem cable - there is a lot of different type of modem...... you may want a very simple null modem cable .... [Gallagher] Would you believe that it is the standard cable that DEC supplies at great expense. [For Floor] That has nothing to do with it ... [Gallagher] So, This should work with the right cable if the two devices know about each other properly. [Jim Starkey] I do it all the time so it will work. [Gallagher] Thank you, that is magic. [Bob Lott] Would you consider proper cable number in the Wombat Examiner? We would all love to hear it, give us choices if it depends on the device. I 42 struggle with this myself. [Gallagher] I obviously have a problem because every VT125 and LA100 in my place has this problem. [Bart Lederman] It is refreshing to see that the software developers coming up with the hardware solutions, isn't it? [Laughter] [Editor's note: I must apologize to all because I did not properly explain this problem during the Magic session; it might have been due to the lateness of the hour or the quantity of refreshments consumed. The hardware configura- tion consists of a VT125 terminal with a LA100 printer attached to the printer port of the VT125. If one places the following statements in a command file for DATATRIEVE plot wombat plot hardcopy print "[5i" ! turn on copy of text to LA100 print "That was a Wombat" print "[4i" ! turn off copy of text to LA100 and then executes them from within DATATRIEVE, the hardcopy on the LA100 is besmirched. What happens is that the "" in the "[5i" arrives at the LA100 before the LA100 has completed the hardcopying. That is, there are still some (few) graphics symbols in the LA100's buffer. The causes 1). the LA100 to momentarily leave graphics mode, or 2). the following text, in this case "That was a Wombat", to be interpreted as graphics "symbols" rather than text. Which ever the case, the hardcopy is spoiled. After considerable experimentation, I found no combination of ESCAPE sequences or "PLOT PAUSE" which would always prevent the hardcopy from getting spoiled. (The only partial solution which I found that came any where close was to place a whole series of "PLOT PAUSE", perhaps as many as 15, after the PLOT HARDCOPY). My question to the audience of the Wombat Magic Session at Cincinnati was "What should one placed between the line "PLOT HARDCOPY" and the line "PRINT '[5i'" in order to cause the VT125 and the LA100 to resynchronize their activities. Since I did not explain the problem correctly, the audience was unable to give a solution. Later, however, I called Jim Starkey and explained the problem; he suggested that I create a dummy plot called RESYNC which would delay the execution of the line containing the ESCAPE sequence. I took his suggestion and created a new plot in the CDD$TOP.DTR$LIB.VT125 dictionary of the form delete resync; define plot resync entry 0 begin plot housekeep 0 plot housekeep 2 end end_plot This little dummy "plotting" routine really does no plotting; however, causes the VT125 to go into ReGIS mode (housekeep 0) and then go out of ReGIS mode (housekeep 2). The important thing is, that it will not go into graphic mode until the previous ReGIS graphics command (PLOT HARDCOPY) is finished! It thus has the effect of preventing the executions of any subsequent print or escape sequences. Therefore, the PLOT RESYNC will not complete until the VT125 is done with transferring is graphics screen dump to the LA100. 43 However, this command alone does not solve the problem. One of the reasons that this problem is never seen when operating interactively is that a print to the text screen of the VT125 causes a little kick to the LA100 to finish printing its buffer. When running as an indirect command file, the "DTR>" prompt is not displayed on the VT125 text screen, and thus, the LA100 "is not told to empty it's buffer". Therefore, to encourage the the LA100 to get its business done, one needs to print something to the VT125 text screen. I tried printing some spaces and some line feeds and that seemed to work, if I also put in another PLOT RESYNC. Thus my empirical solution to the problem (with a grateful acknowledgement to Jim Starkey) is the following plot wombat plot hardcopy plot resync print " ", skip 10, " " plot resync print "[5i" ! turn on copy of text to LA100 print "That was a Wombat" print "[4i" ! turn off copy of text to LA100 We have several VT125/LA100 workstations. This empirical "patch" works on all of them. I am not really sure why this works or if it will work for everyone else. However, I have yet to see a spoiled plot with these three extra lines added, but I must admit that I haven't tried all possible plots!] Terry Golden, Credit Swiss Some people can't afford some of DEC's software so you sorta do work arounds for their products. I am presenting mine here, and that is to essentially monitor your system with an output qualifier inside the batch command job in here. A little bit later on, like the next morning, all I do is I come back and I READY MONITOR, which is the output file. I've set up a table called MONDEF of all the symbols with the various types on the monitor record which are listed on the back of the utilities guide and in essence what I have done is trick the CROSS on a double basis, I'm addressed it here looking at modes so I find all the modes then go back and look at the modes that are in front of it. The way that the monitor utility records things is it records it in an accumulative basis, so what you are interested in is taking the second from the first and on for item [computing differences]. What I have done there in essence in the monitor record I've set up a set of compute field for the var- ious states of the executive. $submit monitor !start monitor under batch $dtr ! the next day run dtr DTR> ready monitor DTR> :mondef ! establish some definitions DTR> find monitor with type = modes DTR> find current cross monitor with rec.type > monitor.rec_type DTR> plot x_y all rec_time, ((kernal+exec+super+user)/ (kernal+exec+super+user+idle))("%CPU Used") DTR> plot connect DTR> plot lr 44 Now very simply what I do is just say PLOT X_Y - the reason I do that is be- cause [PLOT] DATE[_Y] does not work, it sort of gives you an access violation - all record time, that is the klunk values, in essence just add up everything except the idle time, divide that by everything including idle time, and you have a little plot that comes back and tells you what your percent CPU utili- zation is. What I usually do after that is follow that by states for I/O and file accessing so in essence I can draw little plots and say what sort of [things are] going on in the system. [Applause] [Request from the floor to put this in the Wombat Examiner and/or VMS Date Book.] [Golden] I will give you the record [definition] but it has like, it goes out to about 6 pages and we'll be here till 11 o'clock. [Larry Jasmann] We need to put this in the library. [Bob Lott] There was an undocumented utility that came somewhere in VMS called Meeter which gave you some pretty nice statistics for plotting CPU performance, disk usage, that sort of thing. In fact, I use that in my shop. Bob Lott, E. I. DuPont, Wilmington, DE This particular magic I call "DATATRIEVE Eliminates an IBM Cardpunch". A year ago this past January, we were faced with really having converting all our applications to the point that we did not need the key punch except for one. In this particular instance, we were sending some - in the DuPont Co. - something that we refer to FIXED ASSET VOUCHER DATA to some business systems in Delaware over a remote job entry link and in keypunching this data, the way they showed negative values, or credits if you will, they did it by over- punching the last digit. Some of you are familiar with it, I see some nods and hear some yeps. Well we wanted to eliminate the key punch, and this was the last straw, so here is what I did. 45 01 FAV_REC. 05 CARD PIC IS 9. 05 DEPT PIC IS 99. 05 PLANT PIC IS 99. 05 VOUCHER PIC IS 9(4). 05 ACCOUNT PIC IS 9(4). 05 ACNT_MODIFIER. 07 UNIT PIC IS X(4). 07 ITEM PIC IS 99. 07 ZERO PIC IS 9 DEFAULT IS "0". 07 SPACE PIC IS X DEFAULT IS " ". 05 DECSRIPTION PIC IS X(40). 05 SUMMARY REDEFINES DESCRIPTION. 07 TRANS_SUSPENS PIC IS X(4). 07 UNIT_DEPRECIATED PIC IS X(12). 07 BLANK PIC IS X(24). 05 COST PIC IS S9(8) USAGE IS COPM_5. 05 COST_PIECES. 07 FIRST_SEVEN PIC IS X(7). 07 LAST_ONE PIC IS X. 05 YEAR_ACQ PIC IS XX. 05 CLASS PIC IS XX. 05 TYPE_ENTRY PIC IS X. 05 FILLER PIC IS XX. 05 POLL_CODE PIC IS XX. 05 SEQUENCE USAGE IS DATE. 05 SIGN_BYTE PIC IS X COMPUTED BY CHOICE LAST_ONE = "p" THEN "}" LAST_ONE = "q" THEN "J" LAST_ONE = "r" THEN "K" LAST_ONE = "s" THEN "L" LAST_ONE = "t" THEN "M" LAST_ONE = "u" THEN "N" LAST_ONE = "v" THEN "O" LAST_ONE = "w" THEN "P" LAST_ONE = "x" THEN "Q" LAST_ONE = "y" THEN "R" ELSE LAST_ONE END_CHOICE. 05 FIRST_SEVEN_DIGITS PIC IS X(7) COMPUTED BY FIRST_SEVEN. ; You know you can ignore most of the record definition but you will see I've defined something shown in the top in green called COSTS USAGE IS COMP_5. What happens with COMP_5 is that the sign shares the last byte, it shares some of the value with that last digit. I redefine COST in what I call the FIRST_SEVEN here in the LAST_ONE, and some of you went to the records defini- tion presentation that Diana did today and she talked about all the things you can do in a record definition. Here is a case where I use a COMPUTED BY with a CHOICE. Now if you'll look at what the DEC code generates with the USAGE COMP_5, if you have a zero with a minus sign in the last digit, you get a lower case p. A one (1) with a minus sign is a lower case q, and so on to a nine with a minus sign is a lower case y. But this did not quite match what the IBM system was expecting, and you can see the }, J, K, and L and so on down through R. That is really what the IBM system expected. One other thing 46 that I've shown in this record definition is sequence. In this particular instance, I wanted to keep the cards or the records that the clerk was enter- ing in the same order. 01 NEW_FAV_REC. 05 CARD PIC IS 9. 05 DEPT PIC IS 99. 05 PLANT PIC IS 99. 05 VOUCHER PIC IS 9(4). 05 ACCOUNT PIC IS 9(4). 05 ACNT_MODIFIER. 07 UNIT PIC IS X(4). 07 ITEM PIC IS 99. 07 ZERO PIC IS 9 DEFAULT IS "0". 07 SPACE PIC IS X DEFAULT IS " ". 05 DECSRIPTION PIC IS X(40). 05 SUMMARY REDEFINES DESCRIPTION. 07 TRANS_SUSPENS PIC IS X(4). 07 UNIT_DEPRECIATED PIC IS X(12). 07 BLANK PIC IS X(24). 05 NEW_COST_PIECES. 07 FIRST_SEVEN PIC IS X(7). 07 LAST_ONE PIC IS X. 05 YEAR_ACQ PIC IS XX. 05 CLASS PIC IS XX. 05 TYPE_ENTRY PIC IS X. 05 FILLER PIC IS XX. 05 POLL_CODE PIC IS XX. ; In this particular definition which I call the new record definition, you will notice I've defined something called NEW_COST_PIECES which was the first seven digits plus that SIGN_BYTE which was COMPUTED BY the previous record definition. DELETE POPULATE_NEW_FAV_FILE; DEFINE PROCEDURE POPULATE_NEW_FAV_FILE READY FAVS SHARED READ READY NEW_FAVS WRITE FIND FAVS SORTED BY SEQUENCE NEW_FAVS = CURRENT FINISH END_PROCEDURE Here is the procedure to populate the new domain from the original domain. FIND THE ORIGINAL DOMAIN SORTED BY THIS SEQUENCE NUMBER which represents the order in which the records were entered into the domain, and I equate those to the new domain. So I have taken the values that I got from the USAGE COMP_5 and translated them into what was expected in the IBM systems in never-never land and now have something I can send up over my RJE network that is under- stood by the IBM and I have indeed eliminated by card punch. [Applause] 47 Wade Scannell, Ship Analytics We have often had this problem where we get this message saying "FIXED IN NEXT RELEASE." [Part of presentation lost in changing sides of the tape.] ... and you search for an EMT instruction and you look before it and see what is on the stack. Well, DEC does not give a cross reference of the words that are what EMT code is what directive so I just defined a DATATRIEVE record which has a code and the type of the EMT 01 EMT_REC. 05 CODE PIC 999. 05 TYPE PIC X(10). ; PRINT EMT WITH CODE = 123 OR PRINT EMT WITH TYPE = "CRRG" and I sat there with two terminals and I wanted to figure out which EMT this was, I just say PRINT EMT WHERE CODE = 123 or whatever the code was, or it works the other way around too. I just used this to fix a bug in P/OS and I sent the patch to DEC and they included the patch in the overlay run-time system for me. [Applause] It is a good start for building a disassemble with DATATRIEVE. [Applause] [Larry Jasmann] I one time considered doing an assembler in DATATRIEVE, but whoa, I never considered a disassembler. Richard Copeland, Corning Glassworks Recently we went to a dual VAX 780 configuration, of course that meant distri- buted DATATRIEVE, and it has worked 99.44% well, we have only had a couple of problems with it. This one really buffaloed me for a while so you will pro- bably find it entertaining. We had a user who had rolling average report and they were finding a domain with date field greater than or equal to today (-7) to get a seven day rolling average. Find that collection, write a report based on it, print the averages and everyday at midnight this thing kicked off and it was good. Then it was distributed and the today minus seven did not work across the network. It could not pass that expression across the network to be processed by the remote node. So we had to find some way around that. 05 seven_days_age computed by (fn$julian("TODAY") - 7). 05 date_julian computed by (fn$julian(date_field) - 7). So the following was defined on the remote node, define two fields in that record seven_days_ago computed by FN$JULIAN of today minus seven and date_julian computed by FN$JULIAN of date field minus seven which enabled us to say FIND DOMAIN WITH DATE_JULIAN GE SEVEN_DAYS_AGO on the original node. That worked pretty well, but at least it was syntactically correct and it worked most of the time. But we ran into a problem with it. The next thing they wanted to do is after they got the entire week they wanted to break it down by days within that week so they said 48 FIND A IN DOMAIN WITH DATE_JULIAN GE SEVEN_DAYS_AGO to get the collection of the last week. Immediately thereafter FIND B IN A WITH DATE_JULIAN EQ SEVEN_DAYS_AGE to avoid searching the long domain again. When this was run at midnight, B was always empty, but when I said - well resubmit it and run it again, it always worked. That took a little head scratching to figure out. The solu- tion was that the remote node system clock was three minutes earlier than the local systems clock [Laughter] so today rolled after the first FIND. [Applause] Now we run that batch job at 1:00 AM and it works just fine. [Laughter] [From the floor] What do you want to bet that it show up again with daylight saving time? [Pat Scopelliti] Maybe DEC has a cluster clock. [Laughter] Bob Lott, E. I. DuPont, Wilmington, DE This one I call "ACCESS CONTROL". There is a lot of work going on in DATA- TRIEVE version 3.0 in terms of the access control. I commented earlier on the slave - the auto login that we use in our shop and we have users running pro- cedures that generate reports and in that particular case - we do not care, anybody can get a report. But those procedures that modify data, whether it be deletes, erases, or modifying specific fields in records - we don't want those users to have access to all procedures. On the other hand when you do edits of your procedures, as you all know, the access control is lost. So we defined a little dummy procedure, which I have shown at the top define procedure program end_procedure define procedure foo :program (*) ready yachts for yachts with . . . begin . . . end end_procedure DTR> :foo Enter Password for PROGRAM called PROGRAM and as you can see, it does nothing but it has lots of access control on it. And I've shown another procedure which I've named appropriate- ly as FOO in this case and the first thing I do in FOO is invoke Procedure PROGRAM and request that you get a password prompt. And then you READY YACHTS - do whatever you want to do, in our particular case again, these are proce- dures that do modify the data so you would do whatever modifications that you wanted to. Down at the bottom, you invoke FOO and I've shown in green FOO - because of the access control on it - it says Enter PASSWORD for PROGRAM and we have choice the name program because of all these people out there who are not computer users - they just think that it is a program running and that they have been requested to enter the password for it. So that is how we 49 handle the access control - we can modify a procedure all we want to and the access control is never lost because we never edit PROCEDURE PROGRAM. [Applause] Chris Wool, E. I. DuPont, Wilmington, DE We had a little thing I was trying to work up the other day. I was trying to establish a report or a print - I've shown the example with a FIND here, but the problems with any records selection expression - when you want to a STARTING WITH and it is fine if you want to get the values that you are start- ing with once so you can put it at a prompt. So you say FIND domain WITH field STARTING WITH *."prompt" Well, what if you want to keep the value that they are asking for - the start- ing value. It might be a telephone directory and they can enter B or BR or what ever they want for the first starting characters and you want to be able to use that in the title or something? So I tried this declare tmp pic x(20). tmp = *."prompt" find domain with field starting with tmp I declared a variable of - in this case it was twenty characters, prompted for it and then I said FIND DOMAIN WITH FIELDS STARTING WITH the variable. Well, that does not work because the blanks in the variable - it is looking for the full twenty characters no matter how many are in it. So I said well, lets try something crazy and it turned out that it worked. I said find domain with field starting with tmp||"" (concatenated with a null string). You use the double bar concatenation [because] it takes the trailing blanks off and it works fine. [Applause] By the way - this works only on VAX DATATRIEVE - I tried it in DATATRIEVE-11 and complained about the null string. [Larry Jasmann] I think you should explain about the single bar Chuck Watson concatenation, Jim. [Jim Starkey] Original- ly DATATRIEVE-11 had just a dumb concatenate. It just stuck two things back- to-back. Then people wanted to send out junk mail with DATATRIEVE and they complained so I changed it and then Watson sent in an SPR. All we need to do is create a second concatenate which beget a third concatenate. Seems he had some incredibly crock application where he was building keys - gibberish keys out of the random strings of digits and he wanted to stick them together. [From the audience] It was for another a database application. [Jim] Yeah, it was probably a database application. It is not a whole lot of the story but what is what it is. I think there is a comment in there that labels it as a Chuck Watson concatenate. Diana Washburn, Hanes Hosiery, Winston-Salem, NC This is in answer to something that came up in the Pre-symposium seminar - I mentioned there that it would be answered here and I tried to get someone else to do it but failed, so I am doing it. This was part of a REPORT statement using the CHOICE within the PRINT of your report. It was used to produce 50 actually two fields. There was one choice that produced based on the value of BEAM sale price and then the second in a second field gave kind of a commen- tary documentation on how much percent off that particular thing was. The question was - could it be done in one choice rather than in two. And - it can be. report yachts with builder = "CHALLENGER" print model, beam, price using $$$$,$$$, choice beam le 10 then (price * 0.9) beam bt 11 and 20 then (price * 0.85) else (price * 0.80) end_choice ("Sale"/"Price") using $$$$,$$$, choice beam le 10 then "10% off Retail" beam bt 11 and 20 then "15% off Retail" else "20% off Retail" end_choice Sale Model Beam Price Price 35 12 $58,823 $49,999 15% off Retail choice beam le 10 then format(price * 0.9) using $$$$,$$$|" 10% off Retail" beam be 11 and 20 then format(price 0.85) using $$$$,$$$|" 15% off Retail" else format(price * 0.80) using $$$$,$$$|" 20% off Retail" end_choice Sale Model Beam Price Price 35 12 $58,823 $49,999 15% off Retail If put it in one choice, then you can use the format on the first part and use a concatenated expression then to put in the other half. The difference in your print line is that in the first one sale price is the heading over the top of the sale price column - the second one is just kinda pushed over there a ways without a heading and in the second one the sale price is centered over the two columns together. [Applause] Meryem Kazanfer, LSI Avionics I have something very simple and sometimes the simplest things can help you.... What I did is when I started working with this company, one of the tasks that came up was that they had this menu driven system and what they had was two jobs and it is the same database - one was used for retrieval purposes and the other one for updates. However in the morning, a DATATRIEVE job ran at 7:30 in the morning and took almost half a day and what it would do is copy every single record from UIC to another UIC and change a little bit on the format of the menu retrieval. It was holding up the system. I made a batch 51 and let it run - submitted it at night so I'd have the operators to run "@command" to submit the batch job and it runs the DATATRIEVE. $JOB (1:00) $@A $EOJ ! file A.CMD contains MCR DTR @B ! file B.CMD contains SET DICTIONARY SAMPLE :PROCEDUREA EXIT This is basically - from what I remember of the format - I think that is simple - probably all of you know it. [Applause] One more thing that I found out - this is RSX-11M at the time and in the notes - they did not have it in the manual - but in the update notes it said a little paragraph - Oh, the QXDR is used to extract the whole dictionary. I said that great - just what we need - if I extract the whole dictionary - and it is a great utility - really - since under [PDP-]11/44] at the time we did not have EXTRACT or EXTRACT ALL. So at that time it was great - it was magic.. [Applause] [Unidentified questioner from the audience] I would like to know if anyone else knows this - we have a person in Louisville at the Federal Land Bank ... who re-taskbuilt DATATRIEVE under RSX in supervisor mode, [with] RMS resident libraries, and it seems to increase the pool quite a bit on DATATRIEVE and increase the performance as well. I was wondering if anyone has done that. Is DEC planning on doing that as an option or ... [Bart Lederman] I don't really know, there have been unofficial com- ments on it. I do know that you can get the instructions to do it out of telephone support which means that certainly somebody in DEC knows how to do it. It's a little complicated - now to do it right you need RMS version 2.0 and it has to be up to the patch level its at. On a lightly loaded system it won't make your procedures run any faster but it will greatly cut down the amount of system overhead that is invoked by the DATATRIEVE task image so if you have a lot of copies running..... [Questioner] All of the RMS overlay crap is gone? [Lederman] Yeah - that is basically the reduction of overhead - you have far fewer overlays and far fewer directives and especially if you are running on a single disk system if you have a lot of users it will make a big difference. [Questioner] Why wouldn't DEC do that as a standard or an option in the installation? [Lederman] You are going to have to DEC that, but all I know is right now you can get it from telephone support but they have had a policy about not having anything that's specific to one operating system and you can't do it on all operating systems. Other than that, you're just going to have to go to DEC. But if someone wants to do it, I got the instructions through telephone support and I understand they will supply. 52 Bob Lott, E. I. DuPont, Wilmington, DE This one I call "DATATRIEVE UPDATING DECGRAPH". We have a lot of things we are running from batch. Run odd hours in the middle of the night - that kind of thing. . . . we have things that we like to update for batch in the middle of the night and so I use DATATRIEVE to extract data from some of my databases and generate DECGRAPH load files the procedure for which I've shown here. delete create_plot_load_files; define procedure create_plot_load_files ! procedure to create DECGraph "load" files for plant performance data ready performs shared read declare begdate usage is date. declare cost_month pic is xxx. declare month pic is xxx. declare year pic is xxxx. begdate = "TODAY" begdate = begdate + (-14 * 40) cost_month = max prod_date of performs month = fn$str_extract(cost_month,4,3) year = fn$str_extract(cost_month,8,4) find performs with prod_date ge begdate sorted by prod_date ! cost of manufacture on plot:com.grl begin print "TITLE COST OF MANUFACTURE" print "SUBTITLE ", month(-)," ",year(-) print "X_DATA_TYPE TEXT" print "VERTICAL_LABEL $/CWT DMT" print "HORIZONTAL_LABEL COST MONTH" print "Y_LEGEND CAPE FEAR" print "Y_LEGEND OLD HICKORY" for current print col 1,"""",col 2, prod_month(-),col 5,"""", " ",cf_com(-)," ",actual_com(-) end ! . end_procedure $GRAPH/NOINT/LOAD/OUTPUT=COM COM COM You can ignore some of the earlier things, all I'm really doing is trying to decide the date span over which I want to use in the record selection expres- sion. You will notice that I have used a FIND and you've heard, I'm sure, in the past that you really don't want to use FIND, that a FOR is better. In this particular instance, the FIND is better and I will explain why in a moment. But at any rate, I'm establishing a collection based on the date span that I have shown for my data. I am moving the ON statement to PRINT to a file called COM.GRL and the .GRL extension is something that DECGRAPH under- stands as a load file and you'll see that I am printing something called a TITLE ..... SUBTITLE and in this particular instance, I'm printing the month and the year of my most recent data and I'm printing the X data type, the vertical label, the horizontal label, the X - the two Y legends and then I'm printing data from my collection. In this particular case from the current collection. I'm printing a month - something I call CF_COM and ACTUAL_COM. Without the heading, of course, these go to a file and I really should have 53 brought a copy of that file with me - I didn't but at any rate, it's a load file which DECGraph understands. Then, interactively or from batch, in this particular instance, the command I've shown is from batch, you can do -- some- where in there its GRAPH/NOINTERACTIVE/LOAD - I am telling DECGraph that I am using a load file then put - I want to create an output file - something call- ed COM and is used for my descriptor in my data file. With Version 1.2 DECGRAPH you can generate the graphic output file - something they call an EXPORT file from batch without a terminal being connected and then you can put these files on a screen by simply doing a DCL command: $type file_spec. [Applause] One other thing I would comment, this procedure has been abbrevi- ated - I've do some twenty or thirty of these with subsequent ON FILE_NAME so I do a whole series of plots within this procedure. Awards for Magic Presentations Runner up awards went to: Chris Hines for his anti-magic - TV magic cards; Wade Scannell for his perpetual data calender and another excellent presenta- tion - a boomerang of sorts; Tim Alterman for his map of Alaska - a boomerang; Bob Lott for volume of presentation - a boomerang. Grand prize went to Pat Scopelliti for his VT240 magic. ______________________________________________________________________________ News Briefs ______________________________________________________________________________ * Version 3.0 of VAX-DATATRIEVE was in the SDC (software distribution center) in the first week in September. Shipment of Version 3.0 should have begun on about September 28, 1984. * This year is the 20th Anniversary of DEC's 36 bit systems - the PDP-6, PDP-10, and PDP-20. The Large System Special Interest Group is planning special activities at the Fall Symposium to commemorate this auspicious event. You are invited to join them in their celebration in Anaheim. * Jim Starkey has left Digital to form his own software company which will supply relational database software for UNIX-based systems. The members of the DATATRIEVE community owe Jim a great debt for creating our produc- tive and enjoyable computing environment. We wish for him all the best in his new endeavor. Wonder if the UNIX world is prepared to "READY YACHTS"? 54 ______________________________________________________________________________ DATATRIEVE Masters ______________________________________________________________________________ The following list of names identifies people who have agreed to provide assistance to other DATATRIEVE users. Operating System Phone Name and Address ______________________________________________________________________________ RSX & P/OS (212) 775-3567 Bart Z. Lederman Bankers Trust Co., 28th Floor One Bankers Trust Plaza New York, NY 10006 RSX & VMS (617) 839-4411 X5480 Joe Kelly Waymon Gordon Worchester Road North Grafton, MA 01536 IAS & VMS (509) 376-2227 Chuck Watson Battelle Northwest Richland, WA 99352 VMS (202) 426-1345 Larry Jasmann 10067 Marshall Pond Rd. Burke, VA 20015 VMS (312) 982-7430 James Swanger G. D. Searle & Co. 4901 Searle Parkway Skokie, IL 60077 VMS (206) 396-2501 Darrell Eade Naval Undersea Water E. S. Hayport, WA 98345 VMS (302) 366-4610 Chris Wool E. I. DuPont Engineering Dept., Louviers Bldg. Wilmington, DE 19898 VMS (602) 24404316 Dick Azzi Motorola SPS Box 2953 MS: P116 Phoenix, AZ 85062 _____________________________________________________________________________ 55