Stored Procedures and MUMPS for DivConq

35
DivConq Framework’s MUMPS API

description

Reviews examples of details on how to pass data to a stored procedure and how to return data from a stored procedure. Further shows how to pass status or debugging messages from stored procedure, including message localization.

Transcript of Stored Procedures and MUMPS for DivConq

Page 1: Stored Procedures and  MUMPS for DivConq

DivConq Framework’s MUMPS API

Page 2: Stored Procedures and  MUMPS for DivConq

DivConq Database

Page 3: Stored Procedures and  MUMPS for DivConq

This presentation is part of a sequence of presentations on DivConq’s database

features. Visit the Getting Started page at our website to see the suggested order

for our presentations.

About DivConq http://www.divconq.com/about/

Getting Started With DivConq

http://www.divconq.com/home/getting-started/

Page 4: Stored Procedures and  MUMPS for DivConq

Coding and Testing in MUMPS

Page 5: Stored Procedures and  MUMPS for DivConq

In the previous presentations we focused on how stored procedures worked

within Java. Things like the request-response flow, request objects, callbacks,

schema and JSON-Like data structures.

In the coming slides the focus is going to be on MUMPS development for stored

procedures. We’ll use some examples that ship with DivConq Framework so you

can follow along.

Page 6: Stored Procedures and  MUMPS for DivConq

You should recall how to run TestDb from previous presentations in Getting

Started. If not then you may wish to review those presentations.

D:\dev\divconq\template>.\bin\run.bat testdb Command testdb Starting Hub ...

Page 7: Stored Procedures and  MUMPS for DivConq

Select option 4 “Load stored proc results (testProc1)”. The output we see will be

JSON, but keep in mind the database result uses DivConq’s Struct classes

(JSON-Like API). Your output should be:

testProc1 Response: { "Name": "Sally", "Age": 5, "Toys": [ "Legos", "Puzzle" ] , "Friends": [ { "Name": "Chad", "Age": 5 } , { "Name": "Ginger", "Age": 6 } ] }

Page 8: Stored Procedures and  MUMPS for DivConq

Open the MUMPS code file dctTest.m ni a text editor to follow within the real

source code.

D:\dev\divconq\template\packages\dcTest\m\dctTest.m

Page 9: Stored Procedures and  MUMPS for DivConq

This first and simplest example starts by populating a local MUMPS data

structure.

testProc1 n data,tnum,fnum ; s data("Name")="Sally" s data("Age")=5 s data("Toys",1)="Legos" s data("Toys",2)="Puzzle" s data("Friends",1,"Name")="Chad" s data("Friends",1,"Age")=5 s data("Friends",2,"Name")="Ginger" s data("Friends",2,"Age")=6 ; [continued]

Page 10: Stored Procedures and  MUMPS for DivConq

Then the result is started by using MUMPS’ “write” commands. The start of a

record or list begins with StartRec or StartList. The start of a field name starts

with Field. The start of a field value or item is always ScalarNNN.

[continued] w StartRec w Field_"Name"_ScalarStr_data("Name") w Field_"Age"_ScalarInt_data("Age") ; w Field_"Toys"_StartList f s tnum=$o(data("Toys",tnum)) q:tnum="" d . w ScalarStr_data("Toys",tnum) w EndList ; [continued] Java output from this part: { "Name": "Sally", "Age": 5, "Toys": [ "Legos", "Puzzle" ] ,

Page 11: Stored Procedures and  MUMPS for DivConq

“Friends” is a field. The field value is a list of records where each record has two

fields. Note how EndRecord and EndList are paired, you must have an EndNNN

for every StartNNN. Field and ScalarNNN do not need an ending delineator.

[continued] w Field_"Friends"_StartList f s fnum=$o(data("Friends",fnum)) q:fnum="" d . w StartRec . w Field_"Name"_ScalarStr_data("Friends",fnum,"Name") . w Field_"Age"_ScalarInt_data("Friends",fnum,"Age") . w EndRec w EndList [continued] Java output from this part: "Friends": [ { "Name": "Chad", "Age": 5 } , { "Name": "Ginger", "Age": 6 } ]

Page 12: Stored Procedures and  MUMPS for DivConq

Stored procedures will always return a record or a list. So the last “write”

command in a stored proc should always be EndRec or EndList – to match the

first write.

[continued] ; w EndRec ; quit Java output from this part: }

Page 13: Stored Procedures and  MUMPS for DivConq

Stored procedures are used by Java, but if you want to test your procedure in

MUMPS you may emulate a Java call. Bring up the MUMPS prompt, something

like above, and then call local^dcConn to run the procedure. When calling

procedures this way you’ll want to use “UPDATE” or “QUERY” – only use

“UPDATE” if the call will change data in the database.

$ sudo su gtmuser $ cd ~ $ ./gtmcon GTM>d local^dcConn("QUERY testProc1") Data: { , Name: Sally, Age: 5, Toys[ : Legos: Puzzle] , Friends[ { , Name: Chad, Age: 5} { , Name: Ginger, Age: 6} ] } ! Messages: [ ] !

Page 14: Stored Procedures and  MUMPS for DivConq

The results returned to Java from stored procedures are not in JSON format.

Likewise, when we run the procedure within MUMPS we aren’t getting pure JSON

but we do get something similar.

Once you get used to ", " preceding every field (e.g. “, Name” and ": " preceding

every scalar (e.g. “: Legos”) then it is not too bad to read.

{ , Name: Sally, Age: 5, Toys[ : Legos: Puzzle] , Friends[ { , Name: Chad, Age: 5} { , Name: Ginger, Age: 6} ] } !

Page 15: Stored Procedures and  MUMPS for DivConq

A quick look back at how to call from Java, note the “Query” in QueryRequest and

the use of the name “testProc1”. Also note no parameters are used.

QueryRequest tp1 = new QueryRequest("testProc1"); ObjectCallback callback = new ObjectCallback() { @Override public void process(ObjectResult res) { if (res.hasErrors()) { System.out.println(" Error:"); TestDb.printPretty(res.getMessages()); } else { System.out.println(" Response:"); TestDb.printPretty(res.getResult()); } } }; Hub.instance.getDatabase().submit(tp1, callback);

Page 16: Stored Procedures and  MUMPS for DivConq

Lets run the next test procedure, testProc2. This one will show us how to return

messages from a stored proc. Messages are not result data, but rather

information for tracing, info, warnings or errors. Only a few messages should be

returned from a procedure, do not try to return hundreds or more. Note you can

add a message anytime during the output generation – in the middle of a Field is

fine. Also we see how to pass Params from the M command line.

GTM>s Params(0)="gun" GTM>s Params(1)="candy" GTM>d local^dcConn("QUERY testProc2") Data: ! Messages: [ { , Level: Error, Code: 1, Message: Gun not allowed in toy list} { , Level: Error, Code: 1, Message: Candy not allowed in toy list} ] !

Page 17: Stored Procedures and  MUMPS for DivConq

We expect a list of toys for our parameters. A check with $d tells us if the list is

missing. If so, then we need to add an error message and quit the routine.

Calling errMsg or warnMsg in dcConn is one way to do this, we’ll see another way

soon. Note that it is ok to “quit” before any output if there is an error. In Java

always check for errors in the result (ObjectResult) before processing the data.

Ignore the result data if an error occurred.

testProc2 n tnum,toy ; ; validate your inputs, if toy list is not there do not continue i $d(Params)<10 d errMsg^dcConn("Missing toy list") quit ; ; continue input validation, check for undesirable toys f s tnum=$o(Params(tnum)) q:tnum="" d . s toy=Params(tnum) . s toy=$$toUpper^dcStrUtil(toy) . i toy["GUN" d errMsg^dcConn("Gun not allowed in toy list") q . i toy["CANDY" d errMsg^dcConn("Candy not allowed in toy list") q . i toy["HAMMER" d warnMsg^dcConn("A hammer may not be safe for this age") q

Page 18: Stored Procedures and  MUMPS for DivConq

Loop the list of toys in our parameters. Check if the toy matches some key word,

if so create an error and continue in the loop. Every toy that fails will generate a

message. This should be capped, do not return more than a hundred messages

this way.

testProc2 n tnum,toy ; ; validate your inputs, if toy list is not there do not continue i $d(Params)<10 d errMsg^dcConn("Missing toy list") quit ; ; continue input validation, check for undesirable toys f s tnum=$o(Params(tnum)) q:tnum="" d . s toy=Params(tnum) . s toy=$$toUpper^dcStrUtil(toy) . i toy["GUN" d errMsg^dcConn("Gun not allowed in toy list") q . i toy["CANDY" d errMsg^dcConn("Candy not allowed in toy list") q . i toy["HAMMER" d warnMsg^dcConn("A hammer may not be safe for this age") q

Page 19: Stored Procedures and  MUMPS for DivConq

Before we do the output, which just echoes the list back, first check for any error

messages. Remember the validation loops all toys and may generate one or

more warning or error. Doing “i Errors quit” ensures that we don’t bother with

output if an error was created in a previous step.

i Errors quit ; ; if only warnings or no validation messages then proceed w StartList f s tnum=$o(Params(tnum)) q:tnum="" d . s toy=Params(tnum) . s toy=$$toUpper^dcStrUtil(toy) . w ScalarStr_toy w EndList ; quit

Page 20: Stored Procedures and  MUMPS for DivConq

A glance back at calls from Java. Note passing the List of toys as parameters.

ListStruct toys = new ListStruct("gun", "candy"); QueryRequest tp2 = new QueryRequest("testProc2", toys); ... Submit ... // in your callback be sure to check for errors if (res.hasErrors()) { System.out.println(" Error:"); TestDb.printPretty(res.getMessages()); }

Page 21: Stored Procedures and  MUMPS for DivConq

Coding and Testing in MUMPS

Page 22: Stored Procedures and  MUMPS for DivConq

Above is a list of most the ScalarNNN types as they relate to the types in

Schema/Java. To refresh yourself on the data types, see the “Data Types in

DivConq” presentation.

DivConq Name MUMPS Write Type String ScalarStr Integer ScalarInt BigInteger ScalarBigInt Decimal ScalarDec BigDecimal ScalarBigDec Boolean ScalarFalse, ScalarTrue or ScalarBool_”true|false” Null ScalarNull Binary ScalarBin DateTime ScalarDateTime BigDateTime ScalarBigDateTime

Page 23: Stored Procedures and  MUMPS for DivConq

Lists in Java become numerical keys in MUMPS, starting at 0.

Java ListStruct toys = new ListStruct("gun", "candy");

// as used with QueryRequest tp2 = new QueryRequest("testProc2", toys);

MUMPS Params(0)="gun" Params(1)="candy"

Page 24: Stored Procedures and  MUMPS for DivConq

Records in Java become keyed by field name in MUMPS.

Java RecordStruct params = new RecordStruct( new FieldStruct("MinAge", 30), new FieldStruct("MaxAge", 48) );

MUMPS Params("MinAge")=30 Params("MaxAge")=48

Page 25: Stored Procedures and  MUMPS for DivConq

Lists of Records become numerical keys with field name sub-keys.

Java ListStruct toys = new ListStruct( new RecordStruct( new FieldStruct("Name", "Mike"), new FieldStruct("Age", 44) ), new RecordStruct( new FieldStruct("Name", "Mary"), new FieldStruct("Age", 38) ) );

MUMPS Params(0,"Name")="Mike" Params(0,"Age")=44 Params(1,"Name")="Mary" Params(1,"Age")=38

Page 26: Stored Procedures and  MUMPS for DivConq

Records with lists become field name keys with numerical sub-keys.

Java RecordStruct params = new RecordStruct( new FieldStruct("Name", "Mike"), new FieldStruct("Age", 14), new FieldStruct(“Toys", new ListStruct( "Bike", "Soccer Ball" ) ) );

MUMPS Params("Name")="Mike" Params("Age")=14 Params("Toys",0)="Bike" Params("Toys",1)="Soccer Ball"

Page 27: Stored Procedures and  MUMPS for DivConq

Java RecordStruct params = new RecordStruct( new FieldStruct("Name", "Mike Jr."), new FieldStruct("Age", 14), new FieldStruct("Dad", new RecordStruct( new FieldStruct("Name", "Mike Sr."), new FieldStruct("Age", 44) ) ) );

MUMPS Params("Name")="Mike Jr." Params("Age")=14 Params("Dad","Name")="Bike Sr." Params("Dad","Age")=44

Page 28: Stored Procedures and  MUMPS for DivConq

Java ListStruct params = new ListStruct( new ListStruct( "Bike", "Soccer Ball" ), new ListStruct( "Bat", "Soft Ball" ) );

MUMPS Params(0,0)="Bike" Params(0,1)="Soccer Ball" Params(1,0)="Bat" Params(1,1)="Soft Ball"

Page 29: Stored Procedures and  MUMPS for DivConq

MUMPS has some limits to how big your keys and your values can get, but within

reason you can send very complex JSON-Like structures. There is more than

just the examples above. You can have a list of records that have fields with lists

of records.

Params([numerical],[field name],[numerical],[field name])=NNN

Or any combination of lists and records as long as it follows MUMPS limitations

(or specifically GT.M’s limitations – though if you used DivConq with Cache you’d

have to watch the limitations for Cache).

Page 30: Stored Procedures and  MUMPS for DivConq

Globalizing in MUMPS

Page 31: Stored Procedures and  MUMPS for DivConq

The preferred way to send a message is to use a message code. Message

codes can be used to translate a message to the user’s locale. Note the calls to

“err” and “warn” in dcConn. Pass the code and, optionally, up to 6 parameters.

There is also an “info” and a “trace” function. For now you may use the 80,000 –

89,999 code range in your projects.

testProc3 n tnum,toy,utoy ; ; validate your inputs, if toy list is not there do not continue i $d(Params)<10 d err^dcConn(90000) quit ; ; continue input validation, check for undesirable toys f s tnum=$o(Params(tnum)) q:tnum="" d . s toy=Params(tnum) . s utoy=$$toUpper^dcStrUtil(toy) . i (utoy["GUN")!(utoy["CANDY") d err^dcConn(90001,toy) q . i utoy["HAMMER" d warn^dcConn(90002,toy) q ; i Errors quit ...

Page 32: Stored Procedures and  MUMPS for DivConq

Every DivConq package should have a dictionary file (or many). The name of the

file doesn’t matter, though we can see that one file in dcTest contains Pig Latin.

What does matter is that you have an entry for every code in every supported

language.

D:\dev\divconq\template\packages\dcTest\all\dictionary\dictionary.xml D:\dev\divconq\template\packages\dcTest\all\dictionary\x-pig-latin.xml

Page 33: Stored Procedures and  MUMPS for DivConq

The first file contains only English (see Id attribute of Locale element). In

testProc3 the call to “d err^dcConn(90000)” produces “Missing toy list” when

using the English locale.

The call to “d warn^dcConn(90002,toy)” on the other hand has a parameter, the

toy’s name. The first parameter replaces {$1} in the message, so for a Hammer

the message becomes “Toy may not be safe: Hammer”.

<Dictionary> <Locale Id="en"> <Entry Token="_code_90000" Value="Missing toy list" /> <Entry Token="_code_90001" Value="Toy not allowed: {$1}" /> <Entry Token="_code_90002" Value="Toy may not be safe: {$1}" /> <Entry Token="_code_90010" Value="Missing required fields" /> </Locale> </Dictionary>

Page 34: Stored Procedures and  MUMPS for DivConq

The second file contains only Pig Latin, though technically both translations could

be in the same file. The call to “d err^dcConn(90000)” produces “Issingmay oytay

istlay” when using the Pig Latin locale.

The call to “d warn^dcConn(90002,toy)” with a Hammer produces “Oytay aymay

otnay ebay afesay: Hammer”.

<Dictionary> <Locale Id="x-pig-latin"> <Entry Token="_code_90000" Value="Issingmay oytay istlay" /> <Entry Token="_code_90001" Value="Oytay otnay allowedway: {$1}" /> <Entry Token="_code_90002" Value="Oytay aymay otnay ebay afesay: {$1}" /> <Entry Token="_code_90010" Value="Issingmay equiredray ieldsfay" /> </Locale> </Dictionary>

Page 35: Stored Procedures and  MUMPS for DivConq

We now have a better idea of how to pass data to a stored procedure and how to

return data from a stored procedure. We also learned that we can pass status or

debugging messages from our stored procedure – and that those messages can

be localized.