As is often the case, postings on the
Rev forum pique our intellectual curiousity and sometimes when you're
on the road in a hotel room there's nothing more fun than probing some
obscure piece of arcane system information "because we can".
Welcome to the first blog of 2013 where
we pretty much excel ourselves in the arcane department although we
SUSPECT the results will have wider applicability - especially to those
of you doing multiple attaches/detaches within your application.
A recent post on the Rev forum asked
about the use of SET_ATTACH_IMAGE and USE_ATTACH_IMAGE. Those of you
with long memories may recall that these routines were introduced in
AREV to allow essentially "Quick Attaches". They swap out the contents
of @FILES and @VOLUMES for a previously stored set of values. Those of
you with even longer memories will remember that the precursors to these
routines were created by Dunbar & Co - a prolific contributor to
the Rev community - much missed.
With the advent of OI, attach images
disappeared to be replaced by their more visible counterparts, DBTs.
These Operating System files contain pretty much the same information as
the attach images but externalise the process away from the SYSENV file
where the attach images were stored.
To refresh your memory, the syntax of SET_ATTACH_IMAGE is as follows
Set_Attach_Image(imageName, optionalLabel, options, errors)
whilst USE_ATTACH_IMAGE was
Use_Attach_Image(imageName, errors)
So the idea was that you'd attach the
tables you wanted and use Set_Attach_Image to "snapshot" these tables.
The snapshot would be stored as a row in SYSENV and the next time you
wanted them you'd use Use_Attach_Image to make them available again.
This would then replace the contents of @FILES and @VOLUMES with the
stored versions.
Back at using these routines in OI.... whilst they still appear in OI, any attempt to utilise them, for example
Subroutine DeleteMe( Void )
Call Set_attach_Image("ZZTEST", "ANDTHEN", "", Errors)
return
results in
which isn't particularly useful - so back to square one...
OI still has the requirement (and
patently the ability) to swap between file and volume definitions as
shown when you log between applications - so we know it is still
possible. The only question is "How?".
Well, an examination of the most basic
logs provided by OI shows that it changes databases using the
SWAP_DATABASE command so let's give that a go...
Using a client app as a starting point... we have the following tables available to us
So now let's SWAP_DATABASE to SYSPROG
But any attempt to do anything gets this error
The reason is simple. DBTs are "user
aware" and the user I'm logged into my client app as does not exist in
SYSPROG. The answer is simple. Log into SYSPROG and add my username as a
database user for SYSPROG
Now repeat the SWAP_DATABASE and now
when you try to open a record, the only tables available are those in
the SYSPROG definition
Of course, there are always caveats when playing at the system level. In this case the act of swapping the database also
changes @DBID, @APPID and @APPINFO (at the least). It also wipes any
@User and @Recur variables basically setting your system back to a state
as through you had just logged in. So treat this as though you'd logged
to another application - including running any custom initialise
routines for that application!
Now the reason we single out @APPID is because this variable has an impact on the inheritance chain. To explain :-
Imagine you had an application
FIELDGUARD that inherited from SFX which in turn inherited from SYSPROG.
Imagine further that you wish to run a program called EOM. The program
loader will firstly look for $EOM*FIELDGUARD and if it doesn't find it
look for $EOM*SFX. If this isn't found it will finally look for
$EOM*SYSPROG.
Now imagine that you swap database to ACCOUNTING which also inherits from SFX. If we try to run EOM we will now
be looking for $EOM*ACCOUNTING and the load will likely fail - unless
of course there IS an $EOM*ACCOUNTING in which case you'll be running
something that you didn't expect.
The fix is, fortunately, simple. Ensure
that all of the databases that you wish to switch to are inherited from
your core application. This has the added benefit that they will
automatically be created with the same users! So imagine you inherited
application CUSTOM from FIELDGUARD. The program loader will
now firstly look for $EOM*CUSTOM and if it doesn't find it then look for $EOM*FIELDGUARD as before.
Now it has to be said that we haven't
used this technique in a production environment and we have only tested
for our own satisfaction. One thing that did emerge in testing was that
whilst this technique happily changed the tables available to us it
created problems when saving forms. So to be extra careful we'd
recommend that this technique only be used in a non development
environment. We'd also strongly recommend that you test the technique
thoroughly in your own system. That said it seems to work in a very easy
and straightforward manner and would be especially useful in web based
sessions where users attach different databases.