On 27-Mar-2015 17:37 -0500, Karl Abbott wrote:
I want to create a duplicate of the CRTDUPOBJ command, which will
process the CRTDUPOBJ command and then follow up duplicating logical
files, if necessary.
Hmm. Seems very likely then, that a post-processor for the command
would be required, not a pre-processor.? Anyhow, some thoughts
[composed in-line to the quoted text]:
FWiW: The Create Duplicate Object (CRTDUPOBJ) already has the
built-in capability to duplicate the physicals and then the dependent
logical files. That capability however depends on there being a shared
naming prefix for both the Physical File(s) and the dependent Logical
File(s); the Object (OBJ) specification merely need specify the Generic*
name [or special-value *ALL], and as with the other benefits for the DBF
network contained within the same library, all of the dependents with
that naming would be in and thus duplicated from the one From Library
(FROMLIB) named on the CRTDUPOBJ invocation. The feature ensures the
/duplicated/ files are created in the proper order, first the physical
files then the logical files ordered both after any based-on PF and
after any based-on LF [i.e. for any VIEW over VIEW].
Unfortunately the database-file dependency ordering feature [used in
the save, restore, and duplicate paths] is not exposed as an API. So
outside of a common naming prefix, the ordering must be done by other
means; e.g. for a simplest scenario of a PF with only LFs over that one
based-on PF, by using the order of the entries in the directory for the
file, as presented by the Display Database Relations (DSPDBR) for the PF
[or the equivalent API invocation].
I created a duplicate of the CRTDUPOBJ command, named it CRTDUP,
changed the CPP to my program "CRTDUP" in my lib.
That method limits the customization, most notably for an inability
to add extra parameters, and requires that the same [re]customization
takes place again after every time the system-supplied command changes
[which is possible albeit unlikely, to be via a PTF, rather than just to
be via only either a TR or a release-upgrade].
So if the unchanged command is satisfactory, then a better option
might be to intercept the command with Change Command Exit Program
feature (QIBM_QCA_CHG_COMMAND) to effect an alternate outcome for the
existing command invocation; of course probably instead limited as
implemented against a Proxy Command, and probably best named other than
CRTDUP which is consistent with system-command naming mnemonics, so
perhaps something like DUPPFEXT (DUPlicate PF EXTended)].
But because the implied as-desired effect is additional work that
depends upon the completion of the invoked command, merely changing the
command [string] before the CPP is invoked would not be helpful [except
to invoke a different command]. In that case, an additional Retrieve
Command Exit Program (QIBM_QCA_RTV_COMMAND) apparently may be required.
Some resources in that regard:
<
http://iprodeveloper.com/rpg-programming/apis-example-change-and-retrieve-command-exit-points-and-command-exit-cl-commands>
APIs by Example:
Change and Retrieve Command Exit Points - and Command Exit CL Commands
Mar 25, 2010 Carsten Flensburg
System iNetwork Programming Tips Newsletter
"...
Today's APIs by Example focuses on two distinct exit points: Change
Command and Retrieve Command Exit Points. The former enables you to
register a single exit program for almost any CL command on your system.
The latter provides for up to 10 exit programs being registered for each
CL command. ...
..."
<
http://www.mcpressonline.com/cl/the-cl-corner-new-support-for-cl-commands-lets-you-know-when-a-command-ends.html>
The CL Corner:
New Support for CL Commands Lets You Know When a Command Ends
Programming - CL
Written by Bruce Vining
Friday, 24 February 2012 00:00
"Need to know when "something" has finished? The Command Analyzer
Retrieve exit point capability tells you what you need to know.
...
This new support allows you to designate a program that is to be called
when the command processing program (CPP) of a CL command completes. ...
As some background, starting with V4R5, IBM has supported exit point
capabilities allowing you to have exit programs called before the system
transfers control to the CPP of a given command. Using the Retrieve exit
point, documented here
<
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/apis/xcartv.htm>,
your exit program could access the command string originally submitted
to the command analyzer. Using the Change exit point, documented here
<
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/apis/xcachg.htm>
and utilized in the 2009 CL Corner article
<
http://www.mcpressonline.com/tips-techniques/cl/the-cl-corner-overriding-commands-and-their-parameter-values.html>
"Overriding Commands and Their Parameter Values," your exit program
could not only access the original command string, but also change the
command prior to the CPP running. With the PTFs mentioned previously,
you now also have the ability for the Retrieve exit point to call an
exit program after the CPP of a given command has returned control to
the IBM i.
..."
Since I'm using a duplicate of the CRTDUPOBJ command, I was thinking
I could just take the parameters coming in to my CPP and pass them
with a call to the program QLICRDUP, so that the normal CRTDUPOBJ
would process.
Note: Be aware that the prompted order of parameters does not
necessarily match the order of parameters defined to the Command
Processing Program (CPP). There may also be arguments that are passed
to the CPP that are not visible as parameters on the prompted Command
because they are defined as constants. Thus each command for which such
an attempt is made, first should be disassembled; there is a published
command [system-like named IIRC] called Retrieve Command Source
(RTVCMDSRC) that does just that. Doing that makes both creating the
custom command and knowing the nearly exact interface requirements, very
simple\straightforward.
Consider: If creating a custom Command Processing Program (CPP) is
required whether /borrowing/ the system command via a duplicate or
whether creating a custom command object, then a conspicuous
consideration might be to create also, a custom Command (*CMD) object.
Having defined both a CPP and a CMD in conjunction, any changes to
either the system-supplied command or the system-supplied CPP should
have no future impacts, except what might be documented in a future Memo
To Users (MTU) for a release [due to differences with the documented
command interface]. Given the system-program QLICRDUP is an
undocumented interface, any changes to that OS program effectively
always will remain undisclosed to customers [except what might be
inferred from the operation of the CPP or changes made to any commands
naming QLICRDUP as the CPP].
But when I call QLICRDUP I get an error "Object domain or storage
protection error for offset in object QLICRDUP."
The OS ensures a level of protection for the call interfaces to most
system-programs, especially for which the inputs and outputs are not
published; i.e. generally, for those that are not an API. The programs
are protected from non-standard invocations, allowing only those
invocations that are expected would occur only via the published Command
(*CMD) invocation method.
Such non-API programs are generally prevented from being invoked by
either commands or programs that were not created by\for the IBM i OS or
LPPs, mostly because those non-API interfaces [e.g. as a CPP for the
commands], are subject to change without notification [to customers].
IBM can ensure the matching changes are made both to the dependent OS or
LPP Command objects [and to any OS\LPP features that might invoke them
directly, thus bypassing the CMD objects] if\when the CPP changes,
because those commands and programs are under a change control system
that includes notifying those affected. But any changes to those
unpublished interfaces [e.g. to a CPP of a system-supplied command]
would remain unknown to the users, and as unpublished, would remain so.
Because user-coded invocations would not necessarily be [able to be]
appropriately updated to match the changed OS program, those invocations
could lead to unpredictable difficulties. Thus the user program is
properly being prevented from potentially debasing the integrity of the
system, as notified via the exception x4401 domain violation [msg
MCH6801 "Object domain or storage protection error for offset &5 in
object &1."]; the design intends the program should not be invoked, to
prevent potential side effects from unpredictable behavior, due to a
user-coded invocation of an undocumented and possibly changing interface
being essentially a GIGO scenario.
At this point all I am trying to do is pass the parameters through
my program and have the CRTDUPOBJ run.
Here is my program.
The contents of field LENOBJTYPES is variable, based on the object
types you select. I've tried adjusting it from 310 to 410, but always
get the same error.
Just to reiterate, the error is due to the user-domain program [i.e.
the user-created program] being prevented from invoking the
system-domain program [i.e. the OS program], as a consequence of the OS
enforcing domain /integrity/ checking. No matter how accurately the
arguments are declared and ordered [prototyped] to match the parameters
of the invoked program, the invocation still will fail. Only by
changing the user-program into a system-domain program [or in old
releases, possibly not with newer release, by reducing the Security
Level (QSECURITY) system value for the system], can the CALL be effected
without that MCH6801 error.
<<SNIP RPG src with D-Specs, PLIST, and CALL QLICRDUP>>
I would suggest creating a custom command; whether the CPP is REXX or
a PGM() is of no consequence, although the REXX interface provides the
original command string more directly, and sometimes is convenient. The
since-snipped source could be the CPP, but rather than issuing a CALL to
the system-program QLICRDUP, the CPP should construct\retrieve the CL
command-string for what would be the original CRTDUPOBJ request and then
construct each additional CRTDUPOBJ request [or whatever other actions
are required], and then perform the ordered requests successively to
achieve the as-desired reformulated effects for the request to
/Duplicate/ object(s).
A custom command could remove parameters [e.g. such as Object Type
(OBJTYPE) if the intent is that the custom command would support only
<database> *FILE objects], or add parameters [e.g. a specification of
how to deal with a JLF or other multiple-file LF over a PF or a VIEW
over a LF that was either unspecified on the request or was otherwise
omitted per OBJ() specification], or to provide alternate capabilities
perhaps with additional special-values for existing parameters [e.g. the
From Object (OBJ) parameter might be expanded to support multiple
names, could be restricted to an explicit rather than any generic name
specifications, or the Trigger (TRG) parameter might add a *ONLYPF so as
to suggest only triggers on PF are copied whereas INSTEAD OF triggers on
VIEWs would not be copied].
A custom command also resolves the issue of a /pre-process/ operation
being inherently unable to effect what was described-as the extra work
[to duplicate the dependent Logical Files of a PF being duplicated with
the CRTDUP as a command defined as effective duplicate of CRTDUPOBJ]
because that work actually must be performed as a /post-process/; i.e.
must be performed after the end-effect from the originally requested
CRTDUPOBJ, such that a simple changed-command-string as the effect for
the intercepted CRTDUP command string is insufficient.
As an Amazon Associate we earn from qualifying purchases.