It is currently Mon Jun 24, 2019 2:13 am

All times are UTC - 8 hours [ DST ]

Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: Unit 3 - Lesson 2: Create/Edit Database - Exercise 4
PostPosted: Sun Jul 10, 2011 10:35 am 
User avatar

Joined: Wed Nov 17, 2010 8:37 am
Posts: 136
Real Name: Terry L. Wiechmann
Began Programming in MUMPS: 0- 0-1971
Exercise 3 Solution

Routine: MP1PEDIT
MP1PEDIT ; Create/Edit Parts routine for the MP1 Course.
INIT ; Initialize all variables and drop through.
PNUM ; Part Number
    Write !,"Part Number: "
    Write:$Get(PNUM)]"" PNUM," // "
    Read X
    If X="" Set X=PNUM
    If X'?1.6N Goto EXIT:X["^" Do  Goto PNUM
    . Write !?5,"Enter 1-6 numeric digits. Required."
    Set PNUM=X
PDESC ; Description
    Write !,"Description: "
    Write:$Get(PDESC)]"" PDESC," // "
    Read X
    If X="" Set X=PDESC
    If X'?1A.29NAP Goto PNUM:X["^" Do  Goto PDESC
    . Write !?5,"Enter 1-30 characters starting with a letter. Required."
    Set PDESC=X
PQTY ; Quantity
    Write !,"Quantity: "
    Write:$Get(PQTY)]"" PQTY," // "
    Read X
    If X="" Set X=PQTY
    If X'?1.N Goto PDESC:X["^" Do  Goto PQTY
    . Write !?5,"Enter an integer value. Required."
    Set PQTY=X
PLVL ; Reorder Level (it's time to reorder the part if PQTY<PLVL)
    Write !,"Order Level: "
    Write:$Get(PLVL)]"" PLVL," // "
    Read X
    If X="" Set X=PLVL
    If X'?1.N Goto PQTY:X["^" Do  Goto PLVL
    . Write !?5,"Enter an integer value. Required."
    Set PLVL=X
PRC ; Replacement Cost
    Write !,"Replacement Cost: "
    Write:$Get(PRC)]"" PRC," // "
    Read X
    If X="" Set X=PRC
    If X'?.N.1".".2N Goto PLVL:X["^" Do  Goto PRC
    . Write !?5,"Enter replacement cost in dollars[.cents]"
    Set PRC=X
PSP ; Selling Price
    Write !,"Selling Price: "
    Write:$Get(PSP)]"" PSP," // "
    Read X
    If X="" Set X=PSP
    If X'?.N.1".".2N Goto PRC:X["^" Do  Goto PSP
    . Write !?5,"Enter selling price in dollars[.cents]"
    Set PSP=X
FEI ; File/Edit/Ignore Entry
    Set Default="F"
    Write !,"File (F), Edit (E) or Ignore (I) : "
    Write:$Get(PLVL)]"" Default," // "
    Read X
    If X["^" Goto PSP
    If X="" Set X=Default
    ; This code demands rigid upper/lowercase entry. Will be normalized.
    If $Extract("Edit",1,$Length(X))=X Goto PNUM
    If $Extract("Ignore",1,$Length(X))=X Goto INIT
    If $Extract("File",1,$Length(X))=X Do PUT Goto INIT
    Write " Enter F, E or I."
    Goto FEI

  1. Add code to normalize values used for indices.
  2. Add the PUT subroutine to file the Parts record..
  3. Add the lookup code for a part number.
  1. At this point you have a simple routine that lets you create a new Parts record and edit it. The next logical step is to write the code (PUT) that will add it to persistent storage. Once it is in the database, we need to write the lookup code (GET) that will bring the record back into local storage for editing.
  2. Read the Global Structure section in the Student Guide again.
  3. When data is stored in persistent storage for future lookup and use, it must be normalized. That is, put into a form that makes it consistent and standardized. This applies to all data elements, especially to those that are used for lookup. For the Parts global, that is the PNUM and PDESC data elements. They are used to create indices for lookup.
  4. The value of PNUM must be numeric. The syntax check makes sure it is. However, the PDESC value must be normalized to uppercase. The syntax check passes upper and lowercase because we do not want to burden the user with that knowledge. It is the responsibility of the model side filer to insure normalization.
  5. Since this is a generic function, we will create it as an extrinsic function within a new routine called MP1XLATE. In fact, we will create two entry extrinsic functions called Upper and Lower.
    Upper(S) ; Translate the value in the String variable to Uppercase.
        Set S=$Get(S)
        Quit $Translate(S,"abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ")
    Lower(S) ; Translate the value in the String variable to Lowercase.
        Set S=$Get(S)
        Quit $Translate(S,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")
  6. Now, lets write the PUT code. Up until this point, all the code we've written could be classified as View and Controller code. The PUT code falls in the Model domain.
    PUT ; File the Parts record.
       ; If entry does exist, get the old indice values.
       If IEN Do
       . ;Get original indices values.
       . Set OPNUM=$Piece(^MP1PARTS(IEN),"^",1)
       . Set OPDESC=$Piece(^MP1PARTS(IEN),"^",2)
       ; If entry does not exist, get a new Internal Entry Number (IEN).
       Else  Do
       . ; Init old values to null - new record.
       . Set (OPNUM,OPDESC)=""
       . Lock +^MP1PARTS(0):0 ; Increment lock count on node. Force timeout.
       . Else  Write !?5,"Cannot get next node number – record not filed." Quit
       . If '$Data(^MP1PARTS(0)) Set ^MP1PARTS(0)=0
       . Set (IEN,^MP1PARTS(0))=^MP1PARTS(0)+1
       . Lock -^MP1PARTS(0) ; Decrement lock count on node
       ; Make sure indices do not exist - multiple indices not permitted.
       If PNUM'=OPNUM,$Data(^MP1PARTS("B",PNUM)) Do  Quit
       . Write !?5,"Number "_PNUM_" is already being used."
       If PDESC'=OPDESC,$Data(^MP1PARTS("C",PDESC)) Do  Quit
       . Write !?5,"Description "_PDESC_" is already being used."
       ; Lock record node incrementally.
       Lock +^MP1PARTS(IEN):0 ; Increment lock count on record. Force timeout.
       ; If timeout occurred and no lock then pass back record busy message.
       Else  Write !?5,"Record busy – record not filed." Quit
       ; Remove old indices.
       ; Set the new record and indices nodes.
       Set ^MP1PARTS(IEN)=PNUM_"^"_PDESC_"^"_PQTY_"^"_PLVL_"^"_PRC_"^"_PSP
       Set ^MP1PARTS("B",PNUM,IEN)=""
       Set ^MP1PARTS("C",PDESC,IEN)=""
       ; Incrementally unlock record node.
       Lock -^MP1PARTS(IEN) ; Decrement lock count on node
       Write !?5,"Record filed successfully."
  7. The IEN value is used to determine Create or Edit mode. Add the variable IEN to the New list and initialize it to zero. It will be used in the PUT subroutine and must exist for this iteration of the routine.
    INIT ; Initialize all variables and drop through.
        Set IEN=0
  8. Reminder: Please note, all of this code is tightly bound and does not conform to structured programming or the M-V-C pattern. The reason we are doing this is to give you practice coding and to let you see the patterns as they emerge. You should be seeing those patterns at this point.
  9. Lets walk through the code so we understand it. If you do not understand the functionality of the language elements, make sure you refer to your Pocket Guide, Student Guide or Implementation specific documentation. You must get to the point where you can recall the language elements from memory.
  10. First, the IEN is the unique entry number. The record is filed at the ^MP1PARTS(IEN) node which becomes unique. If it is non-zero, this means a record for the PNUM value exists and was looked up before editing each data element. (The lookup code does not exist and will be added next.)
  11. If it does exist and the values were edited, checks would be performed to make sure the values of PNUM and PDESC do not exist already. Note: In a real application, duplicate entries are often permitted. For example, people with the same name. Once verified as not exiting under a different IEN, the existing indices are killed.
  12. If the IEN is zero (hence the Else statement), a new IEN is generated. Note that the code is surrounded by an incremental and decremental Lock command. This serializes the processing of the code to prevent conflict between multiple processes that may be executing the same code at the same time. The Lock command enters the node name in a system table. Locking in MUMPS is purely conventional and requires everyone writing code to adhere to the same convention. If not, it is simply possible to bypass the convention with possible dire consequences.
  13. Regardless of the last two conditions, the record is set to the ^MP1PARTS(IEN) node as well as each index. It too is surrounded by the incremental Lock.
  14. Now that you can populate the global, we need to be able to lookup each record. This is code that does the lookup. The "Set PNUM=X" line is replaced.
    PNUM ; Part Number
        Write !,"Part Number: "
        Write:$Get(PNUM)]"" PNUM," // "
        Read X
        If X="" Set X=PNUM
        If X'?1.6N Goto EXIT:X["^" Do  Goto PNUM
        . Write !?5,"Enter 1-6 numeric digits. Required."
        If 'IEN Do
        . Quit:'$Data(^MP1PARTS("B",X))
        . Set IEN=$Order(^MP1PARTS("B",X,""))
        . Set REC=^MP1PARTS(IEN)
        . Set PDESC=$Piece(REC,"^",2)
        . Set PQTY=$Piece(REC,"^",3)
        . Set PLVL=$Piece(REC,"^",4)
        . Set PRC=$Piece(REC,"^",5)
        . Set PSP=$Piece(REC,"^",6)
        Set PNUM=X
  15. I used the variable REC to hold the record (or empty record). If we do not hide it with the New command (top of routine) it will lay around in the symbol table.

Terry L. Wiechmann

Offline Profile  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC - 8 hours [ DST ]

Who is online

Users browsing this forum: No registered users and 2 guests

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Theme created