Open Sesame! Identically named volumes
Published 07 OCT 2019 at 03:22:00PM by Sprezz
Updated on 08 OCT 2019 at 03:22:00PM
One of our favourite pastimes is spending time on client site being challenged to do stuff we've never even considered doing before. This post documents the result of one such challenge.
For the longest time, Revelation products have not allowed two volumes with the same name to be attached at the same time. To ensure that index transactions are applied to the correct bang file, the system enforces this artificial limit. Note though, that it IS an artificial limit, implemented at the table attaching level, not at the table opening level.
Many VARs working with multiple clients frequently just copy a base subdirectory of application tables to a new folder for a new client and in so doing, duplicate the name in the REVMEDIA map. This, naturally, means that if we have say an INVOICES table in that subdirectory, that we would not be able to consolidate across multiple INVOICES tables without first detaching the old table and attaching the new one.
This introduces significant overhead.
We needed to find a way of opening the same table multiple times for reporting purposes. Note that caveat - we didn't want to write to the file, we merely wanted to be able to read from it. As that is the case, we just needed a simple raw file handle - with no mention of SI.MFS or any other MFSs - just an RTP57 file handle.
For our first proof of concept, we manually created a file handle and were able to show that we could read from multiple tables having the same table name and the same volume name. After all, a pure file handle doesn't include the name of the table in question, it just contains information about the DOS file name of the underlying file. We did, however, notice that, whereas in the dim shrouded mists of antiquity the file handle used to contain the modulo of the file, it now contains a sequential number representing the order in which the file was opened. So our concern was that if we built the handle ourselves, the system might not know that we'd used a sequential number ourselves and that it might subsequently introduce unexpected consequences.
So, we cast around for a better way of creating a file handle, and unsurprisingly settled on making direct calls to RTP57A to do the heavy lifting for us.
The actual task is relatively simple; given the name of the table that we want a handle for, and the location, return a working file handle. So in RTP57 terms, open the media map, read the row corresponding to the table we want the handle for, grab the DOS file name and request a file handle.
With the process defined, it was not rocket science to create a function that returned a file handle given a location and a table name. The results are presented below.
0001 Function zz_getFileHandle( location, fileName ) 0002 0003 $Insert Logical 0004 0005 fileHandle = "" 0006 0007 Gosub validateLocation 0008 If OK Then 0009 Gosub getMediaHandle 0010 If Ok Then 0011 Gosub getFileHandle 0012 End 0013 End 0014 0015 Return fileHandle 0016 0017 validateLocation: 0018 0019 OK = FALSE$ 0020 OSOpen location To vLocation Then 0021 // can be opened so is Not a directory it's a file 0022 osclose vLocation 0023 End Else 0024 // was access denied because it didn't exist or because it's a subdir? 0025 0026 If status() = 2 Then 0027 OK = TRUE$ 0028 location := "\" 0029 End 0030 End 0031 If OK Else call Set_Status( 1, status(),"") 0032 0033 Return 0034 0035 getMediaHandle: 0036 0037 status = TRUE$ 0038 mediaName = "REVMEDIA" 0039 Call RTP57A("OP", mediaName, mediaHandle, "", location , "", status) 0040 If status then 0041 mediaHandle = "RTP57" : @vm : mediaHandle 0042 End else 0043 OK = FALSE$ 0044 End 0045 return 0046 0047 getFileHandle: 0048 0049 If Index( fileName, "*", 1 ) else 0050 fileName := "*" : @DbID<1> 0051 End 0052 0053 Read fileRow from mediaHandle, fileName then 0054 0055 Call RTP57A("OP", fileRow<1>, record, "", location, errMsg, status) 0056 If Status then 0057 fileHandle = "RTP57" : @Vm : record 0058 End else 0059 // Set arbitrary error code 0060 Call Set_Status( 1, 400) 0061 End 0062 End else 0063 // Set arbitrary error code 0064 Call Set_Status( 1, 401) 0065 End 0066 0067 Return 0068