<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DivConq Framework</title>
	<atom:link href="http://www.divconq.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.divconq.com</link>
	<description>Next Generation MUMPS + Java Application Framework</description>
	<lastBuildDate>Mon, 20 Feb 2012 14:56:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Content Management System</title>
		<link>http://www.divconq.com/2012/content-management-system/</link>
		<comments>http://www.divconq.com/2012/content-management-system/#comments</comments>
		<pubDate>Mon, 20 Feb 2012 14:56:47 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=688</guid>
		<description><![CDATA[Progress on DivConq Framework 0.5 is still being made. We are currently building a CMS on the DivConq Framework which is needed by one of our partner projects. The CMS will also be open source and available for download at this site. Building an application using DivConq also helps serve as a sanity check for [...]]]></description>
			<content:encoded><![CDATA[<p>Progress on DivConq Framework 0.5 is still being made.  We are currently building a CMS on the DivConq Framework which is needed by one of our partner projects.  The CMS will also be open source and available for download at this site.  Building an application using DivConq also helps serve as a sanity check for the Framework design, so although it may slow progress a little it will help mature the Framework.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2012%2Fcontent-management-system%2F&amp;title=Content%20Management%20System" id="wpa2a_2"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2012/content-management-system/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Date Time Plans</title>
		<link>http://www.divconq.com/2012/date-time-plans/</link>
		<comments>http://www.divconq.com/2012/date-time-plans/#comments</comments>
		<pubDate>Mon, 06 Feb 2012 16:02:26 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=682</guid>
		<description><![CDATA[Neither the MUMPS standard, nor the GT.M implementation, come with much date time support. Even if it did it would differ from Java&#8217;s support and from the various Javascript libraries out there. For DivConq we want to provide consistent date time formatting and parsing for MUMPS (your stored procedures and queries), for Java (your business [...]]]></description>
			<content:encoded><![CDATA[<p>Neither the MUMPS standard, nor the GT.M implementation, come with much date time support.  Even if it did it would differ from Java&#8217;s support and from the various Javascript libraries out there.  For DivConq we want to provide consistent date time formatting and parsing for MUMPS (your stored procedures and queries), for Java (your business logic and EDI) and for Javascript (your web UI).  Further, as already mentioned elsewhere, we support the BigDateTime data type for dates from -50 billion to +50 billion years.  </p>
<p>Our date time formatting support starts within MUMPS.  Recent releases of DivConq have considerable support for querying the database, but date time is always returned in the internal format (ISO 8601) or in the internal BigDateTime format &#8211; and also always store times using the UTC timezone.  In DivConq every request to the database silently carries the current task&#8217;s (user&#8217;s) timezone (chronology) and locale.  Therefore we have the info we need format a date time within MUMPS.  Our current work is to code support for chronologies and timezones.</p>
<p><span id="more-682"></span></p>
<p>By chronology we mean Gregorian calendar, Julian calendar, Mayan calendar and such.  For starters we are supporting the ISO (proleptic Gregorian) calendar.  It is easy to calculate because it has a year 0 and follows the Gregorian rules back into time indefinitely.  We plan to add support for some additional calendars plus add the hooks for developers to drop in support for their own custom calendars.  And we plan to expand customizable calendar support to Java and Javascript.  Until we do, we suggest using the Joda Time library as it is generally supported in DivConq as an alternative to BigDateTime.  </p>
<p>Beyond picking the calendar, the chronology contains additional details such as timezone.  The  support we are adding for ISO (proleptic Gregorian) calendar includes support for timezones.  In general the approach should work for any timezone, but our initial tests are focused on USA 2007 timezone rules.  Since all dates in dcTables are stored as UTC, it makes formatting easier &#8211; there are no DST rules for UTC.</p>
<p>The next release of DivConq will support a minimal set of locale based date time and number formatting options.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2012%2Fdate-time-plans%2F&amp;title=Date%20Time%20Plans" id="wpa2a_4"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2012/date-time-plans/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stored Procedures and MUMPS</title>
		<link>http://www.divconq.com/2012/stored-procedures-and-mumps/</link>
		<comments>http://www.divconq.com/2012/stored-procedures-and-mumps/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 02:05:26 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=678</guid>
		<description><![CDATA[DivConq has just released an presentation delving into details of Stored Procedure development within DivConq Framework. This includes examples on how to pass data to a stored procedure and how to return data from a stored procedure. It further includes how to pass status or debugging messages from stored procedure, including message localization. Download : [...]]]></description>
			<content:encoded><![CDATA[<p>DivConq has just released an presentation delving into details of Stored Procedure development within DivConq Framework.  This includes examples on how to pass data to a stored procedure and how to return data from a stored procedure.  It further includes how to pass status or debugging messages from stored procedure, including message localization.</p>
<p>Download : <a target="_BLANK" href="https://s3.amazonaws.com/divconqframework/docs/dcDB+Stored+Procedures+2.pdf">Download PDF</a> or <a target="_BLANK" href="http://www.slideshare.net/etimeline/stored-procedures-and-mumps-for-divconq">View on SlideShare</a>.</p>
<p>The presentation covers:<br />
 1) Java Struct Parameters to MUMPS structure conversions<br />
 2) returning JSON-Like data structures<br />
 3) Error messages<br />
 4) Localized messages</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2012%2Fstored-procedures-and-mumps%2F&amp;title=Stored%20Procedures%20and%20MUMPS" id="wpa2a_6"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2012/stored-procedures-and-mumps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Data Structures in DivConq</title>
		<link>http://www.divconq.com/2012/data-structures-overview/</link>
		<comments>http://www.divconq.com/2012/data-structures-overview/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 23:49:47 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[DivConq]]></category>
		<category><![CDATA[Elastic Architecture]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[MUMPS]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=672</guid>
		<description><![CDATA[DivConq has just released an introductory presentation covering the JSON-Like data structures used within DivConq Framework. Download PDF or View on SlideShare. The presentation covers: 1) JSON Compatibility 2) Creating data structures 3) Accessing data structures 4) Use of dcSchema for data validation]]></description>
			<content:encoded><![CDATA[<p>DivConq has just released an introductory presentation covering the JSON-Like data structures used within DivConq Framework.</p>
<p><a target="_BLANK" href="https://s3.amazonaws.com/divconqframework/docs/Data+Types.pdf">Download PDF</a> or <a target="_BLANK"  href="http://www.slideshare.net/etimeline/data-typesstructures-in-divconq">View on SlideShare</a>.</p>
<p>The presentation covers:<br />
1) JSON Compatibility<br />
2) Creating data structures<br />
3) Accessing data structures<br />
4) Use of dcSchema for data validation</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2012%2Fdata-structures-overview%2F&amp;title=Data%20Structures%20in%20DivConq" id="wpa2a_8"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2012/data-structures-overview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stored Procedure Overview</title>
		<link>http://www.divconq.com/2012/stored-procedure-overview/</link>
		<comments>http://www.divconq.com/2012/stored-procedure-overview/#comments</comments>
		<pubDate>Wed, 18 Jan 2012 23:15:02 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[DivConq]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[MUMPS]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=666</guid>
		<description><![CDATA[DivConq has just released an introductory presentation on Stored Procedure use within DivConq Framework. Download Power Point or View on SlideShare. The presentation covers: 1) how DivConq connects to MUMPS 2) how to create a request 3) the request-response flow 4) Java example code 5) schema example declaration 6) MUMPS example code 7) JSON and [...]]]></description>
			<content:encoded><![CDATA[<p>DivConq has just released an introductory presentation on Stored Procedure use within DivConq Framework.</p>
<p><a href="https://s3.amazonaws.com/divconqframework/docs/dcDB+Stored+Procedures.pptx">Download Power Point</a> or <a href="http://www.slideshare.net/etimeline/dcdb-overview-of-stored-procedures">View on SlideShare</a>.</p>
<p>The presentation covers:</p>
<p>1) how DivConq connects to MUMPS<br />
2) how to create a request<br />
3) the request-response flow<br />
4) Java example code<br />
5) schema example declaration<br />
6) MUMPS example code<br />
7) JSON and interoperability</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2012%2Fstored-procedure-overview%2F&amp;title=Stored%20Procedure%20Overview" id="wpa2a_10"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2012/stored-procedure-overview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DivConq Framework 0.4.8 Released</title>
		<link>http://www.divconq.com/2012/divconq-framework-0-4-8-released/</link>
		<comments>http://www.divconq.com/2012/divconq-framework-0-4-8-released/#comments</comments>
		<pubDate>Tue, 17 Jan 2012 22:30:43 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=656</guid>
		<description><![CDATA[This week we released version 0.4.8 of our DivConq Framework. This release extends the capabilities of our dcTables feature. Download. Our open-source DivConq Framework brings a sophisticated but accessible Java library to MUMPS developers with the intention of getting the most out of the pairing. In version 0.4.5 we supplemented our powerful stored procedures feature [...]]]></description>
			<content:encoded><![CDATA[<p>This week we released version 0.4.8 of our DivConq Framework.   This release extends the capabilities of our dcTables feature. <a href="https://s3.amazonaws.com/divconqframework/release/divconq-0.4.8.zip">Download</a>.</p>
<p>Our open-source DivConq Framework brings a sophisticated but accessible Java library to MUMPS developers with the intention of getting the most out of the pairing.  In version 0.4.5 we supplemented our powerful stored procedures feature with dcTables, a feature that aims to provide the rapid development ideal of relational databases to MUMPS.  With version 0.4.8 we round out dcTables by adding support for a SELECT like command.  dcTables already supported commands similar to INSERT, UPDATE and DELETE.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2012%2Fdivconq-framework-0-4-8-released%2F&amp;title=DivConq%20Framework%200.4.8%20Released" id="wpa2a_12"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2012/divconq-framework-0-4-8-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introduction to Stored Procedures Part Two</title>
		<link>http://www.divconq.com/2011/intro-to-stored-procedures-part-two/</link>
		<comments>http://www.divconq.com/2011/intro-to-stored-procedures-part-two/#comments</comments>
		<pubDate>Fri, 30 Dec 2011 23:45:59 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[DivConq]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[MUMPS]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=582</guid>
		<description><![CDATA[In Part One of this series we got to see some simple examples of M code being used as Stored Procedures from Java. We saw that how Stored Procedures are named and how to use the name to call it from Java or from the M command prompt. Part two will cover a deeper example [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="2011/intro-to-stored-procedures-part-one">Part One</a> of this series we got to see some simple examples of M code being used as Stored Procedures from Java.  We saw that how Stored Procedures are named and how to use the name to call it from Java or from the M command prompt.</p>
<p>Part two will cover a deeper example that involves storing and reading data in a M Global &#8211; similar to how you may end up using the Stored Procedures feature your applications.  In the process we&#8217;ll cover in more detail how to write the M code, how to declare the procedure in dcSchema, how to call from Java and how to process the return values.</p>
<p><span id="more-582"></span></p>
<p>View the M routine dctToyTest.m.  Most of the code is for Stored Procedure calls, but at the top are &#8220;setup&#8221; and &#8220;cleanup&#8221; functions.  This example needs setup, so before we go any further lets run that from the M prompt.</p>
<pre class="brush:js">
GTM>d setup^dctToyTest

GTM>
</pre>
<p>Verify that the global has been loaded, compare the code in the &#8220;setup&#8221; function with what you see in the global:</p>
<pre class="brush:js">
GTM>zwr ^dctData
^dctData("People",10000,"Age")=8
^dctData("People",10000,"Friends",1)=10001
^dctData("People",10000,"Friends",2)=10002
^dctData("People",10000,"Name")="Sally"
^dctData("People",10000,"Toys",1)="Legos"
^dctData("People",10000,"Toys",2)="Puzzle"
...

GTM>
</pre>
<p>There are now 6 people in our database.  In addition to the records in ^dctData, there is also a ^dtcIndex which holds the indexes for the Toys and Friends fields.   Sally, the example record above, has 2 friends and 2 toys.  The indexes for her fields look like this:</p>
<pre class="brush:js">
^dctIndex("Friends",10001,10000)=1
^dctIndex("Friends",10002,10000)=1
^dctIndex("Toys","Legos",10000)=1
^dctIndex("Toys","Puzzle",10000)=1
</pre>
<p>The test data and index globals are not well designed, so the point here is just to see how the example works &#8211; not to mimic the design.  When we look at the dcTables feature later the we&#8217;ll discuss design goals.  That said, what we see here is that if we have a person id such as 1002 (Ginger) we can easily find who has friended that person.  By looping the index &#8211; s friend=$o(^dctIndex(&#8220;Friends&#8221;,10002,friend)) &#8211; we can find all those people.  Conversely, the people Ginger has friended will be in ^dctData(&#8220;People&#8221;,10000,&#8221;Friends&#8221;,n)=Friend Id.</p>
<p>Likewise we can find all the people who like a particular toy by looping, for example who likes Legos: s person=$o(^dctIndex(&#8220;Toys&#8221;,&#8221;Legos&#8221;,person)).  If these concepts don&#8217;t make sense you need to resume review MUMPS data structures.</p>
<p>Lets delve into the first Stored Procedure, it just returns a list (JSON Array) of names (strings).  All 6 people are listed:</p>
<pre class="brush:js">
GTM>d local^dcConn("QUERY dctListPeople")

Data:
:[ : Sally: Chad: Ginger: Kyle: Betty: Mike] !
Messages:
:[ ] !
GTM>
</pre>
<p>Recall that we find the M routine name in the ^Proc global.</p>
<pre class="brush:js">
GTM>zwr ^Proc
...
^Proc("dctListPeople")="listPeople^dctToyTest"
...

GTM>
</pre>
<p>So we should look at the &#8220;listPeople&#8221; function in &#8220;dctToyTest&#8221;.  The first few lines handle parameters passed to the stored procedure.  Parameters will (typically) be provided to procedures via the local variable &#8220;Params&#8221;.  Parameters can be complex M structures, but typically they are just key and value pairs such as MinAge and MaxAge.  When these parameters are present they limit the list of names returned so that only people within the range appear.</p>
<pre class="brush:js">
listPeople n id,minage,maxage
 s minage=Params("MinAge"),maxage=Params("MaxAge")
 s:minage="" minage=0
 s:maxage="" maxage=200
</pre>
<p>Note that if the parameter keys are not present we default to a value.  Another option would be to log an error and return &#8211; something like this:  <i>i minage=&#8221;" d err^dcConn(90010) quit</i>.  We&#8217;ll cover error handling in a future part of this series.  But it is useful to know these rules:  </p>
<p>a) You do not have to return any data at all from a stored proc<br />
b) If you find that something expected is missing (parameters, data) then you may log and error or warning, that message will be presented to the calling code (Java or M)<br />
c) If no error or warning is logged then the procedure is assumed to have run correctly even if no data was returned<br />
d) It is good practice to check for errors before returning any data, as much as possible<br />
e) When you do want to return data from a procedure you must return it either in a List or a Record.  Your structures must be well formed and syntactically correct.</p>
<p>Lists and Records have a definite start and end, and you must make sure they are well formed (there is always an end for every start).</p>
<pre class="brush:js">
 w StartList		; start list of people
 ;
 f  s id=$o(^dctData("People",id)) q:id=""  d
 . i (^dctData("People",id,"Age")&lt;minage)!(^dctData("People",id,"Age")>maxage) q
 . ;
 . w ScalarStr_^dctData("People",id,"Name")
 ;
 w EndList		; end list of people
 ;
 quit
</pre>
<p>The start and end of the list is fairly obvious.  Also by now the &#8220;for&#8221; loop should make sense.  Inside the loop we first check to see if the person&#8217;s age is less than or greater than the age range provided to the procedure.  If it is in the correct range we go to the next lines and write out the name.</p>
<p>Note that every item in a list must be preceded with a &#8220;Scalar&#8221;.  Typically the Scalar is a &#8220;ScalarStr&#8221; if the following value is a string, &#8220;ScalarInt&#8221; if the following value is an integer or &#8220;ScalarDec&#8221; if the following value is a decimal.</p>
<p>Procedures may return complex data structures &#8211; Records in Lists, Lists in Lists, Records in Fields and Lists in Fields.  Very much like JSON does.  Consider the procedure &#8220;dctGetPeople&#8221; which links us to the &#8220;getPeople&#8221; function in &#8220;dctToyTest&#8221;.  Here is a description of the return value for this procedure:</p>
<pre class="brush:js">
 [
     {
        "Id": |int, person id|,
        "Name": |string, person name|,
        "Age": |int, person age|,
        "Toys": [
	        |string, toy name|
        ],
        "Friends": [
            {
                "Name": |string, person name|,
                "Age": |int, person age|
            }
        ],
        "FriendedBy": [
            {
                "Name": |string, person name|,
                "Age": |int, person age|
            }
        ]
     }
 ]
</pre>
<p>We see that Friends are records inside of a list, the list is inside a field, the field is in a record, the record is in a list.  A complex structure, but not too hard to code in M.  Run it just for kicks:</p>
<pre class="brush:js">
GTM>d local^dcConn("QUERY dctGetPeople")

Data:
:[ :{ , Id: 10000, Name: Sally, Age: 8, Toys:[ : Legos: Puzzle] , Friends:[ :{ ,
 Name: Chad, Age: 8} :{ , Name: Ginger, Age: 9} ] , FriendedBy:[ :{ , Name: Chad
, Age: 8} ] } :{ , Id: 10001, Name: Chad, Age: 8, Toys:[ : Kite: Playdough] , Fr
iends:[ :{ , Name: Sally, Age: 8} :{ , Name: Ginger, Age: 9} ] , FriendedBy:[ :{
 , Name: Sally, Age: 8} ] } :{ , Id: 10002, Name: Ginger, Age: 9, Toys:[ : Bike:
 Softball] , Friends:[ :{ , Name: Kyle, Age: 10} :{ , Name: Mike, Age: 9} ] , Fr
iendedBy:[ :{ , Name: Sally, Age: 8} :{ , Name: Chad, Age: 8} :{ , Name: Betty,
Age: 9} ] } :{ , Id: 10003, Name: Kyle, Age: 10, Toys:[ : Softball Bat] , Friend
s:[ ] , FriendedBy:[ :{ , Name: Ginger, Age: 9} :{ , Name: Mike, Age: 9} ] } :{
, Id: 10004, Name: Betty, Age: 9, Toys:[ : Jump Rope: Softball Glove] , Friends:
[ :{ , Name: Ginger, Age: 9} :{ , Name: Mike, Age: 9} ] , FriendedBy:[ :{ , Name
: Ginger, Age: 9} ] } :{ , Id: 10005, Name: Mike, Age: 9, Toys:[ : Frisbee] , Fr
iends:[ :{ , Name: Kyle, Age: 10} ] , FriendedBy:[ :{ , Name: Ginger, Age: 9} :{
 , Name: Betty, Age: 9} ] } ] !
Messages:
:[ ] !
GTM>
</pre>
<p>Procedures do not have to have any parameters, consider the first lines of &#8220;getPeople&#8221;.</p>
<pre class="brush:js">
getPeople n id,tnum,fnum,fid
 w StartList		; start list of people
 ;
</pre>
<p>We jump right into writing out a list.  And at the end we be sure to end our list:</p>
<pre class="brush:js">
 ;
 w EndList		; end list of people
 ;
 quit
</pre>
<p>The rest should fairly easily to comprehend, just do loops within loops to get at all the data you want.  We do use the index global here, lets peek at that code (which is already in a loop on the records):</p>
<pre class="brush:js">
 . w Field_"FriendedBy"_StartList	; friended by list
 . f  s fnum=$o(^dctIndex("Friends",id,fnum)) q:fnum=""  d
 . . w StartRec	; friend info
 . . w Field_"Name"_ScalarStr_^dctData("People",fnum,"Name")
 . . w Field_"Age"_ScalarInt_^dctData("People",fnum,"Age")
 . . w EndRec	; friend info
 . w EndList					; end friended by list
</pre>
<p>Note the Start and End list for the friended by field.  We just loop through the index and write out a small record (inside the List) for each friended by entry.</p>
<p>Lets run this via the Java Connector.  Run testdb again, as you did in the <a href="2011/getting-connected-with-divconq/">Getting Connected post</a>.</p>
<pre class="brush:js">
D:\dev\divconq\template>.\bin\run.bat testdb

...
option 8
...

-----------------------------------------------
   Toy Database Menu
-----------------------------------------------
0)  Main Menu
1)  List People Names
2)  List Toys
3)  List People in Tabular
4)  List People in Complex
5)  List People directly to file (Json)
6)  List People directly to file (Yaml)
7)  Add Person
1
MinAge filter [empty for no filter]: 5
MaxAge filter [empty for no filter]: 8

dctListPeople Response:
 [
        "Sally",
        "Chad"
 ]
</pre>
<p>And now for the more complex example, run option 4 and see the data coming back from the procedure formatted in JSON.</p>
<p>As mentioned earlier, Java calls the procedure names &#8220;dctListToys&#8221; and &#8220;dctGetPeople&#8221;.  We know that the ^Proc global holds the mapping for the procedure name to the function name in M.  But who sets up the mapping?</p>
<p>The answer is &#8211; the developer does.  And so this brings us to a whole new topic in DivConq, Packages.  Applications written using DivConq as assembled by combining Packages.  Each Package contains Java and/or M code and adds some functionality to the overall application.</p>
<p>In a sense a Package is like an &#8220;add-on&#8221; only the whole application is composed of &#8220;add-ons&#8221;, separate units of functionality that may be installed or not.  If you are familiar with OSGi then a package is somewhat similar in concept (we don&#8217;t use separation via class-loaders yet though, lets see what Java 8 brings).  Also, to some extent, a WAR file is similar to a Package.</p>
<p>In any event, there is 1 core Package which all applications must have &#8211; it is &#8220;dcCore&#8221;.  Combine this with your own Package &#8220;myApp&#8221; and you have all you need to make a distribution of your application.  But if you choose to allow it, your customers may drop in other packages (their own customizations or third-party) on top of your install to add more functionality.</p>
<p>One of the great things about DivConq is that the contents of one package may override the contents of another package.  Thus, if a customer dislikes images or locale translations or whatever in your application, it is fairly easy to create an override and put it in another package.  This keeps their stuff separate from your distribution, and it also makes it very easy to identify the overrides during an update.  You update installer can say to the user &#8220;we see you overrode X, but we changed X since your last install.&#8221;  It takes work to setup that up in your installer, but the effort in checking for overrides is minimal once you know what you want to provides hints on.</p>
<p>This brings us to the &#8220;dcTest&#8221; package.  This package would not be distributed with your application, it is just here to provide examples to developers learning DivConq.  So &#8220;dcTest&#8221; keeps &#8220;dcCore&#8221; clean by keeping almost all the example files separate.</p>
<p>Look at your copy of the dcTest package in the Template folder: &#8220;template/packages/dcTest&#8221;.  In here is the &#8220;package.xml&#8221; file that describes the package &#8211; more on that later.  There is also an &#8220;m&#8221; folder that contains the M routines that dcTest relies on.  Now look in &#8220;all/schema&#8221; to find the schema declarations.</p>
<p>Open the schema file and look for a Procedure element with Name=&#8221;dctListPeople&#8221;.  Here is what that looks like:</p>
<pre class="brush:js">
&lt;Procedure Name=&quot;dctListPeople&quot; Execute=&quot;listPeople^dctToyTest&quot;&gt;
	&lt;Description&gt;
		Get a list of names of all people in test data.
		Optionally add in an age range filter
	&lt;/Description&gt;
	&lt;RecRequest&gt;
		&lt;Field Name=&quot;MinAge&quot; Type=&quot;Integer&quot; /&gt;
		&lt;Field Name=&quot;MaxAge&quot; Type=&quot;Integer&quot; /&gt;
	&lt;/RecRequest&gt;
	&lt;ListResponse Type=&quot;String&quot; /&gt;
&lt;/Procedure&gt;
</pre>
<p>Every stored procedure in DivConq needs a definition like this.  The definition will be in a schema file within the Package you are developing.  For example, if you are coding some Divconq tests in template then you&#8217;d probably be editing the schema file &#8220;template/packages/dctTemplate/all/schema/schema.xml&#8221;.</p>
<p>Stored procedures need definitions so that Java can determine that it is calling with the right parameters and that the correct data structure is being returned by the procedure.  You can see in the Execute attribute how the name gets mapped to the M function.  </p>
<p>Recall when you did &#8220;run.bat sync&#8221; and updated the M globals (option 2).  The sync utility copies information about the stored procedures to M.  So first you edit the schema, then you run sync, then you may call your procedure.</p>
<p>A future post will expand on how to make schema definitions, but for now look just at how we declare the request:</p>
<pre class="brush:js">
	&lt;RecRequest&gt;
		&lt;Field Name=&quot;MinAge&quot; Type=&quot;Integer&quot; /&gt;
		&lt;Field Name=&quot;MaxAge&quot; Type=&quot;Integer&quot; /&gt;
	&lt;/RecRequest&gt;
</pre>
<p>RecRequest means we will pass in a Record (not a List) and that we&#8217;ll have MinAge and MaxAge as possible fields.  So within M the Params(&#8220;MinAge&#8221;) looks like key value, but within Java/dcSchema we think of that as a record with fields.  There is no Required=&#8221;True&#8221; with these fields, as such they may be absent from the call in Java.</p>
<p>And look at how we declare the response:</p>
<pre class="brush:js">
	&lt;ListResponse Type=&quot;String&quot; /&gt;
</pre>
<p>ListResponse (not RecResponse) means we expect a list &#8211; the Type attribute tells use it will be a list of String.  Each String is a single name, of course.</p>
<p>This brings us to the final example in this part of the Stored Procedure series, a call in Java.</p>
<pre class="brush:js">
RecordStruct ages = new RecordStruct();
ages.setField("MinAge", 3);
ages.setField("MaxAge", 8);

QueryRequest lpr = new QueryRequest("dctListPeople", ages);
</pre>
<p>Although we have not yet covered RecordStruct, you can probably guess that this is what we mean when we declare the parameter as being a &#8220;RecRequest&#8221; &#8211; a record.  Yes, a record with 2 fields just as declared in dcSchema.  The parameter is passed into the QueryRequest object, along with the procedure name, and we have all that we need to make a call to the database.</p>
<p>We&#8217;ll cover more about database calls in the next part.  Along with that we&#8217;ll cover error handling in stored procedures (including localization) and review a stored procedure for updating globals.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2011%2Fintro-to-stored-procedures-part-two%2F&amp;title=Introduction%20to%20Stored%20Procedures%20Part%20Two" id="wpa2a_14"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2011/intro-to-stored-procedures-part-two/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DivConq Framework 0.4.5 Released</title>
		<link>http://www.divconq.com/2011/divconq-framework-0-4-5-released/</link>
		<comments>http://www.divconq.com/2011/divconq-framework-0-4-5-released/#comments</comments>
		<pubDate>Fri, 30 Dec 2011 18:30:30 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[DivConq]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[MUMPS]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=572</guid>
		<description><![CDATA[Today we released DivConq Framework 0.4.5 to introduce &#8220;dcTables&#8221; a new feature which supplements the benefits of stored procedures. Download. As you know, the main purpose of our open-source DivConq Framework is to let Java developers quickly harness the power of MUMPS-compatible &#8220;NoSQL&#8221; databases. To fully harness that power you need to code stored procedures [...]]]></description>
			<content:encoded><![CDATA[<p>Today we released DivConq Framework 0.4.5 to introduce &#8220;dcTables&#8221; a new feature which supplements the benefits of stored procedures.  <a href="https://s3.amazonaws.com/divconqframework/release/divconq-0.4.5.zip">Download</a>.</p>
<p>As you know, the main purpose of our open-source DivConq Framework is to let Java developers quickly harness the power of MUMPS-compatible &#8220;NoSQL&#8221; databases.  To fully harness that power you need to code stored procedures in MUMPS.  But sometimes you just need something *like* a relational table, and why should you have to code that?</p>
<p>At DivConq we say you can have your cake and eat it too.  With dcDb you get the power, flexibility and speed of NoSQL when coding stored procedures in MUMPS.  But, with dcTables you get the rapid development and ease of use of relational databases too.  Furthermore, all your data &#8211; dcDb and dcTables &#8211; can reside in one database.  Easy to administer (setup, backup and restore) and very helpful for developers.  Your stored procedures can access not only your NoSQL (dcDb) data but also your dcTables data &#8211; all in the same routine using only standard MUMPS commands.  For those occasions when data in NoSQL refers to data dcTables (or vice versa) nothing beats the convenience and speed of having all your data in one place.</p>
<p><span id="more-572"></span></p>
<p>dcTables provides Tables with Fields (columns) and Records (rows).  There are methods to Insert, Update, Retire (delete), Revive (undelete) and Load records.  There also also methods for loading lots of records, including a simple paging mechanism so you get only the subset of your query that you need for display.  There are Select, Where and Order clauses &#8211; like SQL.</p>
<p>While there is a lot to like in dcTables if you know SQL, we developed dcTables to be best of breed and not a mere clone.  There are differences, and mostly for the better, though every design has trade offs.  Some key differences include multi-valued fields (columns), replication (eventually consistent) friendly design, and inherent data over time orientation.</p>
<p>It seems intuitive to say that data changes over time, for example a person&#8217;s name may change overtime.  When querying a dcTable you provide a date and you get back the value(s) for that time &#8211; for 1980 you might get &#8220;Fred Smith&#8221; and for 1997 you might get &#8220;Fred Hanson&#8221; for the same record.  The time orientation of data is entrenched within dcTables and encourages developers to associate data with the time period that the data is valid.</p>
<p>Further, dcTables are replication ready &#8211; once DivConq enables the active-active database replication feature all the data in your dcTables (as well as the operations we provide) will be ready for the migration to a replicated deployment.</p>
<p>Our MUMPS connection manager has also gotten a connectivity and threading face lift which should provide more reliable and efficient use of connections.  Look for additional posts about the new features of dcDb and dcTables.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2011%2Fdivconq-framework-0-4-5-released%2F&amp;title=DivConq%20Framework%200.4.5%20Released" id="wpa2a_16"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2011/divconq-framework-0-4-5-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Speeding up SSH Login</title>
		<link>http://www.divconq.com/2011/speeding-up-ssh-login/</link>
		<comments>http://www.divconq.com/2011/speeding-up-ssh-login/#comments</comments>
		<pubDate>Mon, 19 Dec 2011 15:38:22 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=564</guid>
		<description><![CDATA[Anyone who has tried connecting to M using the DivConq Database Connector may have noticed a long wait (5+ seconds) during the initial connection. This is caused the SSH protocol and configuration. If you are a developer you probably hate waiting for this delay each time you run debug. There is a way to reduce [...]]]></description>
			<content:encoded><![CDATA[<p>Anyone who has tried connecting to M using the DivConq Database Connector may have noticed a long wait (5+ seconds) during the initial connection.  This is caused the SSH protocol and configuration.  If you are a developer you probably hate waiting for this delay each time you run debug.  There is a way to reduce that delay by disabling DNS in your server&#8217;s SSH config.  All this does is stop the SSH server from doing a reverse lookup on your ip address for logging.  So if you don&#8217;t care about that then try this config tip.  </p>
<p>Edit /etc/ssh/sshd_config on the server and add (or replace) the DNS option so it looks like &#8220;UseDNS no&#8221;.  Restart the SSH daemon with &#8220;service ssh restart&#8221; or equivalent.  If your problems stem from DNS then your login time should go down considerably.  If that doesn&#8217;t help check out the <a href="http://www.openssh.org/faq.html#3.3">SSH FAQ</a>.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2011%2Fspeeding-up-ssh-login%2F&amp;title=Speeding%20up%20SSH%20Login" id="wpa2a_18"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2011/speeding-up-ssh-login/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introduction to M (MUMPS) Part 4</title>
		<link>http://www.divconq.com/2011/intro-m-part-4/</link>
		<comments>http://www.divconq.com/2011/intro-m-part-4/#comments</comments>
		<pubDate>Sun, 18 Dec 2011 22:16:27 +0000</pubDate>
		<dc:creator>Andy_White</dc:creator>
				<category><![CDATA[Framework]]></category>
		<category><![CDATA[MUMPS]]></category>

		<guid isPermaLink="false">http://www.divconq.com/?p=533</guid>
		<description><![CDATA[In part one of this series I presented a summary of how the DivConq database connector for M (MUMPS) will work. Then we covered how to install M (GT.M software) and how to get to the M prompt. In part two of this series I presented a review of the basics of the M programming [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="/2011/intro-m-part-1/">part one of this series</a> I presented a summary of how the DivConq database connector for M (MUMPS) will work.  Then we covered how to install M (GT.M software) and how to get to the M prompt.</p>
<p>In <a href="/2011/intro-m-part-2/">part two of this series</a> I presented a review of the basics of the M programming language.</p>
<p>In <a href="/2011/intro-m-part-3/">part three of this series</a> we examined how data is persisted in M why the M programming language is well suited to data access.</p>
<p>In this fourth and final part we&#8217;ll finish up some of finer points of M.</p>
<p><span id="more-533"></span></p>
<p>To get started you&#8217;ll want two SSH sessions.  Login as a admin user (e.g. ec2-user).  One of those sessions will be to the M command prompt so get to the gtmuser&#8217;s M prompt:</p>
<pre class="brush:js">
$ sudo su gtmuser

$ cd ~

$ ./gtmcon
</pre>
<p>The other SSH session will be used for editing M routines.  So get to the gtmuser&#8217;s shell prompt in the routines directory:</p>
<pre class="brush:js">
$ sudo su gtmuser

$ cd ~/.fis-gtm/r/
</pre>
<p>Lets build a little program that makes a pyramid (turned on its side) in console output.  We can pass in the tallest point (e.g. 4) and it will build the graphic for us.  For kicks lets solve it with recursion since you may have wondered if M supports recursion (being ancient and all), well it does.  So this is our expected run and output:</p>
<pre class="brush:js">
GTM>zl "intro1"

GTM>d pyr^intro1(4)
*
**
***
****
***
**
*
</pre>
<p>Following is a working example of how to code a solution &#8211; but this code is a little less than desirable.  Here is the whole code:</p>
<pre class="brush:js">
intro1 ;
 ;
pyr(max) s lvl=1 d pyrr quit
 ;
pyrr ;
 f i=1:1:lvl w "*"
 w !
 q:lvl=max
 s lvl=lvl+1
 d pyrr
 s lvl=lvl-1
 f i=1:1:lvl w "*"
 w !
 ;
 quit
</pre>
<p>First, why does this work at all?  The reason for that is we don&#8217;t give our variables (max and lvl) a scope.  Without a scope they are &#8220;global&#8221; to that process.  What I don&#8217;t like about that code is in these three lines: </p>
<pre class="brush:js">
 s lvl=lvl+1
 d pyrr
 s lvl=lvl-1
</pre>
<p>It works because when we call pyrr recursively the lvl is 1 greater than the last call.  But lvl is not a local variable.  To give our code better encapsulation, we should generally use only variables that are local to our function.  A step in that direction is to change the way pyrr is called.  Look at the two places &#8220;pyrr&#8221; is called below:</p>
<pre class="brush:js">
pyr(max) d pyrr(1) quit
 ;
pyrr(lvl) ;
 f i=1:1:lvl w "*"
 w !
 q:lvl=max
 d pyrr(lvl+1)
 f i=1:1:lvl w "*"
 w !
 ;
 quit
</pre>
<p>Making &#8220;lvl&#8221; an argument effectively makes that variable local to the function.  But it is a mistake to think that our problem is completely solved.</p>
<p>Lets say we want our bricks to alternate between &#8220;*&#8221; and &#8220;+&#8221; for each line.  A failed first attempt follows:</p>
<pre class="brush:js">
intro1 ;
 ;
pyr(max) d pyrr(1) quit
 ;
pyrr(lvl) ;
 d chooseBrick
 ;
 f i=1:1:lvl w brick
 w !
 q:lvl=max
 d pyrr(lvl+1)
 f i=1:1:lvl w brick
 w !
 ;
 quit
 ;
 ;
chooseBrick i lvl#2=0 s brick="+"
 e  s brick="*"
 quit
</pre>
<p>Note that in &#8220;chooseBrick&#8221; we use the variable &#8220;lvl&#8221; even though it is not an argument.  This is because anytime you call a method in M the variable scope stays the same &#8211; unless you explicitly change the scope for selected variable names.  Run that code and see that &#8220;lvl&#8221; works in chooseBrick.  But we aren&#8217;t getting the result we hoped for.</p>
<pre class="brush:js">
GTM>zl "intro1"

GTM>k     ; we'll get to this command soon...

GTM>d pyr^intro1(7)
*
++
***
++++
*****
++++++
*******
******
*****
****
***
**
*

GTM>zwr
brick="*"
i=1
</pre>
<p>Our right side is all &#8220;*&#8221;.  And also we see that after running we still have the variable &#8220;brick&#8221; and &#8220;i&#8221; in the process scope, because we did not give any other scope in our code.  Lets try again only this time cleaning up our act.  One thing we should try for is to not add variables to the process scope because their memory does not get released until the process stops.  The other thing is we should try to keep scope where it belongs &#8211; this means always passing parameters and returning values when sharing variables between functions.  There is a command called &#8220;new&#8221; which allows us to declare a variable to the current stack level.  So we&#8217;ll use &#8220;n&#8221; and these other suggestions to make our code nice:</p>
<pre class="brush:js">
intro1 ;
 ;
pyr(max) d pyrr(1,max) quit
 ;
pyrr(lvl,max) n brick,i
 s brick=$$chooseBrick(lvl)
 ;
 f i=1:1:lvl w brick
 w !
 q:lvl=max
 d pyrr(lvl+1,max)
 f i=1:1:lvl w brick
 w !
 ;
 quit
 ;
 ;
chooseBrick(lvl) quit:lvl#2=0 "+"
 quit "*"
 ;
</pre>
<p>Note that we pass variables from function to function as parameters (from pyr to pyrr and from pyrr to pyrr and from pyrr to chooseBrick).  Note also that we use a return value from choose brick so that we do not share the variable &#8220;brick&#8221; across functions.  Every call to pyrr will result in a &#8220;new&#8221; brick variable scope, so both the left and right lines will use the correct bricks.  And finally we also &#8220;new&#8221; &#8220;i&#8221;, not that it changes any functionality, but it keeps &#8220;i&#8221; out of the process scope.</p>
<p>Run that new code and see that it does in fact work &#8211; do the &#8220;k&#8221; before the run and the &#8220;zwr&#8221; after, there should be no variables visible.</p>
<p>Now there are times that you want to clear a variable but not necessarily declare it, because it has already been declared correctly.  Consider these lines:</p>
<pre class="brush:js">
 n p
 f  s p=$o(^Toys(1,p)) q:(p="")!(p="car")
</pre>
<p>Note that we break out of the loop if we hit then end (&#8220;&#8221;) or if we come to &#8220;car&#8221;.  So after that loop, &#8220;p&#8221; might be &#8220;car&#8221; or it might be &#8220;&#8221;.  What if later in the code we have:</p>
<pre class="brush:js">
 f  s p=$o(^Toys(1,p)) q:(p="")!(p="apron")
</pre>
<p>If &#8220;apron&#8221; is in the list sometimes we would find it and sometimes not.  Can you see why?  If we found &#8220;car&#8221; in the code before this then we would end up looking from &#8220;car&#8221; forward and missing &#8220;apron&#8221;.  So should we do &#8220;n p&#8221; again?  We could, but either of these choices would be more common and use less memory:</p>
<pre class="brush:js">
 s p=""
 f  s p=$o(^Toys(1,p)) q:(p="")!(p="apron")
</pre>
<p>or</p>
<pre class="brush:js">
 k p
 f  s p=$o(^Toys(1,p)) q:(p="")!(p="apron")
</pre>
<p>A lot of M programmers would probably choose &#8220;kill&#8221; but neither is especially better than the other.  Now you cannot &#8220;new&#8221; a global (one of the few language differences between local and global) but you can kill it.  If you do &#8220;k ^test&#8221; all data related to that global will be cleared, it will be as if the global had never existed.</p>
<p>Where kill becomes really handy is the ability to &#8220;prune&#8221; branches from a M structure (global or local).  Consider:</p>
<pre class="brush:js">
GTM>k ^test

GTM>s ^test("a")="A"

GTM>s ^test("a",1)="A1"

GTM>zwr ^test
^test("a")="A"
^test("a",1)="A1"

GTM>k ^test("a",1)

GTM>zwr ^test
^test("a")="A"
</pre>
<p>See how you could remove a whole key (subscript)?  Further, any subkeys of &#8220;1&#8243; would also be removed.</p>
<p>There are just a hand full of commands remaining to consider in this post, the next is &#8220;read&#8221;.  To read character input from the command line use &#8220;r&#8221; and then the variable to store the result in.</p>
<pre class="brush:js">
 n input
 r input
 w input,!
</pre>
<p>The &#8220;if&#8221; command we have already covered in part.  There is also an &#8220;else&#8221; command which is a little weird because it does not have any argument.  So with &#8220;else&#8221; there are *always* two spaces after it &#8211; as in &#8220;e__&#8221;.  And there is one other &#8220;got you&#8221; with &#8220;if&#8221;.  In M there is only one process-wide conditional flag.  If that flag changes then it will affect the outcome of the &#8220;else&#8221;.</p>
<pre class="brush:js">
GTM>i 1

GTM>e  w "h"

GTM>i 0

GTM>e  w "h"
h
</pre>
<p>The &#8220;else&#8221; command is not just syntactic sugar, it is a real command that can execute without any &#8220;if&#8221; nearby.  Very nice for REPL and for language design, but odd for coding functions.  Consider the following:</p>
<pre class="brush:js">
GTM>i 1 d func^ROUTINEABC

GTM>e  w "h"
</pre>
<p>Not knowing anything about &#8220;func^ROUTINEABC&#8221; what will print after the else?  Will we get the &#8220;h&#8221;?  At first you think, &#8220;no&#8221;.  But consider that &#8220;func^ROUTINEABC&#8221; may have changed the process conditional flag.  So when we get to the else we are in an uncertain state, the else may run or not depending on what happened in that function call.</p>
<p>To safe guard it is common practice to place an &#8220;i 1&#8243; at the end of an &#8220;if&#8221; to put the conditional flag into the correct state.  So if we are coding this it would be:</p>
<pre class="brush:js">
GTM>i abc d func^ROUTINEABC i 1

GTM>e  d func^ROUTINEXYZ
</pre>
<p>This way we always execute either only &#8220;ROUTINEABC&#8221; or &#8220;ROUTINEXYZ&#8221;.</p>
<p>The next command I&#8217;ll just introduce because it could be a whole topic, but briefly there is a &#8220;merge&#8221; command that can take two M structures and merge one of them into a branch of the other.  It works with globals or locals, or across globals and locals.</p>
<pre class="brush:js">
GTM>k ^test

GTM>s ^test("a")="A"

GTM>zwr ^test
^test("a")="A"

GTM>s tmp(1)="A1"

GTM>zwr tmp
tmp(1)="A1"

GTM>m ^test("a")=tmp

GTM>zwr ^test
^test("a")="A"
^test("a",1)="A1"
</pre>
<p>As you can see, the contents of the variable &#8220;tmp&#8221; have been copied to the &#8220;a&#8221; branch of ^test.  This works even for complex structures with many keys and sub keys.  The source (e.g. &#8220;tmp&#8221;) will override any keys already in the destination (e.g. &#8220;^test&#8221;).</p>
<p>A built-in function to be aware of is &#8220;$d&#8221;.  It returns 0, 1, 10 or 11.  0 means the key does not exist, 1 the key does exist (has value) but there are no sub keys, 10 means there are sub keys only and no value for the key, 11 means there is a value for the key and also there are sub keys.</p>
<pre class="brush:js">
GTM>zwr ^test
^test("a")="A"
^test("a",1)="A1"

GTM>w $d(^test("a"))
11
GTM>w $d(^test("a",1))
1
GTM>w $d(^test("a",2))
0
GTM>
</pre>
<p>That covers a lot of the day-to-day stuff well.  There are two higher-level concepts I do want to cover here: transactions and locking.</p>
<p>Transaction support is pretty new to M, it was not part of the original design.  And frankly code that is written to M design concepts cannot really use transactions in spite of the fact they are supported.  The problems boils down to two things &#8211; how do you lock and what happens to your indexes when you roll back.</p>
<p>M is good at locking specific targets, so you can lock and index and update then unlock very quickly &#8211; the next process can then update the index and no dead lock because your first process isn&#8217;t holding on to lots of locks.  With careful planning you can keep your code to a minimal of locks and lock very specific things, thus reducing conflict and preventing deadlock.</p>
<p>When you start using transactions in M you end up having to lock much larger swathes of data and therefore produce more blocking.  M design hates inefficiency like that.  </p>
<p>Second, consider what would happen if you did lock, update and release indexes during a transaction.  What would happen if you rolled back?  The index would go back to the state before you updated, which means any updates to the index after your update get wiped out.  This is very bad.  So really tx is just not M like and I feel should be ignored as much as possible.</p>
<p>Moving on to locking.  Locking is a great feature of M because you can lock any key of any global with the &#8220;lock&#8221; command.  The &#8220;lock&#8221; command is a little weird though as it uses a &#8220;+&#8221; to acquire and a &#8220;-&#8221; to release.  Acquire:</p>
<pre class="brush:js">
 l +^test("a",1)
</pre>
<p>Release:</p>
<pre class="brush:js">
 l -^test("a",1)
</pre>
<p>Lock does not prevent another process from updating the global.  So all code that updates a certain global must manually lock first, which then blocks until available, and then make the update (and then release lock).  When ever possible lock only a single record at a time.  Keep the record locked until all updates are made to the record as well as any index updates relating to that record.  The &#8220;record first&#8221; and &#8220;1 record only&#8221; rules pretty much prevent dead locks.  If you don&#8217;t write code that locks the index first and then tries to lock the record, well you won&#8217;t open the door to deadlock.  You might hit the occasionally blocking wait, but that is much better than deadlock.</p>
<p>That wraps up the mini-series on MUMPS.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.divconq.com%2F2011%2Fintro-m-part-4%2F&amp;title=Introduction%20to%20M%20%28MUMPS%29%20Part%204" id="wpa2a_20"><img src="http://www.divconq.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.divconq.com/2011/intro-m-part-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

