Time Waits For No One
My nominee for the most commonly used, yet least well understood, feature of MPE/iX: the system clock and the SETCLOCK command. SETCLOCK was added to MPE/iX with version 5.0. In the US, most of us use this command at least twice a year: in April when we switch to Daylight Savings Time and in October when we switch back to Standard time. Even if SHOWTIME seems to give the correct time, there is a very good chance your system has an incorrect value for Timezone and/or GMT unless you set it up correctly yourself when you moved to 5.0 or when you received a new machine. [For example, when I arrived here on the West Coast earlier this year to start work at a new company, I discovered that the clock was screwed up on two of our five HP 3000s: our two principle production machines.]
It will soon be time for most of us in North America to switch back to Standard Time. As usual, there have been questions posted to HP 3000-L about the HP 3000's system clock. Therefore, I am going to repeat (suitably brought up to date) a net.digest item from the October 1996 issue of The 3000 NewsWire.
If you are not on MPE/iX 5.0 or 5.5 you are probably wishing you were, since the only supported way HP provides to change the time is a system SHUTDOWN followed by a system START. If you are at least on MPE/iX 5.0, then changing from Daylight Savings to Standard time or vice versa is easily accomplished with the timezone form of the SETCLOCK command. In fact, here is a snippet of JCL from a scheduled job stream I use that runs at 2:00 a.m. Sundays (I am located in the Pacific timezone of the US, so adjust as necessary):
!IF HPDAY = 1 AND HPMONTH = 10 AND HPDATE > 24 THEN
! SETCLOCK TIMEZONE = W8:00
!ELSEIF HPDAY = 1 AND HPMONTH = 4 AND HPDATE < 8 THEN
! SETCLOCK TIMEZONE = W7:00
There is, however, one giant caveat to this: your "real" system time must be correct. Check it now. For example, using the SHOWCLOCK command and SHOWCLKS.PUBXL.TELESUP after initializing TZ appropriately on one of my systems yields:
!IF HPDAY = 1 AND HPMONTH = 10 AND HPDATE > 24 THEN
[GONZO: JPB,MGR.SYSMGR,PUB] MON, SEP 15, 1997 9:35 PM [/SYSMGR/PUB] :SETVAR TZ,"PST8PDT" [GONZO: JPB,MGR.SYSMGR,PUB] MON, SEP 15, 1997 9:36 PM [/SYSMGR/PUB] :SHOWCLOCK SYSTEM TIME: MON, SEP 15, 1997, 9:37:06 PM CURRENT TIME CORRECTION: 0 SECONDS TIME ZONE: 7 HOURS 0 MINUTES WESTERN HEMISPHERE [GONZO: JPB,MGR.SYSMGR,PUB] MON, SEP 15, 1997 9:37 PM [/SYSMGR/PUB] :SHOWCLKS.PUBXL.TELESUP SHOWCLKS/XL A.10.00 DEBUG/iX B.79.06 HPDEBUG Intrinsic at: 5388.00007258 PROGRAM+$198 PRIV=$3 := $0 ************************************************************* *** *** *** Greenwich Mean Time : TUE, SEP 16, 1997, 4:37 AM *** *** GMT/MPE offset : -7:00:00 *** *** MPE System Time : MON, SEP 15, 1997, 9:37 PM *** *** *** ************************************************************* **** C Library Information **** Current value of Time Zone(TZ) variable : PST8PDT CTIME function return : Mon Sep 15 21:37:25 1997If your system does not look something like this (adjusted of course for your timezone), then you need to correct things before adjusting for the change to Standard time at the end of October. [Gilles Shipper deserves credit for being the first to present the concise procedure below.]
Step 1: RTFMs. See Chapter 10 of the 5.0 Communicator for a discussion of the SHOWCLOCK and SETCLOCK commands. Also, in the MPE/iX HELP system read over the entries for SHOWCLOCK and SETCLOCK.
Step 2: :setclock timezone=zn:00 (your timezone, e.g. w7:00, the offset from GMT west or east)
Step 3: :setclock ;cancel (stop the correction
Step 4: :setclock date=mm/dd/yy;time=hh:mm;now (correct date and time immediate)
That should do the trick. By the way, if it's important at your site, the TZ variable can be set via a system logon UDC. TZ affects "c" time; i.e. anything written in c that accesses date/time information. The correct form for the Pacific Time Zone is:
A Case Of Over Reaction
To An Error Message
This may seem a little esoteric, but if you do much programming, you will eventually have to deal with issues of multi-user access to plain MPE files. TurboIMAGE hides most of the nasty business from you when you access databases, so the first time you try multi-user access of MPE files, you too may have trouble:
"We have this program that is returning an error on a specific file (the program searches for occurrences of a string in a group of files):
File System message 430
Dynamic LOCKING was specified on a previous OPEN of this file,
LOCKING was not specified on this call to HPFOPEN. (FILE OPEN ERROR -430)
File System message 430
"So I went into the source and added code to open the file with the dynamic locking option set on and multijob access on. The FOPEN now returns successfully. However, the FREAD is then failing on this file. It's returning:
END OF FILE (FSERR 0)
"Why? After some experimentation, I determined that if I add an FPOINT before each FREAD (FPOINT to rec 1,2,3 ....) then the FREAD succeeds. So why for files of this type, do you have to FPOINT to each record before the FREAD? Anyone know? Is there a "correct" way to get this to work?"
Combining the responses of John Korb and Bill Bennett with my own thoughts:
You got a little carried away reacting to the error message. First, you do not want to add dynamic locking to all the HPFOPENs this utility does. Doing this means that any other program accessing a file you are searching must open it with dynamic locking to have concurrent access. By making this one file work for your search program, you may have caused problems in other programs. Change the code to try to open without locking first, then if you get a file error 430, try to open with locking.
Second, the actual problem you mention is caused because you added multijob (GMULTI) access. With GMULTI access, the program is sharing file pointers with all other programs accessing the file. In your case, the first program probably was waiting to append to the end of the file (so the record pointer was at EOF). Note that by changing the pointer you are having an unpredictable, and probably undesirable, effect on the other program. For your application, you don't want multijob access, you want your own copy of the file pointers.
In cases where GMULTI mode is appropriate, locking is very important, as is making sure that you position the file pointer before reading or writing. A checklist for accessing files in GMULTI mode:
1) Enclose your file operations within FLOCK, FUNLOCK.
2) Use FPOINT and then FREAD or FWRITE, or use FREADDIR, FWRITEDIR.
3) Always assume that the file pointer is somewhere other than where you want it.
GMULTI has some really neat applications, if you are careful. It also can cause some really nasty consequences and exhibit odd behavior if you are not scrupulously careful in your implementation.
Slick, Low Cost Document Storage
And Retrieval Need Not Be An Oxymoron
The problem: "We are initiating a project for the storage and retrieval of raster images. Due to budgetary constraints and other factors, we would like to have as low a cost solution as possible. We will have scanned images of documents containing text and graphics in ordinary PCX, TIFF and other formats and want to be able to retrieve them on demand to a Windows95 desktop. Any ideas?"
Neil Harvey supplied a great response as someone who's "been there done that" which I will quote in whole:
"My two cents worth of advice is to avoid storing the scanned images as BLOBs in some relational database. Instead, scan them and store them as serial numbers in a slashed sub directory structure. Store image number 0010132456.tif under a directory as follows:
"Each subdirectory will hold only 100 entries, and will be very swift to get to. The HP 3000 can be used to maintain the serial number sequence. As for the index information, store this in the world's most robust and easy-to-use database called TurboImage. All you need to image-enable any application (existing, or new) is a single field (column) tagged onto the already indexed dataset record. It's not that difficult to do this, and now with Samba/iX, you can even store the images on the HP 3000.
"Glue the structured data and the images together at the client, using some DDE enabled viewer (VB?), and Reflection or MS92. The application can initiate the DDE commands to tell the image viewer to retrieve and display the image, or function keys can be preprogrammed to do this. However you do it, you will gain hugely against paper handling/micro film base systems.
"Don't get hung up about workflow, the main selling point of document image handling packages. When everyone has near instant access to the scanned image, perceived workflow requirements simply vanish. Mostly, what people want to do when viewing an image is add a little something to the index record, and HP 3000's are very good at allowing this to happen.
"We have a customer with over 5 million images safely stored this way on a single NT server with raid and securely indexed on the HP 3000."
Even in this age of client-server report writers with GUI interfaces, good old QUERY remains a workhorse tool for the Database Administrator. This thread was started by the following question:
I am using QUERYNM to attempt to change an item in a dataset if it fits certain criteria in both the dataset it is in and other datasets. I am using the following query ... (he goes on to show a lengthy JOIN and MULTIFIND). QUERY finds the entries I am looking for and I can report them. However, when I try to make the replacement, I get the message "RECORD HAS NOT YET BEEN FOUND". What is going on?
John Alleyn-Day, Michael Berkowitz and Jerry Fochtman all noted that this is a long standing deficiency in QUERY. Michael Berkowitz added that enhancing QUERY to provide this functionality is on the current SIGIMAGE improvement ballot, but HP has not committed one way or the other. John Alleyn-Day went on to describe the following work-around:
"When you have done your multifind, you create a special report and write it out to a file. I don't remember all the parameters offhand, but you have to set something like 'NOPAGE' and maybe a couple of other things to eliminate all the stuff you don't want. The 'text' of this report consists of a 'FIND' wrapped around the key value of the file that you want to update. The next line of the 'report' consists of the command 'UPDATE REPLACE'. Then, you run QUERY again using the 'report' file as command input. Obviously, you can have a multitude of 'FINDS' in your report, one for each record you need to update. There are a lot of sneaky tricks like this that enable QUERY to do some quite complex things. This is one of the easier ones."
Not satisfied, the original poster responded:
1. How do you output to a file? The output command seems only to provide for LP and TERM.
2. How do you input from the file you create? IO redirection?
Again, John Alleyn-Day and Michael Berkowitz provided the answer:
If you want QUERY to write to something other than the printer or terminal, you have to give a file equate to "QSLIST". For example, to write to a new disk file XXXX:
Then, use the LP command, and do your report. The output will be written to XXXX. After you create this file, you can then change it with an editor if necessary, or if ready to go, you can use the XEQ command of query to read this file and execute the query commands you've written to it.