You are on page 1of 26

Extreme Database programming with MUMPS Globals

Chapter 1
Globals: An alternative to the relational view
The really important heart of MUMPS is its data storage mechanism. This is based on
what are known as Global Variables, more commonly known simply as Globals. Globals
are an incredibly simple concept, and yet incredibly powerful.
Many people get turned off by Globals. They are a primitie structure. There are none of
the controls, safety nets or alue!added mechanisms that "proper# databases proide. $s
a result, MUMPS is often dismissed as irreleant, insufficient or somehow, %ust plain
wrong. To do so is to ignore a data storage mechanism that is lean, mean and totally
malleable. &n the right hands, that lack of baggage and oerhead can be an incredibly
liberating e'perience. &n the wrong hands it can be a recipe for disaster. &t(s a bit like a
dangerous, e'treme sport such as free!form mountain climbing. )ew "proper#
sportspeople will recommend it, but it(s the fastest, most efficient and most e'hilarating
way up that mountain if you can master the skills to climb without the safety!related
paraphernalia. The climbing e*uipment companies won(t recommend it either, because it
*uestions the need for their products+
So if you think you(re up to the challenge, and ready to accept that there may be another
way to consider data storage than the entrenched relational and S,- iew of the world,
let(s dig deeper.
This first chapter will summarise the basics of Globals. The second chapter focuses on
their use in terms that a ./0MS1S,- programmer will be familiar. &f you wish, skip to
2hapter 3 now and return to 2hapter 4 to familiarise yourself with the basics later.
$ll MUMPS systems and their modern deriaties, such as 2ach5, use Globals as the
basis of their storage mechanism. Many modern MUMPS systems and1or alue!added
packages layer more "conentional# iews onto the core Global construct, eg a global!
based system can be layered to present a logical 6b%ect database, relational database or
natie 7M- database characteristics. &ndeed the same physical Global!based database
could potentially be logically presented and iewed in more than one, if not all, of these
ways. $s a result, there are growing numbers of deelopers who are unaware that
Globals are there under the coers, and unaware of what they are, how they work and
how you can use them. This paper will help you discoer this hidden and, we hope you(ll
agree, ery cool world.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4
So what are Globals?
Put simply, a Global is a persistent, sparse, dynamic, multi!dimensional array, containing
a te't alue. $ctually MUMPS allows the use of both persistent and non!persistent
multi!dimensional arrays, the latter known as "local arrays#.
Somewhat unusually, MUMPS allows the use of both numeric and te'tual subscripting.
So in MUMPS, you can hae an array such as9
8mployee>company,country,office,employee@umber? A employee/etails
eg
8mployee>"MGB#,#UC#,#-ondon#,4? A ".ob TweedD/irectorD;3; EF;F <;:F#
&n this e'ample, the data items that make up the employee details >name, position,
telephone number? hae been appended together with the back!apostrophe character as a
delimiter. MUMPS does not impose any controls or rules oer how you construct your
data structures 9 there(s no schema or data dictionary for describing your database
records. This gies you incredible fle'ibility and speed of deelopment. Gou can
arbitrarily assign one or more data delimiters to break the te't alue of an array record
into a number of "fields#. The total string length that can be assigned to a single array
record depends on the MUMPS implementation, but in 2ach5 it is up to <3k. The string
length that is actually stored is ariable, and you can see that by using a delimiter
character, indiidual fields are ariable length also. This makes MUMPS globals a ery
efficient data storage mechanism 9 there(s almost no disc space holding empty, unused
spaces.
@ow in the e'ample aboe, the employee record will be held in what is known as a
"-ocal $rray#. &f you were to e'it from your MUMPS session, the array would disappear,
%ust like a PHP array once the page or session has gone.
@ow here(s the fun bit. To store this employee record permanently to disc, ie as a Global,
%ust add a "I# in front of the array name9
I8mployee>company,country,office,employee@umber? A employee/etails
eg
I8mployee>"MGB#,#UC#,#-ondon#,4? A ".ob TweedD/irectorD;3; EF;F <;:F#
That(s all there is to it+
So, to create such a global node, you would use the MUMPS command "set#, ie9
set I8mployee>"MGB#,#UC#,#-ondon#,4? A ".ob TweedD/irectorD;3; EF;F <;:F#
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
3
Something that confuses and frightens people about MUMPS is that most commands can
be abbreiated down to a single letter >in upper or lower case?, so you(ll often see the
following instead9
s I8mployee>"MGB#,#UC#,#-ondon#,4? A ".ob TweedD/irectorD;3; EF;F <;:F#
@ow when you e'it from MUMPS, the record will persist on disc permanently. Bhen
you come back at any time in the future, you can retriee the record straight off the disc
by using the global reference9
I8mployee>"MGB#,#UC#,#-ondon#,4?
To recoer a global node within your programs, you typically use the "set# command to
assign the alue held in a global record >or "node#? to a local ariable, eg9
Set company.ecordA I8mployee>"MGB#,#UC#,#-ondon#,4?
The ariable company.ecord will now contain the string alue9
".ob TweedD/irectorD;3; EF;F <;:F#
Globals can hae as many subscripts as you like, and the subscripts can be any mi'ture of
te't and numbers >real or integers?. String subscripts must be surrounded by double
*uotes, while numbers are not.
Most MUMPS implementations hae practical limits oer the total subscript length, so
you can(t go totally oerboard, but you(ll find that it will cater for all of your
re*uirements.
To delete a global node, you use the "kill# command, eg9
Cill I8mployee>"MGB#,#UC#,#-ondon#,4?
That(s literally all there is to Globals. The real trick is how to make such a primitie data
structure work for you. That(s what the rest of this paper will do. Be(ll attempt to do
this in such a way that the relational database programmer can understand the e*uialent
techni*ues and representations that a MUMPS database practitioner would use.
.emember that there(s nothing in MUMPS that will enforce a particular database design
methodology, and its up to you to add the controls and checks that will ensure your
database is logically consistent and error!free. That means you(ll be doing a lot of work
that a more conentional /0MS would otherwise do for you, but you(ll soon find that
you can automate the most repetitie tasks, and make light work of the management of a
MUMPS!based database.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
<
Creating a simple multilevel hierar!h"
Gou may hae multiple leels of subscripting simultaneously in your globals, eg9
I8mployee>"MGB#,#UC#,#-ondon#? A 3
I8mployee>"MGB#,#UC#,#-ondon#,4? A ".ob TweedD/irectorD;3; EF;F <;:F#
I8mployee>"MGB#,#UC#,#-ondon#,3? A "2hris MuntD/irectorD;4J<J <J4F:J#
Here we(re specifying the number of employees at a gien office at the third leel of
subscripting, and the actual employee record at the fourth leel.
-inks between different globals are for the programmer to define. 6nce again MUMPS
proides no automatic inde'ing or cross!linking itself.
Hence, we could hae a telephone number global that acts as an inde' to the employee
global, eg9
I8mployeeTelephone>";3; EF;F <;:F? A "MGBDUCD-ondonD4#
I8mployeeTelephone>";4J<J <J4F:J#? A "MGBDUCD-ondonD3#
&n this e'ample, the data alue stored against each telephone number holds the subscripts
for the associated employee record, concatenated together. 0y knowing the telephone
number, all we(d hae to do is break the data alue apart using the back apostrophe as a
delimiter, and we could retriee the main employee record.
)or e'ample9
S tel@oA#;3; EF;F <;:F#
S inde'/ataAI8mployeeTelephone>tel@o?
S companyAKpiece>inde'/ata,#D#,4?
S countryAKpiece>inde'/ata,#D#,3?
S officeAKpiece>inde'/ata,#D#,<?
S employee@oAKpiece>inde'/ata,#D#,F?
S recordAI8mployee>company,country,office,employee@o?
S employeeAKpiece>record,#D#,4?
@ote the use of the Kpiece MUMPS function to separate out the indiidual "pieces# in the
inde' data string and the employee record string.
6ne of the great things is that nothing in MUMPS has to be pre!declared. Gou decide
when and how to create, modify or delete global records L it(s all automatically and
dynamically handled for you. Gou can add further pieces to your global at any time
without any need for declarations whatsoeer. &f you want to start using another global,
%ust start using it and it will be created dynamically for you.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
F
Setting# Getting an$ Deleting Globals
To summarise, in MUMPS, globals are created and retrieed using the "Set# command,
and deleted using the "Cill# command.
4? 2reating a global record9
Set I8mployee>"MGB#,#UC#,#-ondon#,4?A".ob TweedD/irectorD;3; EF;F <;:F#
This creates the global reference, saing the record to disc.
3? .etrieing a global record
Set dataAI8mployee>"MGB#,#UC#,#-ondon#,4?
This retriees the specified global and places the data alue into a local ariable
named "data#.
<? /eleting a global record9
kill I8mployee>"MGB#,#UC#,#-ondon#,4?
This permanently and immediately deletes the specified global record from disc.
Be very careful with the Kill command L it(s both e'tremely simple to use and
incredibly dangerous. &f you specify fewer subscripts, all lower!leel subscripts
will be deleted. &f you specify no subscripts at all, the entire global will be deleted,
eg9
Cill I8mployee>"MGB#,#UC#?
This will delete all records for all UC offices
Cill I8mployee
This will delete the entire I8mployee global, immediately, permanently and
irretrieably, unless you(d backed it up.
%raversing a Global
6ne of the most fre*uent things you need to do is traerse some or all of a global. )or
e'ample, let(s say you want to manipulate all the employee records, perhaps to display a
list so that the user can select one of them, or to count them. To do this, you use the
Korder MUMPS function. The Korder function is one of the "crown %ewels# of MUMPS,
allowing, with incredible simplicity, access to any of the data you store in your globals.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
:
&t(s not functionality that will be intuitie to a "traditional# database programmer, but it(s
worth understanding because it is so powerful and yet so simple.
The Korder function operates on a single subscript leel within a global, and returns the
ne't subscript alue in collating se*uence that e'ists at that leel in the global. Gou can
specify some starting alue, and the Korder function will find the ne't alue that e'ists in
collating se*uence. To find the first subscript at the specified leel, use a starting alue
of null >"#?. To find the first subscript at the specified leel that starts with "2#, use a
starting alue that collates %ust before "2#, for e'ample "0M#
So, to find the first company in our 8mployee global 9
S companyA##
S companyAKorder>I8mployee>company??
The ariable company now contains the alue of the company subscript in the first record
in the I8mployee global.
Bhen the last alue is found, the ne't time the Korder function is run, it will return a null
alue. So, for e'ample, if there was only one company in the global, if we repeat that
Korder, ie9
S companyAKorder>I8mployee>company??
then the ariable company will now contain a null alue >ie "#?
To get and process all companies in the 8mployee global, we would create a loop9
S companyA##
)or s companyAKorder>I8mployee>company?? *uit9companyA## do
. N do something with the company
This demonstrates some of the interesting features of the breity of MUMPS coding9
The )or command followed by two spaces sets up an infinite loop.
The ,uit9companyA## proides the termination condition for the loop, and uses a
construct known as the "post!conditional#. Bhat this construct is saying is "if the
alue of company is null, then *uit the )or loop#. The ,uit must be followed by
two spaces if any other command is written after it.
The "do# at the end of the line means e'ecute an code that follows at the ne't
"dot# leel. The "do# will get e'ecuted on eery iteration of the )or loop where
company is non!null
The code that is to be e'ecuted on eery loop is written after a single dot. &n
essence, any lines starting with a dot constitute a subroutine that is e'ecuted by
that "do# at the end of the second line in the e'ample.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
O
So, we seed the Korder with a null to make sure that it starts by finding the first subscript
alue that is stored in the global. Be loop through each alue until we e'haust the alues
that are saed, in which case we get a null alue returned by the Korder. Be then detect
this null alue and terminate the loop.
Gou(ll find that this kind of loop is one of the most common things you(ll find in a
MUMPS routine.
Be can e'tend this to traerse the entire global. To do this we loop through each
subscript leel, starting at the first, and progressiely moing to the ne't one9
s companyA##
for s companyAKorder>I8mployee>company?? *uit9companyA## do
. s countryA##
. for s countryAKorder>I8mployee>company,country?? *uit9countryA## do
. . s officeA##
. . for s officeAKorder>I8mployee>company,country,office?? *uit9officeA## do
. . . s employee@oA##
. . . for s employee@oAKorder>I8mployee>company,country,office,employee@o??
*uit9employee@oA## do
. . . . s recordAI8mployee>company,country,office,employee@o?
. . . . N do something with the record
@ote here the way we(e nested the "dot# leels to create a hierarchy of nested
subroutines. $lso note how the Korder is being used to ultimately proide alues for the
four subscripts of the global, so that at the inside of the loop hierarchy, we can process
each and eery record on file.
&f we wanted to find and process only those employees in companies starting with "2#,
then one common method is as follows9
s companyA#0M#
f s companyAKo>I8mployee>company?? *uit9Ke>company,4?(A#2# do
. N do something with the record
@ote the use of the Ke'tract >or Ke? function. This e'tracts the character from the
specified position in the string alue 9 in this case the first character of the company
alue. $lso note way that "not e*uals 2# is specified 9 this uses the MUMPS NOT
operator which is a single *uote >P?.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
J
So read this loop as9
Seed the Korder with a alue that %ust preceeds "2# in collating se*uence
Set up an infinite loop to find all company records in collating se*uence
&f the first character of the company name no longer starts with a "2#, then e'it the
loop
6therwise, process the company record.
This ability to start and stop traersing or parsing a global at any place in the collating
se*uence, and at any leel in the hierarchy of subscripts is pretty much uni*ue to
MUMPS globals.
Che!&ing to see i' a Global no$e exists
Gou(ll often want to know if a particular global node e'ists. Gou can use the MUMPS
Kdata function for this, eg9
if Kdata>I8mployee>company?? do '''
.ead this as "if I8mployee>company? e'ists, then e'ecute the ''' subroutine. The Kdata
function can be abbreiated to Kd.
Kdata will actually return a number of different alues.
&f data e'ists at the specified leel of subscripting, and there are no sub!nodes, a
alue of 4 is returned
&f data e'ists at the specified leel of subscripting, and there are sub!nodes, a
alue of 44 is returned
&f no data e'ists at the specified leel of subscripting, but there are sub!nodes, a
alue of 4; is returned
&f no data and no subnodes e'ist at the specified leel of subscripting, a alue of ;
is returned.
&n MUMPS, any non!Qero alue is ealuated as "true# when a logical operator such as if
is used. Hence, the first three alues returned by Kdata >ie 4, 4; and 44? will ealuate as
true. The last situation >no data and no subnodes? will ealuate as false.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
E
)or e'ample, consider the following global9
ItestA<
Itest>"a#?A4
Itest>"a#,#b#,#c#?A3
Itest>"a#,#b#,#d#?A<
Kdata>Itest? A 44
Kdata>Itest>"a#,#b#?A4;
Kdata>Itest>"a#,#b#,#c#?A4
Kdata>Itest>"b#?A;
Preventing Un$e'ine$ errors
&f you try to retriee a global node that doesn(t e'ist, MUMPS will produce a run!time
error, eg RU@/8)S. To preent this happening, you can either use the Kdata function to
first test for the e'istence of the node, or, more coneniently, you can use the Kget
function. This will return the alue of the global node if it e'ists, or a null alue if it
doesn(t e'ist. The Kget function can be abbreiated to Kg
So, based on the e'ample we used in the preious section on Kdata9
Kget>Itest? A <
Kget>Itest>"a#,#b#?A## N because no data e'ists at this leel of subscripting
Kget>Itest>"a#,#b#,#c#?A4
Kget>Itest>"b#?A##
Kget>Inon8'istentGlobal?A##
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
T
Examining Globals
2ach5 and all other MUMPS systems include utilities for e'amining globals. The
simplest, command line utility is IUG which you(ll find in 2ach5 and some other
MUMPS implementations. .un this from a terminal session9
US8.S D ^%G
Global I Employee
Typing %ust the Global name will list the entire global. Howeer, you can restrict the
listing to specific subscripts, eg9
Employee()
This will list all alues for the first subscript only
Employee(MGW
This will list all 8mployee records with a first subscript alue of MGB
Employee(MGW,)
This will list all second subscripts for 8mployee records with a first subscript of
"MGB#
$lternatiely, 2ach5 proides a graphical user interface tool called 2ach5 8'plorer that
allows you to iew and edit globals.
Con!lusions
Be(e now coered the core basics of what globals are and how they can be created and
manipulated. The ne't chapter will look at globals from the perspectie of someone
familiar with a relational database.
Gou(e probably already realised that MUMPS globals impose ery few controls or
limitations oer what you do. That(s both a great thing L it allows you to ery rapidly and
fle'ibly design, implement and redesign your database structures L and a dangerous thing
L in the wrong hands it can be a recipe for a completely uncontrolled mess. MUMPS
leaes the discipline to you, the programmer. There are no safety nets, but on the other
hand, there(s almost no limit to what you can achiee or how you achiee it. Gou(ll find
that the efficiency of coding and e'ecution is what really makes MUMPS an e'citing and
e'hilarating enironment to work in.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4;
6nce you try using MUMPS globals persistent storage, you(ll probably begin to wonder
why all databases couldn(t work this way+ &ts simple, intuitie, fle'ible and the
performance outstrips any relational database. &ts also aailable for pretty much eery
platform, and will scale to enormous systems L some of the biggest interactie systems in
the world run in MUMPS, some with tens of thousands of concurrent users.
Howeer, if you think you need those controls and safety nets and the features that the
relational world beliee are essential "must!hae# features, then MUMPS is definitely not
for you. &f you(re still determined to go free!form mountain climbing, moe on to the
ne't chapter +
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
44
Chapter (
)D*MS+S,- vs. MUMPS
This chapter will set out the salient differences between a standard .elational /atabase
Management Systems >./0MS? managed through S,- and the MUMPS data repository.
.efer back to to 2hapter 4 if you need to understand more about the basics of Globals and
their manipulation.
De'ining the $ata
-et us start with the basics L defining the data.
$s an e'ample, we shall use a simple database consisting of three tables9
4. $ table of customers >2UST6M8.?.
3. $ table of orders >6./8.?.
<. $ table indicating the items making up an indiidual order >&T8M?.
CUS%/ME) cust@o name address total6rders
V
V
W!!!!!!R /)DE) order@o cust@o order/ate inoice/ate totalValue
V
V
W!!!!!!R 0%EM order@o item@o price
Table names are shown in bol$. The primary key of each table is shown underlined.
CUS%/ME)
cust@o The 2ustomer(s >uni*ue? number.
name The 2ustomer(s name.
address The 2ustomer(s address.
total6rders The number of orders placed by the customer to date.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
43
/)DE)
order@o The order number.
cust@o The releant customer number >a foreign key from 2UST6M8.?.
order/ate The /ate of the 6rder.
inoice/ate The /ate of the &noice.
totalValue The Value of the order.
0%EM
order@o The order number >corresponding key from 6./8.?.
item@o The item >or part? number.
price The price of the item to the customer >including any discount?.
The one!to!many relationships are shown in the diagram. 8ach customer can hae many
orders and each order can be made up of any number of items >or parts?.
The number of orders for a particular customer >2UST6M8..total6rders? is the total
number of orders placed by the customer as identified by 6./8..order@o. The alue of
an order >6./8..totalValue? is the sum of the cost of each item in the order >as
identified by &T8M.price?.
2UST6M8..total6rders and 6./8..totalValue are not directly entered by a user of the
application ! they are deried fields.
)or an ./0MS, these table definitions must be entered into the data definition part of the
database >or schema? before S,- can be used to add, modify and retriee records.
MUMPS does not enforce the use of a data!definition scheme and, as such, records can
be written directly to the MUMPS data store without the need to formally defined the
data. Howeer, it is important to note that a relational schema can easily be layered on
top of an MUMPS data repository for the purpose of accessing the MUMPS data ia
S,-!based reporting tools. $ relational schema can be retrospectiely added to an
e'isting MUMPS data store proided the records are modeled to >appro'imately? third
normal form.
The tables can be represented in MUMPS using the following globals9
CUS%/ME)
I2UST6M8.>cust@o?AnameVaddressVtotal6rders
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4<
/)DE)
I6./8.>order@o?Acust@oVorder/ateVinoice/ateVtotalValue
0%EM
I&T8M>order@o,item@o?Aprice
The relationship between the 2UST6M8. and 6./8. tables could be represented by
another global9
I6./8.74>cust@o,order@o?A##
This would proide pointers to all 6rder @umbers for a specified 2ustomer @umber.
&n MUMPS, its up to you what global names you use. $lso you hae a choice of either
using different globals for each table >as we(e shown aboe?, or using the same global
for some or all the tables and indices. )or e'ample, we could pack eerything together
using the following global structure9
I6rder/atabase>"customer#,cust@o?A nameX#M#XaddressX#M#Xtotal6rders
I6rder/atabase>"order#,order@o?A cust@oX#M#Xorder/ateX#M#Xinoice/ateX#M#XtotalValue
I6rder/atabase>"item#,order@o,item@o?Aprice
I6rder/atabase>"inde'4#,cust@o,order@o?A##
)or the purposes of the e'amples that follow, we(e chosen to use separate globals for
each table.
Be(e also decided, arbitrarily, to use a tilde >M? character as the data delimiter in our
e'ample globals.
A$$ing new re!or$s to the Database
-et(s start with a really simple e'ample. -et(s add a new customer record to the customer
table.
S,-
INSERT INTO CUSTOMER (CustNo, Name, Address)
VALUES (100, Chris Mut!, O"#ord!)
MUMPS
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4F
Set $CUSTOMER(100)% &Chris Mut'()*)()O"#ord)
Be are using the tilde character >M? as the field delimiter. Be can, of course, use any
character we like for this purpose >including non!printable characters?. )or e'ample, we
could use9
Set $CUSTOMER(100)% &Chris Mut'(+,(1)()O"#ord)
.ead the Kc>4? >aka Kchar? function as meaning "the character whose $S2&& alue is 4#.
This second alternatie therefore uses $S2&& 4 as a field delimiter.
6f course, in a real situation, the data alues would be passed to the insert *uery >or
MUMPS command? by means of a program as alues of ariables9
S,-
INSERT INTO CUSTOMER (,ustNo, -ame, -address)
VALUES (-,ustNo, -ame, -address)
MUMPS
Set $CUSTOMER(,ustNo)%ame()*)(address
)etrieving re!or$s 'rom the $atabase
S,-
SELECT A.ame, A.address
/ROM CUSTOMER A
01ERE A.,ustNo % -,ustNo
MUMPS
Set re,ord%+2et($CUSTOMER(,ustNo))
Set ame%+3ie,e(re,ord,)*),1)
Set address%+3ie,e(re,ord,)*),1)
@ote the use of the Kget>?. This is a conenient way of safely retrieing a global node. &f
the node doesn(t actually e'ist, the Kget>? function returns a null >"#?. &f you don(t use the
Kget>? function, ie9
Set re,ord%$CUSTOMER(,ustNo)
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4:
Then if the specified global node doesn(t e'ist, MUMPS will return a run!time
RU@/8)S >ie undefined? error. -ike most commands and functions in MUMPS, the
Kget>? function can be abbreiated to %ust Kg>?, eg9
Set re,ord%+2($CUSTOMER(,ustNo))
)emoving re!or$s 'rom the $atabase
S,-
4ELETE /ROM CUSTOMER A
01ERE A.,ustNo % -,ustNo
MUMPS
5i66 $CUSTOMER(,ustNo)
@ote that this simple e'ample doesn(t take referential integrity into account. Gou(ll see
later how we(ll deal with this.
Parsing the $atabase
S,-
SELECT A.,ustNo, A.ame, A.address
/ROM CUSTOMER A
MUMPS
s ,ustNo%'' # s ,ustNo%+order($CUSTOMER(,ustNo)) 7uit-,ustNo% &' do
. Set re,ord%+2et($CUSTOMER(,ustNo))
. Set ame%+3ie,e(re,ord,)*),1)
. Set address%+3ie,e(re,ord,)*),8)
. Set tota6Orders%+3ie,e(re,ord,)*),9)
. : add ,ode here to 3ro,ess the &se6e,ted ro;'
@ote the use of the so!called "dot synta'#. The lines preceded with a dot >".#? represent a
subroutine, called by the "do# command that terminated the first line. Typically you
would do whateer you need to do with each "selected row# within the subroutine, as
indicated by the comment >the last line that starts with the semi!colon >"N#?.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4O
The Korder function in MUMPS is one of the keys to the power and fle'ibility of globals.
&ts functionality is not likely to be intuitie to someone familiar with ./0MS and S,-,
so it(s word reading the more detailed description in 2hapter 4.
Bith Korder and globals, you hae total access to step through any of the keys in a table,
starting and finishing on any alue we wish. The important thing is to understand that
Globals represent a hierarchical data storage structure. The key fields in the tables we(re
emulating are represented as the subscripts in a global, so we no longer hae to access
rows from a table in strict se*uence9 the Korder function can be applied to each subscript
>key? independently.
Using MUMPS 'un!tions to en!apsulate $atabase a!!ess
&n practice, and in order to ma'imise code reuse, the MUMPS *ueries shown preiously
would usually be implemented as functions. 8'amples of such functions are shown
below.
A$$ing new re!or$s to the $atabase:
setCustomer(,ustNo,data) :
I# ,ustNo%)) 7uit 0
Set $CUSTOMER(,ustNo)%data()ame))()*)(data()address))
7uit 1
This function could be now called repeatedly in the following way9
kill data ; clear down data local array
set data()name))=)Rob Tweed)
set data()address))=)London)
set custNo=101
set ok=$$setCustomer(custNo,.data)
@ote the period >".#? in front of the data parameter. This is a "call by reference#. data is
a local array, not a simple scalar ariable, so we must pass the name of the array by
reference into the function.
The e'ample aboe assumes that the set2ustomer function is contained in the same
MUMPS routine as our e'ample run!time code. set2ustomer might be held in a different
routine >eg Imy)unctions?, in which case our run!time code would look like the
following9
kill data ; clear down data local array
set data()name))=)Rob Tweed)
set data()address))=)London)
set custNo=101
set ok=$$setCustomer^myFunctions(custNo,.data)
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4J
The KKset2ustomer>? function is known as an extrinsic function. Think of e'trinsic
functions as accessor methods and you won(t go far wrong. The KKset2ustomer function
returns ; >ie false? if a null alue of customer number is specified. 6therwise the record is
saed and it returns 4 >ie true?. Gou may want to test the alue of the ariable ok to check
that the function worked.
0ecause we hae a deried field >total6rders? within the 2UST6M8. table, the
MUMPS code would more properly be9
setCustomer(,ustNo,data) :
i# ,ustNo%)) 7uit 0
: 4eri<e the um=er o# orders
Set data(&tota6Orders')%0
Set orderNo%''
#or set orderNo%+order($OR4ER>1(,ustNo,orderNo)) 7uit-orderNo%'' do
. set data(&tota6Orders')%data(&tota6Orders')?1
set $CUSTOMER(,ustNo)%data()ame))()*)(data()address))('*'(data(&tota6Orders')
7uit 1
Be will discuss these deried fields later in the Ptriggers( section.
)etrieving re!or$s 'rom the $atabase:
The following e'trinsic function will retriee a row from the 2UST6M8. table.
2etCustomer(,ustNo,data) :
e; re,ord
5i66 data : ,6ear do; data arra@
i# ,ustNo%)) 7uit 0
set re,ord%+2et($CUSTOMER(,ustNo))
set data()ame))%+3ie,e(re,ord,)*),1)
set data()address))%+3ie,e(re,ord,)*),8)
set data()tota6Orders))%+3ie,e(re,ord,)*),9)
7uit 1
This function can be used as follows9
S cust@oA4;4
set okAKKget2ustomer>cust@o,.data?
This will return the local array data >note the call by reference? containing the three data
fields for the specified customer number9
data>"name?
data>"address#?
data>"total6rders#?
)emoving re!or$s 'rom the $atabase:
The following e'trinsic function will delete a row from the 2UST6M8. table9
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4E
de6eteCustomer(,ustNo) :
i# ,ustNo%)) 7uit 0
5i66 $CUSTOMER(,ustNo)
7uit 1
This function can be used as follows9
S cust@oA4;4
S okAKKdelete2ustomer>cust@o?
Se!on$ar" 0n$i!es
&n an ./0MS, secondary indices are maintained within the data!definition layer. Haing
defined them there, the contents of the inde' are automatically created and maintained by
the ./0MS.
&nde'es within MUMPS are maintained e'plicitly, for e'ample in the table(s update
function. 0ecause of the hierarchical nature of the MUMPS data repository, the primary
record doubles as an inde' based on the primary key.
)or e'ample, consider the MUMPS function for adding a new record to the 6./8.
table9
setOrder(orderNo,data) :
e; re,,itemNo,o5
i# orderNo%)) 7uit 0
: Ca6,u6ate the <a6ue o# the order
set data(&tota6Va6ue')%0
set itemNo%''
#or set itemNo%+Order($ITEM(orderNo,itemNo)) 7uit-itemNo%'' do
. set o5%++2etItem(orderNo,itemNo,.item4ata)
. Set data(&tota6Va6ue')%data(&tota6Va6ue')?item4ata(&3ri,e')
set re,%data(),ustNo))()*)(data()order4ate))()*)(data()i<oi,e4ate))
set re,%re,('*'(data(&tota6Va6ue')
set $OR4ER(orderNo)%re,
7uit 1
@otice the code for calculating the alue of the order. This parses all the &T8M records
for the specified 6rder @umber, and uses the KKget&tem>? function to reteiee the alue
for each item. The KKget&tem>? function would contain the following9
getItem(orderNo,itemNo,itemData)
kill itemData
s itemData(price)=0
if orderNo= Quit 0
if itemNo= Quit 0
if $data(^ITEM(orderNo,itemNo)) Quit 0
set itemData(price)=^ITEM(orderNo,itemNo)
Quit 1
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
4T
@ote the line in this function that checks for the e'istence of a global node for the
specified 6rder @umber and &tem @umber. This uses the MUMPS function Kdata, and
also the not operator >"(#?.
@ow, suppose we wish to add the inde' to facilitate easy access to orders on a per!
customer basis. Be(re representing this by another global named I6./8.74. To do
this we create an inde' on 2ustomer @umber >cust@o? and 6rder @umber >order@o?.
This would be implemented by e'tending the set6rder function as follows9
setOrder(orderNo,data) :
e; re,,itemNo,o5
i# orderNo%)) 7uit 0
: Ca6,u6ate the <a6ue o# the order
set data(&tota6Va6ue')%0
set itemNo%''
#or set itemNo%+Order($ITEM(orderNo,itemNo)) 7uit-itemNo%'' do
. set o5%++2etItem(orderNo,itemNo,.item4ata)
. Set data(&tota6Va6ue')%data(&tota6Va6ue')?item4ata(&3ri,e')
set re,%data(),ustNo))()*)(data()order4ate))()*)(data()i<oi,e4ate))
set re,%re,('*'(data(&tota6Va6ue')
set $OR4ER(orderNo)%re,
i# data(&,ustNo')!%'' set $OR4ER>1(data(&,ustNo'),orderNo)%''
7uit 1
Be(d use this function to create an order as follows9
set orderNo=21
kill data
set data(custNo)=101
set data(orderDate)=4/5/2003
set data(invoiceDate)=4/7/2003
set ok=$$setOrder(orderNo,.data)
)e'erential 0ntegrit"
.eferential &ntegrity is, perhaps, the best known of a general class of Preferential actions(.
.eferential actions include all operations that inole changes to tables that must be made
as a direct conse*uence of modifications to other tables.
The process of maintaining .eferential &ntegrity is responsible for maintaining semantic
integrity between related tables. Specifically, it is concerned with maintaining the natural
%oins or primary1foreign key correspondences between tables.
)or e'ample, when a customer number >2UST6M8..cust@o? is changed from one alue
to another >or remoed?, in order to maintain semantic integrity between the customer
table and the order table, a corresponding change is indicated in the order table
>6./8..cust@o?. Similarly, when an order number >6./8..order@o? is changed from
one alue to another >or remoed?, in order to maintain semantic integrity between the
order table and the item table, a corresponding change is indicated in the item table
>&T8M.order@o?.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
3;
&n an ./0MS, these integrity rules are implied by the information contained within the
data definition layer >primary and foreign keys?. &n MUMPS, these rules can be
implemented directly within our functions for maintaining the data store.
Taking the relationship between the customer and the order table, an update operation for
2UST6M8. would be e'pressed as9
S,-
UA4ATE CUSTOMER A
SET ,ustNo % -e;CustNo
01ERE A.,ustNo % -o6dCustNo
This *uery will result in the corresponding records being updated in the 6./8. table
>according to the %oin 2UST6M8..cust@o A 6./8..cust@o?

MUMPS
u3dateCustomer(o6dCustNo,e;CustNo,e;4ata) :
e; resu6t,order4ata,orderNo
i# (o6dCustNo%)))B(e;CustNo%))) 7uit 0
set orderNo%))
#or set orderNo%+order($OR4ER>1(o6dCustNo,orderNo)) 7uit-orderNo%)) do
. set resu6t%++2etOrder(orderNo,.order4ata)
. set order4ata(),ustNo))%e;CustNo
. set o5%++setOrder(orderNo,.order4ata)
set o5%++setCustomer(e;CustNo,.e;4ata)
i# e;CustNoC%o6dCustNo set o5%++de6eteCustomer(o6dCustNo)
7uit 1
@otice that this function is largely built using functions that we hae already created for
the purpose of maintaining the customer and order table. &t is easy to reuse code in
MUMPS.
Be(d need to create the KKget6rder function 9
2etOrder(orderNo,order4ata) :
e; re,ord
i# (orderNo%))) 7uit 0
set re,ord%+2($OR4ER(orderNo))
set order4ata(&,ustNo')%+3ie,e(re,ord,'*',1)
set order4ata(&order4ate')%+3ie,e(re,ord,'*',8)
set order4ata(&i<oi,e4ate')%+3ie,e(re,ord,'*',9)
set order4ata(&tota6Va6ue')%+3ie,e(re,ord,'*',D)
7uit 1
Be(ll also need to e'tend our original, simple KKdelete2ustomer>? function. Similar
considerations apply to operations that remoe customer records from the database. The
S,- *uery together with its e*uialent M function is shown below.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
34
S,-
4ELETE /ROM CUSTOMER A
01ERE A.,ustNo % -,ustNo
This *uery will result in the corresponding records being deleted from the 6./8. table
>according to the %oin 2UST6M8..cust@o A 6./8..cust@o and the integrity rules
specified within the data!definition layer?.
MUMPS
de6eteCustomer(,ustNo) :
e; orderNo
i# ,ustNo%)) 7uit 0
set orderNo%))
#or set orderNo%+order($OR4ER>1(,ustNo,orderNo)) 7uit-orderNo%)) do
. set resu6t%++de6eteOrder(,ustNo,orderNo)
5i66 $CUSTOMER(,ustNo)
7uit 1
This re*uires the KKdelete6rder>? function9
de6eteOrder(,ustNo,orderNo) :
5i66 $ITEM(orderNo) : remo<e a66 order items
5i66 $OR4ER(orderNo) : remo<e the order
5i66 $OR4ER>1(,ustNo,orderNo) : remo<e the ,ustomerEorder re6atioshi3
7uit 1
@ote that all item records in the &T8M table can be remoed by applying the kill
command at the order@o hierarchy leel.
This assumes that a Pcascading( relationship is re*uired between the customer and order
table. $ Pbreaking link( relationship would be implemented as follows9
de6eteCustomer(,ustNo) :
e; orederNo,resu6t,order4ata
i# ,ustNo%)) 7uit 0
set orderNo%))
#or set orderNo%+order($OR4ER>1(,ustNo,orderNo)) 7uit-orderNo%)) do
. set resu6t%++2etOrder(orderNo,.order4ata)
. set order4ata(),ustNo))%''
. set resu6t%++setOrder(orderNo,.order4ata)
5i66 $CUSTOMER(,ustNo)
7uit 1
Similar logic will apply with respect to data held in the &T8M table when an 6rder
@umber >6./8..order@o? is modified in, or deleted from the 6./8. table.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
33
%riggers
Triggers are simply a way of automatically inoking pre!defined code when certain
conditions are met within the database. $ trigger is usually fired as a result of records
being updated in a certain way within the database.
&n an ./0MS, triggers are defined within the data definition layer. &n MUMPS we can
add trigger code directly to the functions that we write for the purpose of maintaining the
data store.
)or e'ample, consider the number of orders for a customer >2UST6M8..total6rders?.
Be could define a trigger to automatically update this field as records are added >or
remoed? from the order table.
S,-
The following S,- would be included in the trigger code within 6./8. for the purpose
of creating 2UST6M8..total6rders9
SELECT COUNT(A.orderNo)
/ROM A.OR4ER
01ERE A.,ustNo % -,ustNo
This *uery will be triggered for all constructie and destructie operations that are
applied to the 6./8. table >according to the %oin 2UST6M8..cust@o A
6./8..cust@o?
MUMPS
Be simply add the following >trigger? code to the function for adding records to the order
table9
setOrder(orderNo,data) :
e; re,,itemNo,o5
i# orderNo%)) 7uit 0
: Ca6,u6ate the <a6ue o# the order
set data(&tota6Va6ue')%0
set itemNo%''
#or set itemNo%+Order($ITEM(orderNo,itemNo)) 7uit-itemNo%'' do
. set o5%++2etItem(orderNo,itemNo,.item4ata)
. Set data(&tota6Va6ue')%data(&tota6Va6ue')?item4ata(&3ri,e')
set re,%data(),ustNo))()*)(data()order4ate))()*)(data()i<oi,e4ate))
set re,%re,('*'(data(&tota6Va6ue')
set $OR4ER(orderNo)%re,
i# data(&,ustNo')!%'' set $OR4ER>1(data(&,ustNo'),orderNo)%''
:
: Tri22er the u3date o# the CUSTOMER.tota6Orders #ie6d
e; ,ust4ata
Set o5%++2etCustomer(data(&,ustNo'),.,ust4ata)
Set o5%++setCustomer(data(&CustNo'),.,ust4ata)
:
7uit 1
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
3<
The same considerations apply to operations that remoe data from the 6./8. table.
$ similar scheme can be employed for the purpose of automatically updating the alue of
an order >6./8..totalValue? as items are added to the order.
S,-
The following S,- would be included in the trigger code for the &T8M table for the
purpose of generating 6./8..Value9
SELECT SUM(A.3ri,e)
/ROM A.ITEM
01ERE A.orderNo % -orderNo
This *uery will be triggered for all constructie and destructie operations that are
applied to the &T8M table >according to the %oin 6./8..order@o A &T8M.order@o?
MUMPS
Be simply add the following >trigger? code to the function for adding records to the
&T8M table9
setItem(orderNo,itemNo,data) :
e; o5
i# (orderNo%)))B(itemNo%'') 7uit 0
set $ITEM(orderNo,itemNo)%data()3ri,e))
set$OR4ER>1(,ustNo,orderNo)%''
: Tri22er the u3date o# the OR4ER.tota6Va6ue #ie6d
set o5%++2etOrder(orderNo,.order4ata)
set o5%++setOrder(orderNo,.order4ata)
7uit 1
The same considerations apply to operations that remoe data from the &T8M table.
$ further e'ample of the use of triggers in our customer and orders database would be to
automatically generate and raise an inoice for the customer as soon as an inoice date is
added to the order table >6./8..inoice/ate?. Be can ery simply add this
functionality to our procedure for updating the 6./8. table9
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
3F
setOrder(orderNo,data) :
e; re,,itemNo,o5
i# orderNo%)) 7uit 0
: Ca6,u6ate the <a6ue o# the order
set data(&tota6Va6ue')%0
set itemNo%''
#or set itemNo%+Order($ITEM(orderNo,itemNo)) 7uit-itemNo%'' do
. set o5%++2etItem(orderNo,itemNo,.item4ata)
. Set data(&tota6Va6ue')%data(&tota6Va6ue')?item4ata(&3ri,e')
set re,%data(),ustNo))()*)(data()order4ate))()*)(data()i<oi,e4ate))
set re,%re,('*'(data(&tota6Va6ue')
set $OR4ER(orderNo)%re,
i# data(&,ustNo')!%'' set $OR4ER>1(data(&,ustNo'),orderNo)%''
:
: Tri22er the u3date o# the CUSTOMER.tota6Orders #ie6d
e; ,ust4ata
Set o5%++2etCustomer(data(&,ustNo'),.,ust4ata)
Set o5%++setCustomer(data(&CustNo'),.,ust4ata)
:
: Raise a i<oi,e i# a i<oi,e date is etered
i# 4ata(&i<oi,e4ate')!%'' Set Resu6t%++i<oi,eOrder(orderNo)
:
7uit 1
6f course, the e'trinsic function KKinoice6rder>? would hae to be written to carry out
the appropriate processing logic to raise the inoice.
%ransa!tion Pro!essing
$ complete update to a database often consists of many indiidual updates to a number of
tables. $ll contributing updates must be guaranteed to complete before the whole update
>or transaction? can be said to be complete.
&n an ./0MS, transaction control is usually actie as a matter of default behaiour. &n
other words, changes to the database are not committed until the modifying process issues
a Pcommit( command, at which point the updates are committed to the database and a
new transaction begins.
MUMPS is ery similar in this respect with the e'ception that transaction control has to
be e'plicitly turned!on. $ program must issue a Ptransaction start( command in addition
to the Ptransaction( commit command.
S,-
2ommit a transaction and >implicitly? start a new transaction9
COMMIT
MUMPS
Start a new transaction9
TSTART
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
3:
2ommit a transaction9
TCOMMIT
&f transaction control is not e'plicitly switched on in a MUMPS system, then all updates
for that process will be immediately made to the lie data store. &n other words, each and
eery S8T or C&-- of a global node will be regarded as a complete transaction in its own
right.
Con!lusions
There are many key adantages to using MUMPS oer a traditional ./0MS.
Maintainability and core reuse. Bith discipline, an e'tremely high leel of code reuse
can be achieed. The e'amples we(e described in this paper demonstrate how you
can encapsulate all your database actions in terms of get, set and delete functions for
each table L write these once and re!use them.
Transportability. The definition of the data is contained within the functions that
operate on it. There is no diision between definition and implementation.
)le'ibility. The update code can be modified to trigger any action or eent within the
system.
Performance and fine!tuning. 8'perienced MUMPS analysts will recognise
opportunities for tuning the functions shown here for maintaining the data store. This
is possible because the definition of the data and the implementation of the operations
that are applied to it are held together within discrete functions. The analyst using
S,- has no fine control oer the way triggers, referential actions or transactions are
managed.
The adantages of using S,- to maintain or retriee the data >use of third party
reporting tools, for e'ample? are not lost because a relational data definition can be
transparently layered oer the top of an e'isting set of MUMPS tables >globals?. This
can een be done retrospectiely. )or e'ample, both 2ach5 S,- and the third!party
C0XS,- product >http911www.kbsystems.com1?, implement a full S,- enironment,
layered on MUMPS globals.
8'treme /atabase Programming with MUMPS Globals
Version 4.4 9 4: May 3;;<
=3;;<, M1Gateway /eelopments -td >http911www.mgateway.com?
3O

You might also like