The %Routine class provides a way to create and manipulate
routines stored within a database.
The %Routine class provides a stream interface
(see %AbstractStream) that allows you to read existing
routines as well as create new one programmatically.
%Routine includes methods to save and compile
modified routines.
For example, the following code creates, saves, and compiles a
simple ObjectScript routine (note that lines of code start with a space
character):
Set routine = ##class(%Routine).%New("MyRoutine.MAC")
; Write lines of code to the routine
Do routine.WriteLine("MyRoutine")
Do routine.WriteLine("Tag()")
Do routine.WriteLine(" Write ""This is my routine"",!")
Do routine.WriteLine(" Quit")
; save the routine
Do routine.Save()
; compile the routine
Do routine.Compile()
For INT routines if this is compiled from a MAC then return true if the INT
is up to date with the MAC, but if the INT is different to the MAC, e.g. it was
modified and saved directly or the MAC was modified and saved but not compiled
then it will return false.
For MAC routines it will be true if the generated pcode from compiling this MAC
is up to date and false if recompiling this MAC would generate different pcode, so
either the MAC has changed or the pcode has changed.
classmethod %ExistsId(id As %String) as %Boolean [ Language = objectscript ]
Inherited description: Checks to see if the object identified by the ID id exists in the extent.
Returns %Boolean TRUE is it exists, FALSE if it does not.
method %IsModified() as %Integer [ Language = objectscript ]
Inherited description: Returns true (1) if a property of this instance has been modified, otherwise false (0).
A TRUE result does not necessarily mean that any property has actually been changed. If
%IsModified() returns false then the object has not been modified. There are some
situations where we simply cannot efficiently detect a change in value. In these cases we
will set the modified status of the property.
method %ObjectModified() as %Integer [ Language = objectscript ]
Inherited description: This method is somewhat similar to %IsModified but it also checks to see if swizzled
references would cause the object to become modified should they be serialized. This works
on the assumption that a reference to a persistent object will never be modified if the ID has
already been assigned. For references to serial objects, a call to %ObjectModified indicates
whether or not the serialized value is different. If the reference to a swizzled object is
different from the initial object state then the $$$objModAll macro will already return true.
Reference the Set code.
Returns true (1) if this instance has been modified, otherwise false (0).
private method %OnClose() as %Status [ Language = objectscript ]
Inherited description: This callback method is invoked by the %Close() method to
provide notification that the current object is being closed.
The return value of this method is ignored.
private method %OnNew(initval As %String = "") as %Status [ Language = objectscript ]
Inherited description: This callback method is invoked by the %New() method to
provide notification that a new instance of an object is being created.
If this method returns an error then the object will not be created.
It is passed the arguments provided in the %New call.
When customizing this method, override the arguments with whatever variables and types you expect to receive from %New().
For example, if you're going to call %New, passing 2 arguments, %OnNew's signature could be:
Method %OnNew(dob as %Date = "", name as %Name = "") as %Status
If instead of returning a %Status code this returns an oref and this oref is a subclass of the current
class then this oref will be the one returned to the caller of %New method.
private method BuildRoutineName() as %String [ Language = objectscript ]
Return the complete routine name for this routine.
classmethod CheckProtect(name As %String) as %Boolean [ Language = objectscript ]
Check if we are allowed to save this routine in this namespace
classmethod CheckSyntax(ByRef Source As %String, ByRef Errors As %String, LanguageMode As %Integer = 0) as %Status [ Language = objectscript ]
This function syntax checks INT source code.
Source - source (INT) code;
either a single line stored in a variable, or
an array where: array(0)=#lines, array(1-n)=source
Errors (byref) - Returned array of errors detected by compiler
LanguageMode - language mode, 0-10 (optional, default 0)
method Clear() as %Status [ Language = objectscript ]
Inherited description: Clear the contents of this Stream from permanent storage. This will remove the permanent stream storage and
any temporary stream and initialise the stream to its initial state that it starts in, including removing all
the stream attributes.
Returns a %Status value indicating success or failure.
method Compile(qspec As %String) as %Status [ Language = objectscript ]
Compile this routine. The qspec is the standard objects qualifiers described in
'Do $system.OBJ.ShowQualifiers()'.
Compile all routines in a namespace.
This method will compile all routines in the current namespace. Flags Bit string of options to method.
Bit 0 - Suppress syntax error display.
Bit 1 - Suppress output to principal device. IO Already open device to send the output to. For example, "c:\a.out" Count (by ref) Number of routines compiled. Errors (by ref) Number of routines with syntax errors. MultiCompile - If true then use multiple jobs to do the compile, if not specified use the default /multicompile qualifier setting Journal - If true then journal the compile, if false disable journaling for compile, if not specified use the default /journal qualifier setting KeepSource - If true (default) then keep INT code from compiling a MAC, if false then do not save INT code
classmethod CompileAllNamespaces(Flags As %String = 0, IO As %String = $p, ByRef Count As %Integer, ByRef Errors As %Integer, MultiCompile As %Integer = 1, Journal As %Integer = 1, KeepSource As %Boolean = 1) as %Status [ Language = objectscript ]
Compile all routines in all namespace.
This method will compile all routines in all namespaces. This will not compile
routines in SYSTEM defined namespaces. Flags Bit string of options to method.
Bit 0 - Suppress syntax error display.
Bit 1 - Suppress output to principal device. IO Already open device to send the output to. For example, "c:\a.out" Count (by ref) Number of routines compiled. Errors (by ref) Number of routines with syntax errors. MultiCompile - If true (default) then use multiple jobs to do the compile Journal - If true (default) then journal the compile, if false disable journaling for compile KeepSource - If true (default) then keep INT code from compiling a MAC, if false then do not save INT code
classmethod CompileList(rtns As %String, qspec As %String) as %Status [ Language = objectscript ]
Compile a list of routines in the current namespace.
Pass this a comma separated list of items, which can include wild card
characters e.g. 'test.mac,abc*.int' or pass in a subscripted array with the
routine name as the subscript. It will return an error %Status.
If you do not wish to use multicompile then pass in /multicompile=0
Compile selected routines in a namespace. Mask Selection mask of which routines to compile. This mask is passed to
%Library.Routine.RoutineList() and must be in a format it understands. Flags Bit string of options to method.
Bit 0 - Suppress syntax error display.
Bit 1 - Suppress output to principal device. IO Already open device to send the output to. For example, "c:\a.out" Count (by ref) Number of routines compiled. Errors (by ref) Number of routines with syntax errors. MultiCompile - If true then use multiple jobs to do the compile, if not specified use the default /multicompile qualifier setting Journal - If true then journal the compile, if false disable journaling for compile, if not specified use the default /journal qualifier setting KeepSource - If true (default) then keep INT code from compiling a MAC, if false then do not save INT code
classmethod Delete(rtnname As %String, flag As %String = 0, supressbackup As %Boolean = 0, nsp As %String = $namespace) as %Status [ Language = objectscript ]
Delete the routine rtnname. If the rtnname is not fully qualified we will resolve this into
a fully qualified name first and then proceed with the rest of the delete. For example if you specify 'test' and there
is a 'test.mac' it will resolve to this, if there was only a 'test.obj' it will resolve the name to this.
The parameter flag specifies now much to delete.
The options are:
0 - Delete entire routine, for a MAC routine this will delete MAC, INT, OBJ. For an INT routine
it will delete INT and OBJ, for a INC routine it will only delete the INC, for a BAS routine it will
delete the BAS and the OBJ code.
1 - Delete just the named routine, for example for a MAC routine it will only delete the MAC
and it will leave the INT and OBJ if present.
2 - Delete all the source code but leave any OBJ code.
This returns a %Status code to show if it worked or not. If you pass a name like 'test.mac;*' it will
delete all backup versions of this routine. If the routine name which is passed does not
exists, the method will return success.
Inherited description: Deprecated method, use %Delete() instead.
Deletes the stored stream identified by oid. This will not remove the stream attributes of any
saved streams, it will just remove the stream data. If you need to clear the attributes as well you will
have to call Clear() on the stream object.
classmethod Exists(name As %String) as %Boolean [ Language = objectscript ]
This is a class method which tests if the routine name exists.
If name consists of a routine name and an extension,
such as INT, MAC, etc. then it will check for this specific routine. If it
just contains the routine name it will check if either MAC, INT, or BAS exists.
method Flush() as %Status [ Language = objectscript ]
Inherited description: Flush any output in the stream not already saved.
method GetCurrentTimeStamp() as %TimeStamp [ Language = objectscript ]
Get the on-disk timestamp for the routine.
classmethod GetDate(name As %String) as %TimeStamp [ Language = objectscript ]
Return the timestamp the routine with name was last updated.
method GetObjectVersion() as %Numeric [ Language = objectscript ]
Returns the major.minor version number of the ObjectScript compiler that produced the object code
for this routine. Returns 0 if there is no object code for the routine.
classmethod GetRoutineGlobals(ByRef Names As %String) as %Status [ Language = objectscript ]
Return list of globals where routine and class information is stored.
Returns Names="ROUTINE,rBACKUP,rINC,rINCSAVE,rINDEX,rMAC,rMACSAVE,rMAP,rOBJ,oddDEF"
Here is some documentation on the format of the routine globals.
ROUTINE - Native .INT COS code, generated from .MAC, or generated from classes.
When compiled generates .OBJ code.
ROUTINE(Name,0)=timestamp when last saved
ROUTINE(Name,0,0)=# lines in routine
ROUTINE(Name,0,1...x) = Source Lines in routine
ROUTINE(Name,0,"GENERATED")= 0/1 whether routine is generated or native
ROUTINE(Name,0,"INC",IncludeFileName1)=Timestamp when last include file last saved
ROUTINE(Name,0,"INC",IncludeFileName2)=Timestamp when last include file last saved
ROUTINE(Name,0,"SIZE")=# bytes in routine
ROUTINE(Name,0,"LANG")=language mode
ROUTINE(Name,"MAC")=Timestamp of .MAC code when last saved if generated
rBACKUP(Name,Type,version) - backup of ^ROUTINE, created by the command
Merge ^rBACKUP(rtn,type,nextverersion)=^ROUTINE(rtn) where type="INT/MVI/BAS"
rINC - Native .INT or macro code, compiled into .MAC when included with #include directive
rINC(Name,0)=timestamp when last saved
rINC(Name,0,0)=# lines in include file
rINC(Name,0,1...x) = Source Lines in include file
rINC(Name,0,"SIZE")=# bytes in include file
rINC("ZZ","P") - Meta data used for precompiling include files
rINCSAVE - Backup of ^rINC, created by the command
Merge ^rINCSAVE(rtn,nextver)=^rINC(rtn,0)
rINDEX - Index of .OBJ, .INT, and .MAC routines
rINDEX(Name,"OBJ/MAC/INC")=$lb(Time compiled,Size)
rINDEX(Name,"INT")=$lb(Time compiled,Size,Generated 0/1)
rMAC - Native .MAC Macro code which when compiled generates .INT code
rMAC(Name,0)=Timestamp when last saved
rMAC(Name,0,0)=#lines in routine
rMAC(Name,0,1...x) = Source Lines in routine
rMAC(Name,0,"SIZE")=# bytes in routine
rMACSAVE(Name,Type,version) - backup of ^rMAC, created by the command
Merge ^rMACSAVE(rtn,nextver)=^rMAC(rtn,0)
rMAP - Debug map used by the debugger and for error trapping
rMAP(Name,"INT","MAC",offsets)=$lb(debuginfo)
rMAP(Name,"MAC","INT",offsets)=$lb(debuginfo)
rOBJ - Compiled .INT code
rOBJ(Name,"INT")=timestamp of .INT code when compiled
rOBJ(Name,0...n)=Compiled object code
oddDEF - Source code for classes
oddDEF($zcvt(Name,"U"),....)=source code from class. Note that all of the other
odd* nodes are meta data describing the class, and can be recreated by compiling
the class. The rINDEXCLASS and rINDEXSQL nodes also get recreated when compiling
the class.
private method IOGetStreamId() as %String [ Language = objectscript ]
Inherited description: Return the id for a stream; that is, an identifier that can later be used
to open the same stream.
private method IOInit() [ Language = objectscript ]
Inherited description: Initialize member variable used by the StreamAdaptor. This
This is called when the containing stream is opened via %SetSerial.
private method InitWriteData() as %Status [ Language = objectscript ]
method LanguageModeGet() as %Integer [ Language = objectscript ]
method LanguageModeSet(languagemode As %Integer) as %Status [ Language = objectscript ]
method LastModifiedGet() as %TimeStamp [ Language = objectscript ]
method LineTerminatorGet() as %String [ Language = objectscript ]
method Lock() as %Status [ Language = objectscript ]
Lock the current routine
classmethod LockRoutine(name As %String, lock As %Boolean = 1, nsp As %String = $namespace, IModeLock As %Boolean = 0, timeout As %Integer = 0) as %Status [ Language = objectscript ]
Lock a particular routine name. If lock is true (the default)
then it locks the routine, and if false then it unlocks the routine. If a routine is derived from
a class then it will lock the class name in ^oddDEF to prevent another user from attempting to
edit the class at the same time this process is editing the routine. If IModeLock is True,
then it will unlock the routine with the #I flag so that the node will unlock even if in a transaction.
method MoveToEnd() as %Status [ Language = objectscript ]
Inherited description: Move to the end of the stream so the next Write will be appended to the end.
This allows you to read from a stream, then MoveToEnd() and append new data, where just calling
Write() after a read will clear the stream before writing new data.
Returns a %Status value indicating success or failure.
method NameGet() as %String [ Language = objectscript ]
method NamespaceGet() as %String [ Language = objectscript ]
method OpenStream(sid As %String) as %Status [ Language = objectscript ]
private method ParseRoutineName(name As %String) as %Status [ Language = objectscript ]
Split a routine name into its components; set the name,type etc.
If name has no extension, then the default is .MAC.
method Read(ByRef len As %Integer = 32000, ByRef sc As %Status) as %String [ Language = objectscript ]
Inherited description: Reads up to len characters from the current position
in the stream. The current position is advanced by the number of
characters read. Upon exit, len is set to the actual
number of characters read. If a read occurs when the stream position
is at the end of the stream, len will be set to -1 and
Read() will return a null string (""). If no len
is passed in, ie. 'Read()()' then it is up to the Read implementation as to
how much data to return. Some stream classes use this to optimize the amount of
data returned to align this with the underlying storage of the stream.
You must call Rewind() if you want to read a stream from the beginning
again. Calling Read() after Write() implicitly ends the Write()
operation and rewinds to the start of the stream.
Returns a string up to len characters long. The byref argument sc will
return a %Status if any error occurred during the read.
private method ReadIntoBuffer() as %Boolean [ Language = objectscript ]
Reads the next node into Buffer.
Returns 0 if there is no more data.
method ReadLine(ByRef len As %Integer = 32000, ByRef sc As %Status, ByRef eol As %Boolean) as %String [ Language = objectscript ]
Inherited description: Read a line from the stream. This will look for the line terminator in the stream and
once it finds the terminator it will return the string minus the terminator character/s. If it reaches the
end of the stream before it finds a terminator it will return the data it has so far, and if you specify a
maximum size in len it will only read up to this number of characters. On exit len
will contain the actual number of characters read. The byref argument sc will
return a %Status() if any error occured during the read and the byref argument eol
is true if it found the line terminator and false otherwise. So for example you can read in a stream
a line at a time and output the results to the current device with:
While 'stream.AtEnd { Write stream.ReadLine(,.sc,.eol) If $$$ISERR(sc) { Write "ERROR" Quit } If eol { Write ! } }
method Rewind() as %Status [ Language = objectscript ]
Inherited description: Go back to the start of the stream.
method RoutineExists() as %Boolean [ Language = objectscript ]
This is an instance method which tests if this routine exists (that
is, it has been saved to disk).
classmethod RoutineListClose(QHandle As %Binary) as %Status [ Language = objectscript ]
final classmethod RoutineListExecute(ByRef QHandle As %Binary, ByRef spec As %String(MAXLEN=512)="", Dir As %Integer = 1, Type As %Integer = 0, Nsp As %String = $namespace, nolang As %Boolean = 0) as %Status [ Language = objectscript ]
classmethod RoutineListFetch(ByRef QHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) as %Status [ Language = objectscript ]
Fetch returns the next row in the query.
classmethod RoutineListFetchRows(ByRef QHandle As %Binary, FetchCount As %Integer = 0, ByRef RowSet As %List, ByRef ReturnCount As %Integer, ByRef AtEnd As %Integer) as %Status [ Language = objectscript ]
RoutineListFetchRows returns the next FetchCount rows in the query.
method RoutineNameSet(newvalue As %String) as %Status [ Language = objectscript ]
classmethod RoutinesSortByFieldClose(QHandle As %Binary) as %Status [ Language = objectscript ]
final classmethod RoutinesSortByFieldExecute(ByRef QHandle As %Binary, ByRef Spec As %String(MAXLEN=512)="", Dir As %Integer = 1, Type As %Integer = 0, OrderBy As %String = "Date", Nsp As %String = $namespace) as %Status [ Language = objectscript ]
classmethod RoutinesSortByFieldFetch(ByRef QHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) as %Status [ Language = objectscript ]
Fetch returns the next row in the query.
classmethod RoutinesSortByFieldFetchRows(ByRef QHandle As %Binary, FetchCount As %Integer = 0, ByRef RowSet As %List, ByRef ReturnCount As %Integer, ByRef AtEnd As %Integer) as %Status [ Language = objectscript ]
RoutineListFetchRows returns the next FetchCount rows in the query.
method Save(supressbackup As %Boolean = 0) as %Status [ Language = objectscript ]
Save this routine.
method SaveStream(supressbackup As %Boolean = 0, Output Refresh As %Boolean) as %Status [ Language = objectscript ]
Inherited description: Deprecated method, use %Save() instead.
Saves the temporary copy of the stream data to a persistent location. Note that
any locking or transaction handling must be done by the caller.
Returns a %Status value indicating success or failure.
method SizeGet() as %Integer [ Language = objectscript ]
Return the current size of the data stream.
private method StoreGlvnGet() as %String [ Language = objectscript ]
method Unlock() as %Status [ Language = objectscript ]
Unlock the current routine
method UpToDateGet() as %Boolean [ Language = objectscript ]
Inherited description: Appends the string data along with a line terminator to the stream and advances the
current stream position by the number of characters in data plus the line terminator.
Returns a %Status value indicating success or failure.
private classmethod normalizeName(ByRef rtn As %String, ByRef nm As %String, ByRef type As %String, obj As %Boolean = 1) as %Status [ Language = objectscript ]
This query provides a list of all lines that differ between two given routines. Nsp1 and RouName1 specify the first routine. Nsp2 and RouName2 specify the second routine. Nsp1 and RouName2 can be either an explicit or an implied namespace.
The query returns the routine that contains FindWhat, one line per row, with two columns,
Line and Match. Line is the line text. Match is 1 if Line contains FindWhat.
The entire routine is returned.
This query provides a list of all routines that match the pattern
specified by spec.
spec may contain both * and ? as wildcards. It may also
consist of more than one, comma-delimited selections.
For example: "*.MAC" "A*.MAC" "A?.MAC" "A*.MAC,B*.MAC" dir specifies the direction to search in, 1 is forwards
and -1 is backwards. type is 1 to include OBJ files
in the search and the default, 0 will just include INT, MAC, INC, BAS. nsp is the namespace to list from. If omitted, the query returns the routines from the current
namespace. nsp can be either an explicit or an implied namespace.
This query provides a list of all routines that match the Spec
ordered by the OrderBy. The Dir specifies the direction to search in, 1 is
in assending order and -1 is in decending order.
Spec may contain both * and ? as wildcards. It may also
consist of more than one, comma-delimited selections.
For example: "*.MAC" "A*.MAC" "A?.MAC" "A*.MAC,B*.MAC"
The Type is 1 to include OBJ files
in the search and the default, 0 will just include INT, MAC, INC, BAS.
OrderBy is one of:
Date - Date/Time the file was saved (the default)
Size - Size of the file
Type - Type of the file ie. INT, MAC, INC, BAS
If you wish to return the results in name order then use the RoutineList query as this is faster
as it does not need to build a full list first in order to sort it correctly. nsp is the namespace to list from. If omitted, the query returns the routines from the current
namespace. nsp can be either an explicit or an implied namespace.