<?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>GigaMegaBlog &#187; IBM Universe (U2)</title>
	<atom:link href="http://www.gigamegablog.com/category/programming/ibm-universe-u2/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.gigamegablog.com</link>
	<description>Powered by GigaMegaWatts</description>
	<lastBuildDate>Sun, 05 Feb 2012 16:39:22 +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>UniVerse and .Net: Give or take a period</title>
		<link>http://www.gigamegablog.com/2009/04/13/universe-and-net-give-or-take-a-period/</link>
		<comments>http://www.gigamegablog.com/2009/04/13/universe-and-net-give-or-take-a-period/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 00:25:46 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[UniVerse]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/?p=125</guid>
		<description><![CDATA[q <a href="http://www.gigamegablog.com/2009/04/13/universe-and-net-give-or-take-a-period/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve recently come across a couple of tricky bugs in IBM&#8217;s ADO.NET driver for their <a href="http://www-01.ibm.com/software/data/u2/">U2 UniVerse database</a>, showing that there are still a few sharp edges on that shiny new finish.</p>
<p>The first and more serious bug is that the driver always returns numbers with a decimal point as a zero when using French &#8220;regional settings&#8221; in Windows.</p>
<p>For example, when using these Regional Settings&#8230;</p>
<div class="img size-full wp-image-128" style="width:404px;">
	<img src="http://www.gigamegablog.com/wp-content/uploads/2009/04/regionalsettings.png" alt="Zut alors, c'est un comma!" width="404" height="485" />
	<div>Zut alors, c'est un comma!</div>
</div>
<p>&#8230;the sample .Net application that IBM provides in its <a href="http://www.ibm.com/developerworks/edu/dm-dw-dm-0805else-i.html">QuickStart tutorial</a> displays this:</p>
<div class="img size-full wp-image-127" style="width:500px;">
	<img src="http://www.gigamegablog.com/wp-content/uploads/2009/04/ibmsampleprogram.png" alt="French toast" width="500" height="386" />
	<div>French toast</div>
</div>
<p>We ran into this bug because many of our product&#8217;s users have the &#8220;French (Canada)&#8221; setting on their PCs.  I assume that the root cause of the bug is that a comma, rather than a period, is used as  the decimal point, as marked in yellow above.  IBM support has confirmed that this is a bug are internally testing a fix in the Runtime Client, so the fix will likely be available in Fix Pack 3c or the one after that.</p>
<p>I&#8217;m surprised that nobody (including us) ran into this bug earlier, but that&#8217;s probably because most developers (including us) have got into the habit of reading data from UniVerse as strings, then converting the data into its proper format in their code.  As I&#8217;ve mentioned in past articles, UniVerse has a &#8220;multivalue&#8221; heritage where all data is stored internally as strings.  Developers should go against this grain at their own peril.</p>
<p>For example, rather than defining a currency field in the Universe dictionary like this&#8230;</p>
<pre class="brush: sql; title: ; notranslate">
COMMISSION
001 A
002 34
005 S
007 MD3
009 R
010 7
</pre>
<p>&#8230; define it as&#8230;.</p>
<pre class="brush: sql; title: ; notranslate">
COMMISSION.STR
001 A
002 34
005 S
006 CHAR,7
009 R
010 7
</pre>
<p>&#8230; and read the value into a String.  Then, you can convert it to a Decimal variable using code like&#8230;</p>
<pre class="brush: csharp; title: ; notranslate">
Decimal.TryParse(strValue, System.Globalization.NumberStyles.Number,
System.Globalization.CultureInfo.InvariantCulture, out decValue);
</pre>
<p>The &#8220;InvariantCulture&#8221; thing is needed because, when defined as a CHAR, UniVerse will return a decimal value using &#8212; surprise, surprise &#8212; a period as the decimal point.</p>
<p>The second bug that we tripped over was a little more obscure.    The bug was found by one of our developers, who was double-checking the configuration of our clients&#8217; databases to make sure that all of our latest patches had been applied.  He found that one particular SQL statement used in our application was failing with the following error:</p>
<pre class="brush: sql; title: ; notranslate">
Error  occurred: ERROR [Command_ExecuteDirect]  [IBM  U2][UCINET][UNIVERSE]:UniVerse/SQL: syntax error.  Unexpected verb.  Token was  &quot;LIST&quot;. Scanned command was FROM VENDORS SELECT LIST  :  IBM.Data.DB2: -2147467259
</pre>
<p>This type of error usually indicates a mismatch between our dictionary entries and our application, which was the type of configuration issue that he was checking for.  It wasn&#8217;t a big surprise, since the problem was found in a database that is only used for in-house training.  Surprisingly, though, after reapplying the latest dictionary entries the bug remained.</p>
<p>Like most database systems that I&#8217;ve worked with, UniVerse&#8217;s SQL parser tends to return some pretty vague error messages.  The particular SQL statement that was failing was quite long,  containing about 20 columns, none of which were named &#8220;LIST&#8221;.  By trial-and-error, I found that the culprit was a field named DEMO.LIST.  The DICT definition of this field was fine &#8211; it exactly matched the dictionary entry used in the other databases at this client site, none of which were experiencing this error.  While scratching my head over this, our developer told me that he found the same error in the same SELECT statement in a database at a different client.  This database was also one used for in-house training.</p>
<p>This made me suspect that the error was caused by bad data.  The databases used for in-house training are more likely to contain weird characters like embedded tabs or carriage-returns.</p>
<p>The dictionary definition of DEMO.LIST was a 100-character string:</p>
<pre class="brush: sql; title: ; notranslate">
DEMO.LIST
001 A
002 5
005 S
006 CHAR,100
009 L
010 100
</pre>
<p>As mentioned earlier, strings are usually a safe choice for data in UniVerse.  I&#8217;m not aware of any type of data that can cause a SELECT of a a string to fail in UniVerse&#8217;s ADO.NET driver, but there&#8217;s a first time for everything.  However, a bit of trial-and-error testing made it clear that this SELECT statement was failing on the plainest of records: vanilla text that couldn&#8217;t possibly cause a problem.  It was a real whodunnit.</p>
<p>Back to the not-very-helpful error message,  It was complaining about a &#8220;token&#8221; named LIST.  If I simplified the variable name to something like FIELD1, did that affect the error message?  Well, yeah: it made the error go away completely. The SELECT statement worked fine if the column name was changed to FIELD1, or DEMO or even DEMOLIST.  Weird.  We have periods in lots of our column names, and a lot of them are named LIST.  DEMO, not so much.</p>
<p>At this point, things finally fell into place.  The name that we give our databases that are used for in-house training is DEMO.  And, of course, in standard SQL syntax, a period in a column name is used to identify the table, such as &#8220;SELECT TABLE1.FIELD1&#8243;.  Sure enough, I ran some tests in our development database, named DEV, and found that naming a column &#8220;DEV.LIST&#8221; or &#8220;DEV.FIELD&#8221; or &#8220;DEV.WHATEVER&#8221; caused SELECT statements that use that field to fail.</p>
<p>The moral of the story, I suppose, is don&#8217;t use periods in your column names.  That was IBM support&#8217;s suggestion, though I&#8217;m hoping that they will fix this bug as well.</p>
<p>I suppose that both of these bugs are indicative of what happens when you drag a 40-something year-old non-relational database kicking and screaming into the .Net world.  Oops, better make that &#8220;dotNet&#8221; to be safe!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2009/04/13/universe-and-net-give-or-take-a-period/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>IBM UniVerse and .Net, BFF</title>
		<link>http://www.gigamegablog.com/2008/12/18/ibm-universe-and-net-bff/</link>
		<comments>http://www.gigamegablog.com/2008/12/18/ibm-universe-and-net-bff/#comments</comments>
		<pubDate>Thu, 18 Dec 2008 22:37:51 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[UniVerse]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/2008/12/18/ibm-universe-and-net-bff/</guid>
		<description><![CDATA[This article is the third and final part of a series that covers some lessons learned when trying to plug Visual Studio into our IBM U2 UniVerse database using IBM&#8217;s ADO.NET driver.&#160; Part 1 was an overview of how well &#8230; <a href="http://www.gigamegablog.com/2008/12/18/ibm-universe-and-net-bff/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><html><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"></meta><meta content="text/html;charset=utf-8" http-equiv="Content-Type" id="metaid"></meta><meta content="pagewise" id="fntype"></meta><meta content="1-1" id="fnstyle"></meta><meta content="212" name="zid"><br />
<style id="styletagforeditor">body { border: 0px; font-family:verdana; font-size :10pt; direction :ltr; background-color :#ffffff; line-height :1.2; margin:0% 10% 0% 10%;}</style>
<style id="styletagtwoforeditor">table { font-size: 10pt;} p { margin-top:0px; margin-bottom:0px; }</style>
<link href="/styles/print.css" id="stylesheetforpreview" media="print" rel="stylesheet"></link>
<link href="/styles/print_preview.css" id="stylesheetforprintpreview" media="screen" rel="stylesheet"></link>
<link href="/styles/editor.css" id="stylesheetforeditor" rel="stylesheet"></link></meta></head><body>This article is the third and final part of a series that covers some lessons learned when trying to plug Visual Studio into our <a href="http://www-01.ibm.com/software/data/u2/" zid="195">IBM U2 UniVerse database</a> using IBM&#8217;s ADO.NET driver.&nbsp; <a href="http://gigamegablog.com/2008/11/25/visual-studio-and-ibm-universe-playing-the-matchmaker/" zid="196">Part 1</a> was an overview of how well the ADO.NET driver has worked for us, and the prerequisite software that is required to use it.&nbsp; <a href="http://gigamegablog.com/2008/12/03/the-meaning-of-everything-universe-dictionaries-for-the-net-programmer/" zid="197">Part 2</a> gave some tips on preparing your UniVerse dictionaries for use with Visual Studio.&nbsp; In this part of the series, we finally get to fire up Visual Studio and connect it to the database.<br zid="6"/><br zid="8"/>One of the great things about the ADO.NET driver, when compared to other UniVerse APIs like UniOLEDB and UniVerse Objects.NET, is that it allows Visual Studio to finally recognize UniVerse as a database.&nbsp; That means you don&#8217;t have to write a bunch of code in order to see the data &#8212; you can use use Visual Studio to explore the database and test your SQL statements.&nbsp; (On the other hand, if you prefer to just write code and avoid all the point-and-click stuff, you can <a href="#StartCoding" zid="203">skip ahead to this point in the article</a>.)<br zid="9"/><br zid="10"/><img align="right" alt="UniVerse Data Connections" border="0" hspace="3" src="http://writer.zoho.com:80/ImageDisplay.im?name=305886000000072001/1229560596507_12-17-2008%207-34-19%20PM.png&#038;accId=305886000000002007" vspace="8" zid="205"/>The first step is to configure your UniVerse database in Visual Studio&#8217;s Server Explorer. &nbsp;This process is explained well in IBM&#8217;s developerWorks article <a href="http://www.ibm.com/developerworks/edu/dm-dw-dm-0802kumar-i.html" zid="204">&quot;Access IBM U2 data server from your .NET applications, Part 2&quot;</a>.&nbsp; Since I would strongly advise you to read IBM&#8217;s three-part tutorial series anyway, I won&#8217;t repeat the information here.<br zid="11"/><br zid="12"/>You should now have a new node in the Data Connections section of the Server Explorer, as shown in the screenshot on the right, with a name like &quot;&lt;user-ID&gt;@&lt;account&gt;[UNIVERSE 10.02.0000]&quot;.&nbsp; Expand that node, and you&#8217;ll see 4 sections: Tables, Views (which will be forever empty), Procedures and Functions (also empty).&nbsp; Expand the Tables node and, hopefully, you&#8217;ll see a list of the tables in your account.&nbsp; Expand one of the tables, and you&#8217;ll hopefully see the columns in that table.&nbsp; Right-click on the table and select &quot;Show Data&quot;, and you&#8217;ll see a grid containing all the rows of the table.&nbsp; Groovy!&nbsp; UniVerse and Visual Studio sitting in a tree-ee&#8230;<br zid="15"/><br zid="16"/><img align="left" alt border="0" hspace="8" src="http://writer.zoho.com:80/ImageDisplay.im?name=305886000000072001/1229560839859_12-17-2008%207-38-03%20PM.png&#038;accId=305886000000002007" vspace="0" zid="206"/>Alas, you might, like I,&nbsp;find that Visual Studio&#8217;s love for UniVerse is not so easily requited.&nbsp; When I expand the Tables node in our development account, I see the warning on the left.&nbsp; After clicking on the Yes button, I am then left staring at the hourglass for a few minutes before the table list appears.&nbsp; If I expand one of the tables to view its columns, I once again find myself contemplating the Windows hourglass for a minute or so, even if the table only contains a few columns.&nbsp; If I want to use Visual Studio&#8217;s query builder with my UniVerse database: you guessed it, again with the hourglass.&nbsp; Trust me, that gets real old real fast!<br zid="17"/><br zid="18"/>It would seem that Visual Studio&#8217;s Explorers like to, well, explore.&nbsp; If you have a large UniVerse master dictionary, all that exploring takes some time.&nbsp; The key to speeding up Visual Studio is to limit how much of your master dictionary it sees.&nbsp; If you read Chapter 4 of the <a href="http://www-01.ibm.com/software/data/u2/pubs/library/102univ/" zid="207">UniVerse ODBC Guide</a>, you&#8217;ll find that happily there is a mechanism for doing just that: create a file named HS_FILE_ACCESS and add an entry in it for each file that you want to use with Visual Studio.&nbsp; Unhappily, while this limits the number of tables that you&#8217;ll see in Visual Studio, it only makes things slightly faster. <br zid="19"/><br zid="20"/>I suspect that the solution to this problem is to create a new account whose master dictionary contains only the data files you want Visual Studio to work with.&nbsp; I&#8217;ll be trying this for myself at some point in the future, and I&#8217;ll blog about it then.&nbsp; <br zid="21"/><br zid="22"/>Fortunately, even if you find that slow performance makes some of Visual Studio&#8217;s point-and-click features unusable, you are still left with enough tools to get the job done.&nbsp; <br zid="23"/><br zid="24"/>    Let&#8217;s start with some SELECT queries.&nbsp; Right-click the database connection in the Server Explorer and, instead of New Query, choose New Script.&nbsp;&nbsp; This opens the Script Builder (shown in the screenshot below), an IBM tool that is basically a stripped-down version of Visual Studio&#8217;s Query Builder: no Diagram pane, no Criteria pane, just a box for your SQL and a&nbsp; grid with your results.&nbsp; (And a tiny little 1-icon toolbar &#8211; cute!).&nbsp; More typing, but a lot less waiting, since this dialog do a scan of your UniVerse master dictionary.<br zid="27"/><img align="middle" alt="UniVerse Script Builder" border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=305886000000072001/1229562120646_12-17-2008%207-59-52%20PM.png&#038;accId=305886000000002007" vspace="8" zid="208"/><br zid="28"/>The SELECT commands that you enter here follow most of the same rules as for a SQL database, but there are a few tricky things:<br zid="31"/><br zid="32"/>1) Case matters &#8211; if your columns are defined in your DICT in upper-case, you must use upper-case here, something that is sure to trip up any SQL Server or Oracle developer.<br zid="46"/><br zid="33"/>2) Columns and tables that contain hyphens must be surrounded with double quotes &#8212; the square brackets that you may be used to using with other databases won&#8217;t cut it here.&nbsp; For example,</p>
<pre class="brush: sql; title: ; notranslate">
select USER.ID from &quot;CSUSER-FILE&quot;
</pre>
<p>is valid, but not</p>
<pre class="brush: sql; title: ; notranslate">
select USER.ID from [CSUSER-FILE]
</pre>
<p>or</p>
<pre class="brush: sql; title: ; notranslate">
select user.id from &quot;csuser-file&quot;
</pre>
<p>Oddly, names that contain a period do not have to be quoted &#8211; unlike its SQL database brethren, UniVerse is smart enough to figure out when the period delimits the table ID from the column name.<br zid="44"/><br zid="45"/>3) A &quot;SELECT *&quot; query will return the key fields along with whatever fields are defined in a special dictionary entry named &quot;@&quot;.&nbsp; For example, if you want SELECT * FROM USERS to return the FIRST-NAME and LAST-NAME fields, you&#8217;ll need to edit the dictionary as follows:</p>
<pre class="brush: sql; title: ; notranslate">
ED DICT USERS
Record name = @
2 lines long.

----: 2
0002: 1 2
Bottom at line 2.
----: R FIRST-NAME LAST-NAME
0002: FIRST-NAME LAST-NAME
Bottom at line 2.
----: FI
&quot;@&quot; filed in file &quot;DICT USER&quot;.
</pre>
<p>If you don&#8217;t have a record named &quot;@&quot; in your file&#8217;s dictionary, then &quot;SELECT *&quot; will return the column named &quot;@ID&quot; if you have one (which you probably do, since the primary key is  automatically added to all dictionaries under this name when you first create them).&nbsp; If you happen to have deleted the &quot;@ID&quot; column, then SELECT * will fail with a &quot;No column rows&quot; error.<br zid="61"/><br zid="62"/>What if you have a 200 column table and you want SELECT * to return all 200 columns?&nbsp; Sorry, but you&#8217;ll have to enter all 200 column names in that &quot;@&quot; record.&nbsp; And if you add, delete or rename a column, you&#8217;ll have to remember to edit that &quot;@&quot; record. I feel your pain!&nbsp; This cumbersome approach dates back to UniVerse&#8217;s ODBC driver, and I suppose they can&#8217;t change it now without breaking a lot of applications.&nbsp; You can find the details described in inscrutable IBM-ese in the UniVerse ODBC Guide.<br zid="13"/><br zid="14"/>4) Errors encountered when executing your SQL statement are reported in a pretty obscure manner.&nbsp; You&#8217;ll see a message box with the &quot;Error in SQL.&nbsp; Check the SQL and try again.&nbsp; For error detail information refer to the IBM Output Message Pane&quot;.&nbsp; It took me awhile to figure out where the &quot;IBM Output Message Pane&quot; was hidden.&nbsp; It&#8217;s in the Output window (Ctrl-W O), but you&#8217;ll need to change the &quot;Show output from&quot; combo to &quot;IBM Output Message Pane&quot; as shown below.&nbsp; <br zid="209"/><img align="middle" alt="IBM Output Message Pane" border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=305886000000072001/1229562562845_12-17-2008%208-08-07%20PM.png&#038;accId=305886000000002007" vspace="8" zid="210"/><br zid="2"/><br zid="65"/>5) If you have subvalued fields, only the first subvalue in the field will appear in the Results grid.&nbsp; (Subvalues are ASCII 252 delimiters which are used to fit multiple fields into the same column).&nbsp; This is presumably a side effect of a bug in IBM&#8217;s ADO.NET driver which replaces subvalue delimiters with CR/LF.<br zid="148"/><br zid="149"/>6) There are a couple of bugs in the ADO.NET driver for which, as far as I know, there is no good workaround.&nbsp; The first is that the SQL processor can&#8217;t handle hard-coded values which contain the &quot;at sign&quot;, such as:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT * FROM MY.TABLE WHERE THE.KEY = &quot;DAN@WORK&quot;
</pre>
<p>Depending on the structure of your data you may be able to get at the data by using a wildcard instead</p>
<pre class="brush: sql; title: ; notranslate">
SELECT * FROM MY.TABLE WHERE THE.KEY LIKE &quot;DAN%WORK&quot;
</pre>
<p>The other bug is that zero-length numeric fields such as the one in attribute 5 below will result in an <span style="width: 500px;" zid="158"><font size="-1" zid="159">&ldquo;Input string was not in a correct format&rdquo; error (that funny little accented character is ASCII 253, the multivalue delimiter):</p>
<pre class="brush: sql; title: ; notranslate">
0001: SMITH
0002: 1414 W. 8TH
0003: DENVER
0004: CO
0005: V2001Ã½Ã½C8181
0006: 200Ã½3599Ã½1050
</pre>
<p>This latter bug was fixed by IBM in the recently released Fix Pack 3, but if you have users on earlier releases there is a workaround you can implement in your code, as explained later in the article.<br zid="66"/></font></span><br zid="67"/>7) Last, but not least, multivalues.&nbsp; As described in <a href="http://gigamegablog.com/2008/12/03/the-meaning-of-everything-universe-dictionaries-for-the-net-programmer/" zid="211">my previous article</a> there are a few different ways to configure your dictionary to return multivalues, but the method that IBM recommends is to list the multivalued fields in a special &quot;association&quot; dictionary entry that looks like this:</p>
<pre class="brush: sql; title: ; notranslate">
    DETAILS
001 PH ASSOCIATION OF ORDER DETAIL FIELDS
002 ORDER.IDS ORDER.AMOUNTS
</pre>
<p>The advantage of this approach is that you can return the items within the multivalued field as if they were separate columns, which makes the data a lot easier to work with.&nbsp; The disadvantage is that you&#8217;ll have to puzzle out the syntax for a join with a &quot;virtual table&quot;. &nbsp; If the above field DETAILS was defined in the dictionary of a table named CUSTOMERS, then a SQL statement to return a list of order IDs and amounts would be:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT a.KEY.FULL, ORDER.IDS, ORDER.AMOUNTS FROM CUSTOMERS a JOIN CUSTOMERS_DETAILS b ON a.KEY.FULL = b.KEY.FULL
</pre>
<p>Since the dictionary field that is automatically added for the primary key, &quot;@ID&quot;, can&#8217;t be used in SQL statements, you&#8217;ll have to add one yourself in order to use it in the JOIN &#8212; in the above example I added a field named KEY.FULL to CUSTOMERS.<br zid="101"/><br zid="102"/>If by this point you&#8217;re fully freaked out by the UniVerse way of implementing SQL, then I&#8217;ve got some good news for you: the code itself is pretty much plain vanilla and won&#8217;t require much explanation.&nbsp; <br zid="200"/><img align="right" alt border="0" hspace="8" src="http://writer.zoho.com:80/ImageDisplay.im?name=305886000000072001/1229562797642_12-15-2008%207-48-19%20PM.png&#038;accId=305886000000002007" vspace="3" zid="212"/><br zid="201"/><a class="ItemAnchor" name="StartCoding" title="StartCoding" zid="202"></a>Before you start coding, you&#8217;ll need to add a reference to the IBM.Data.DB2 DLL to your project References list, as shown at the right.&nbsp; You&#8217;ll also need to add &quot;IBM.Data.DB2&quot; to your list of namespaces:</p>
<pre class="brush: csharp; title: ; notranslate">
using IBM.Data.DB2;
</pre>
<p>The process of building a connection string is quite similar to other databases like SQL Server.&nbsp; You&#8217;ll need to set the Server, User, Password and Database (which is the UniVerse account name). &nbsp; In addition, you need to set two less familiar properties &#8212; ServerType and Pooling:</p>
<pre class="brush: csharp; title: ; notranslate">
private string providerName = &quot;IBM.Data.DB2&quot;;
private DbConnectionStringBuilder builder;
private DbConnection conUniVerse;

builder = new DbConnectionStringBuilder();
builder[&quot;Server&quot;] = txtServer.Text.Trim();
builder[&quot;User ID&quot;] = txtUserID.Text.Trim();
builder[&quot;Password&quot;] = txtPassword.Text.Trim();
builder[&quot;ServerType&quot;] = &quot;universe&quot;;
builder[&quot;Pooling&quot;] = &quot;false&quot;;
builder[&quot;Database&quot;] = txtAccount.Text.Trim();
string strConnectionString = builder.ConnectionString;

DbProviderFactory m_provider = DbProviderFactories.GetFactory(providerName);
conUniVerse= m_provider.CreateConnection();

conUniVerse.ConnectionString = strConnectionString;
conUniVerse.Open();
</pre>
<p>You&#8217;ll then need to create an ADO Data Adapter and feed it the SQL statement.</p>
<pre class="brush: csharp; title: ; notranslate">
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
DbDataAdapter adapter = factory.CreateDataAdapter();
adapter.FillError += new FillErrorEventHandler(adapter_FillError);
adapter.SelectCommand = DB_GetCommand(strSQL);
</pre>
<p>Lastly, you create an ADO Dataset to hold the results of the query, then bind that Dataset to a grid on your form to display the data:</p>
<pre class="brush: csharp; title: ; notranslate">
DataSet dsData = new DataSet();
adapter.Fill(dsData , &quot;MyData&quot;);

bindingSource1.DataSource = dsData ; // bindingSource1 is a BindingSource object that I dragged from the Toolbox onto my form
bindingSource1.DataMember = &quot;MyData&quot;;
gridData.DataSource = bindingSource1; // gridData is a DataGridView object on my form
conUniVerse.Close();
</pre>
<p>You may have noticed that I added a FillError event handler to my adapter.&nbsp; This is a workaround for the zero-length multivalue problem that I mentioned earlier in the article.&nbsp; In the error handler, you can examine the Exception&#8217;s properties and, if it appears to be the zero-length multivalue error, set the e parm&#8217;s Continue property to true.</p>
<pre class="brush: csharp; title: ; notranslate">
void adapter_FillError(object sender, FillErrorEventArgs e)
{
    if (e.Errors.Message.Contains(&quot;Input string was not in a correct format&quot;))
        e.Continue = true;
}
</pre>
<p>This will result in the dataset being filled, but without the multivalued &quot; virtual record&quot; that contained the zero-length value. If the zero-length value is just bad data then that&#8217;s probably what you want &#8212; otherwise, you&#8217;ll need Fix Pack 3.<br zid="193"/><br zid="194"/>Whew!&nbsp;&nbsp; That might seem like a lot of work to read some data into a grid, but it&#8217;s stable, it&#8217;s pretty fast, and it&#8217;s still a lot less coding than the only other stable and fast UniVerse API out there, UniVerse Objects.&nbsp; Once you&#8217;ve learned the ropes, UniVerse is now a viable database option for .Net development.&nbsp; <br zid="5"/><br zid="1"/></body></html></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2008/12/18/ibm-universe-and-net-bff/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Meaning of Everything: UniVerse Dictionaries for the .Net Programmer</title>
		<link>http://www.gigamegablog.com/2008/12/03/the-meaning-of-everything-universe-dictionaries-for-the-net-programmer/</link>
		<comments>http://www.gigamegablog.com/2008/12/03/the-meaning-of-everything-universe-dictionaries-for-the-net-programmer/#comments</comments>
		<pubDate>Thu, 04 Dec 2008 00:49:09 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[UniVerse]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/2008/12/03/the-meaning-of-everything-universe-dictionaries-for-the-net-programmer/</guid>
		<description><![CDATA[This article is a continuation of my previous post about using IBM U2 UniVerse&#8216;s ADO.NET driver with Visual Studio.&#160; Today I&#8217;m going to deal with the part of the process that makes .Net programmers cringe but is the key to &#8230; <a href="http://www.gigamegablog.com/2008/12/03/the-meaning-of-everything-universe-dictionaries-for-the-net-programmer/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><html><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"></meta><meta content="text/html;charset=utf-8" http-equiv="Content-Type" id="metaid"></meta><meta content="pagewise" id="fntype"></meta><meta content="1-1" id="fnstyle"></meta><meta content="200" name="zid"><br />
<style id="styletagforeditor">body { border: 0px; font-family:verdana; font-size :10pt; direction :ltr; background-color :#ffffff; line-height :1.2; margin:0% 10% 0% 10%;}</style>
<style id="styletagtwoforeditor">table { font-size: 10pt;} p { margin-top:0px; margin-bottom:0px; }</style>
<link href="/styles/print.css" id="stylesheetforpreview" media="print" rel="stylesheet"></link>
<link href="/styles/print_preview.css" id="stylesheetforprintpreview" media="screen" rel="stylesheet"></link>
<link href="/styles/editor.css" id="stylesheetforeditor" rel="stylesheet"></link></meta></head><body>This article is a continuation of <a href="http://gigamegablog.com/2008/11/25/visual-studio-and-ibm-universe-playing-the-matchmaker/" zid="112">my previous post</a> about using <a href="http://www-01.ibm.com/software/data/u2/" zid="113">IBM U2 UniVerse</a>&#8216;s ADO.NET driver with Visual Studio.&nbsp; Today I&#8217;m going to deal with the part of the process that makes .Net programmers cringe but is the key to crafting effective SELECT statements: the UniVerse dictionary.<br zid="102"/><br zid="103"/>You probably already have dictionary entries that you (or others) use with UniVerse Basic code, but there are a few cases where you may need to modify them in order to access the fields through ADO.Net.&nbsp; UniVerse Basic is pretty forgiving about incorrect dictionary entries &#8212; as long as the entry tells the code which attribute to look in, UniVerse Basic is happy.&nbsp; Unfortunately, ADO.Net (and other SQL-oriented APIs) are picky about data types and conversion codes &#8212; they frown on UniVerse&#8217;s attempt to portray every piece of data as a string.<br zid="104"/><br zid="105"/>IBM has provided a utility named HS.SCRUB which analyzes your dictionaries and flags any fields which might cause problems for the database driver.&nbsp; If you are brave, you can even let HS.SCRUB &quot;autofix&quot; your dictionaries. This utility was actually introduced with the UniVerse ODBC driver, and you&#8217;ll find the documentation for it in the UniVerse ODBC Guide and the Using UniOLEDB manual.&nbsp; (You can download PDF copies of any of the UniVerse manuals from <a href="http://www-01.ibm.com/software/data/u2/pubs/library/102univ/" zid="114">here</a>.) Frankly, the utility found so many problems in our dictionaries, including a lot of false positives, that I ended up ignoring it and building new dictionary entries from scratch.&nbsp; Your mileage may vary.<br zid="106"/><br zid="107"/>However, even after letting HS.SCRUB have its way with your dictionaries, there are some cases that will require special attention:<br zid="28"/><br zid="136"/><span style="font-weight: bold;" zid="108">1) Non-string fields that may be null.</span><br zid="137"/><br zid="29"/><span style="font-weight: bold;" zid="138"></span>If you don&#8217;t specify the data type of a field, the database driver will helpfully try to guess the data type on-the-fly by looking at the data.&nbsp; HS.SCRUB uses a similar approach to determine the correct data type.&nbsp; Unfortunately, both of them are tripped up by non-string fields which contain some zero-length values &#8212; if you &nbsp; define these as any data type except strings, the zero-length values will result in &quot;invalid data type&quot; .Net Exceptions at run time.<br zid="109"/><br zid="110"/>In cases like this, I&#8217;d suggest you force the field to be read as a string, by specifying &quot;CHAR&quot; in the data type attribute of the dictionary entry.&nbsp; The data type attribute is 6 for A and S-type dictionary entries, and attribute 8 for D- and I-type correlatives.&nbsp; If you have no idea what that means, then you&#8217;d better have a look at Chapter 5 of the UniVerse System Description manual.&nbsp; (As mentioned earlier, PDF copies of all of the UniVerse manuals can be found <a href="http://www-01.ibm.com/software/data/u2/pubs/library/102univ/" zid="115">here</a>.)<br zid="30"/><br zid="31"/><span style="font-weight: bold;" zid="147">2) Time fields with contain milliseconds.&nbsp; </span><br zid="148"/><br zid="149"/>In Universe files, time fields are written in a &quot;Julian&quot; format which converts the time to the number of seconds past midnight: for example, 1:30 am is 5400.&nbsp; Optionally, these time fields can contain the number of milliseconds, which is written as a decimal value: for example, 5400.5 is half a second after 1:30 am.&nbsp; Unfortunately, the UniVerse ADO.Net driver can&#8217;t convert a string with that format into a TimeSpan.&nbsp; One workaround is to define the field as a string, by specifying &quot;CHAR&quot; as the data type (see point (a), above).&nbsp; You will then have to write a bit of code to convert the string to a .Net TimeSpan value:</p>
<pre class="brush: csharp; title: ; notranslate">
public static TimeSpan TimeSpan_FromUniverseString(string strUniverseTime)
{
    int intUniverseTime = 0;
    // if the string contains milliseconds, discard them
    int intIndex = strUniverseTime.IndexOf('.');
    if (intIndex &gt;= 0)
    {
        strUniverseTime = strUniverseTime.Substring(0, intIndex);
    }

    if (!Int32.TryParse(strUniverseTime, out intUniverseTime))
    {
        // if not a numeric, then return 00:00:00
        return new TimeSpan(0);
    }
    int intDays = intUniverseTime / 86400;
    int intRemainder = intUniverseTime % 86400;
    int intHours = intRemainder / 3600;
    intRemainder = intRemainder % 3600;
    int intMinutes = intRemainder / 60;
    int intSeconds = intRemainder % 60;
    return new TimeSpan(intDays, intHours, intMinutes, intSeconds);
}
</pre>
<p>However, an easier workaround (which I stumbled across after using the above approach for months) is to take advantage of the &quot;correlative&quot; code.&nbsp; <br zid="120"/><br zid="121"/>This code only exists in A- and S-type dictionary entries, in attribute 8.&nbsp; Ordinarily, time fields are defined in UniVerse dictionaries by specifying a &quot;conversion code&quot;, such as &quot;MTS&quot; in attribute 7.</p>
<pre class="brush: sql; title: ; notranslate">
    ACCESS.TIME
001 A
002 3
005 S
007 MTS
009 R
010 5
</pre>
<p>This tells ADO.Net (or UniVerse Basic) that the value in this field can be regarded as a time.&nbsp; However, by specifying the same conversion code in attribute 8, the conversion to a time value is handled internally by the UniVerse database&nbsp;before ADO.Net sees it. </p>
<pre class="brush: sql; title: ; notranslate">
    ACCESS.TIME.SQL
001 A
002 3
005 S
008 MTS
009 R
010 5
</pre>
<p>Therefore, a value such as &quot;3600.5&quot; will be seen by the ADO.Net driver as 1:30 am, without that nasty millisecond value that it so dislikes.<br zid="57"/><br zid="150"/><span style="font-weight: bold;" zid="151">3) Multivalues</span><br zid="58"/><br zid="152"/>Ah yes, multivalues.&nbsp; This is a method for storing multiple values into the same field, separated by a special delimiter.&nbsp; For example, attribute 1 might contain a list of order numbers, and attribute 2 the amount (in cents) of each of order:</p>
<pre class="brush: sql; title: ; notranslate">
001 C2000Ã½M3000Ã½S3000
002 600782Ã½700422Ã½101456
</pre>
<p>Multivalued strings are the primary feature that distingishes UniVerse and its brethern databases from all the others, but .Net doesn&#8217;t really understand the concept (nor do many .Net programmers, actually).&nbsp; UniVerse provides some tools which allow you to dress up the multivalued data to resemble columns in a normalized SQL database &#8212; it is up to you whether you want to play dress-up, or just process the multivalued fields in their underlying form: delimited strings.<br zid="158"/><br zid="159"/>There are 3 different approaches to definining multivalued strings in the dictionary so that they are safe for consumption by .Net:<br zid="59"/><br zid="60"/>i) The documented approach is to use a D-type dictionary entry which contains an &quot;M&quot; in attribute 6 and an &quot;association&quot; name in attribute 7.&nbsp; For example, the definition of the Order ID and Order Amount fields might look like:</p>
<pre class="brush: sql; title: ; notranslate">
    ORDER.IDS
001 D Order IDs
002 1
004 Order IDs
005 10L
006 M
007 DETAILS

    ORDER.AMOUNTS
001 D Order Amounts
002 2
003 MD0,$
004 Order Amount
005 7R
006 M
007 DETAILS
</pre>
<p>And the dictionary entry which defines the virtual &quot;DETAILS&quot; table would be:</p>
<pre class="brush: sql; title: ; notranslate">
    DETAILS
001 PH ASSOCIATION OF ORDER DETAIL FIELDS
002 ORDER.IDS ORDER.AMOUNTS
</pre>
<p>If the main table which contained the multivalued fields was named SALES, then there would now be a virtual table named SALES_DETAILS containing three fields: ORDER.IDS, ORDER.AMOUNTS, and&nbsp;a foreign key field that points back to the primary key of the SALES table.&nbsp;<br zid="160"/><br zid="161"/>For details, see chapter 5 of the UniVerse System Description manual, and for a thorough example see the sample code which is included with <a href="http://www.ibm.com/developerworks/edu/dm-dw-dm-0802kumar-i.html" zid="189">Part 2 of IBM&#8217;s tutorial on the ADO.Net driver</a>.&nbsp; In the third part of this series, I will show an example of how you would use a JOIN clause in a SELECT statement to return the fields in the virtual table in the same record as the fields in the main table.<br zid="187"/><br zid="188"/>The advantage of this approach is that the resulting SQL statements will closely resemble those that would be used for a relational database, and this should make it easier to port your application from UniVerse to a relational database should you wish to.&nbsp; The downside is that it can become quite cumbersome to code when your records contain multivalued attributes that aren&#8217;t related on one another. For example, if a customer record contains a list of order numbers in attribute 1, and a list of customer contacts in attribute 2, you&#8217;ll have to specify a different association name for these 2 entries,&nbsp;and retrieve them using either a very complicated 3-way JOIN, or using 2 different SELECT statements. Also, since UniVerse does not offer any constraints or other mechanisms for enforcing the integrity of your data, you are likely to find that bad data fouls up your application, resulting in missing rows or runtime Exceptions.&nbsp; In our application, we use this approach only for small and simple tables.<br zid="61"/><br zid="70"/>ii) You can return the multivalued strings in their &quot;native&quot; form &#8212; strings with delimiters separating the values.&nbsp; You do this by using an I-type dictionary entry that converts the multivalue delimiter (ASCII 253) to whatever character you want.&nbsp; For example, to return attribute 1 with the multivalued fields delimited by commas:</p>
<pre class="brush: sql; title: ; notranslate">
   FIELD.LIST
001 I
002 CONVERT(@VM,',',@RECORD&amp;lt;1&gt;)
004 FIELD.LIST
005 50L
006 S
008 VARCHAR,32767
</pre>
<p>You might be wondering why you can&#8217;t just return the strings using the original delimiter, ASCII 253.&nbsp; For reasons known only to IBM, this results in a runtime exception. &nbsp;Incidentally, there is is a second type of delimiter which is also common in UniVerse, the subvalue delimiter (ASCII 252). &nbsp;UniVerse subvalues&nbsp; occur when the parts of a multivalued fields are, in turn, delimited into smaller fields.&nbsp; For reasons also known only to IBM, these are automatically converted by the ADO.NET driver to a carriage return and line feed (i.e. &quot;rn&quot;).&nbsp;&nbsp; IBM support has indicated that this delimiter conversion is actually a bug and will be changed back to ASCII 252 to a future Fix Pack.<br zid="190"/><br zid="195"/>Once you have the delimited string, you&#8217;ll need to use .Net&#8217;s string parsing capabilities to separate it into individual fields and convert the fields to their correct data type.&nbsp; You&#8217;ll find that .Net isn&#8217;t ideally suited for this type of string processing.&nbsp; UniVerse, on the other hand, is very much suited to it, and IBM provides a library named UniVerse Objects.Net that contains a variety of methods for extracting data from delimited strings.&nbsp; Frustratingly, your ability to use UniVerse Objects to parse your data is hampered by the fact that ADO.NET has forced you to replace all the multivalue and subvalue delimiters with other delimiters that UniVerse Objects doesn&#8217;t support.<br zid="192"/><br zid="193"/>If you decide to read UniVerse multivalued data in its native form, you might want to consider bypassing ADO.NET altogether and reading the data using UniVerse Objects.&nbsp; This is what our application does when dealing with tables that contain data that is mostly multivalued.&nbsp; It is much faster, and will likely require less code.<br zid="72"/><br zid="191"/>iii)&nbsp; While &quot;official&quot; UniVerse multivalued fields are delimited using ASCII 253 and 252, many UniVerse Basic programmers grow so fond of multivalues that they use them all over the place, with whatever delimiter character tickles their fancy.&nbsp; I&#8217;ve seen multivalued strings used as the primary key, and I&#8217;ve seen multivalued strings that contain embedded dates and time fields.&nbsp; While that kind of data structure would make SQL programmer cringe and a SQL database crawl, UniVerse is tuned to handle these strings efficiently and provides functions that you can insert in your dictionary to extract these fields relatively easily. <br zid="2"/><br zid="3"/>The trick is to place a correlative in attribute 8.&nbsp; Appendix C of the UniVerse Basic manual documents these correlatives, but be forewarned: they are cryptic enough to make a Perl programmer weep with frustration.&nbsp; Here are a couple of examples to get you started.<br zid="4"/><br zid="5"/>Say you had a key that was delimited with &quot;@&quot; signs.&nbsp; Just to make things interesting, say that one of the fields was a UniVerse Julian date, and another was a UniVerse Julian time.&nbsp; A typical key would be: FIRSTPART@14927@49055.75.<br zid="7"/><br zid="8"/>If you wanted to return the 1st part of the key (&quot;FIRSTPART&quot;) as a separate field in the SELECT statement, you could define it as follows in the UniVerse dictionary:</p>
<pre class="brush: sql; title: ; notranslate">
    THE.STRING
001 S
002 0
005 S
008 F;0;(G0@1)
009 L
010 20
</pre>
<p>The correlative in attribute 8 means &quot;take attribute 0 (the key), then split it into sections with &#8216;@&#8217; as the delimiter and return part 0&quot;.&nbsp; If you want all the gory details of what the &quot;F code&quot; can do, see Appendix C of the UniVerse Basic manual.&nbsp; <br zid="22"/><br zid="23"/>To return the date string as a date, you would use a similar &quot;F code&quot; string in attribute 8, along with a conversion code in attribute 7:</p>
<pre class="brush: sql; title: ; notranslate">
    THE.DATE
001 S
002 0
005 S
007 D2
008 F;0;(G1@1)
009 R
010 9
</pre>
<p>The time field is trickier &#8211; as mentioned above, the ADO.NET driver doesn&#8217;t like time fields with milliseconds.&nbsp; The best way to handle these fields is by putting the conversion code in attribute 8, but that&#8217;s where we need to put the correlative, and (as far as I know) you can&#8217;t put both a conversion code and a correlative in the same dictionary attribute.&nbsp; You can, however, combine 2 extract commands in a correlative:</p>
<pre class="brush: sql; title: ; notranslate">
	THE.TIME
001 S
002 0
005 S
007 MTS
008 F;0;(G2@1);(G0.1)
009 R
010 12
</pre>
<p>This correlative tells the database to extract the time field from the key and then, having done that, extract the part before the decimal point.&nbsp; The conversion code in attribute 7 then converts that value to a .Net TimeSpan. &nbsp;(The Universe Basic manual refers to this as &quot;<span style="font-style: italic;" zid="198">reverse Polish format (Lukasiewicz)</span>&quot; &#8212; how geeky is that?)<br zid="196"/><br zid="197"/>So, there you have it: an overview of the tricks that I&#8217;ve used to whip our UniVerse data into a form suitable for consumption by .Net.&nbsp; <br zid="199"/><br zid="200"/>If you are new to UniVerse, you are likely thinking at this point: &quot;um, so how do I edit a dictionary&quot;.&nbsp; As a crash course on UniVerse for Windows programmers, I would strongly recommend the &quot;<a href="http://212.241.202.162/cms/cmsview.wsp?id=learner_pack" zid="117">Learner Pack</a>&quot; put together by the U2 User Group.&nbsp; The UniVerse manuals are a well written, exhaustive reference when you are ready to dive deeper, but as a crash couse you can&#8217;t do better than the U2UG Learner Pack.<br zid="118"/><br zid="119"/>In third and final part of this series, I&#8217;ll show you the (relatively simple) coding required to load UniVerse data into a DataGridView using ADO.Net.<br zid="6"/><br zid="1"/></body></html></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2008/12/03/the-meaning-of-everything-universe-dictionaries-for-the-net-programmer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visual Studio and IBM UniVerse &#8211; Playing the Matchmaker</title>
		<link>http://www.gigamegablog.com/2008/11/25/visual-studio-and-ibm-universe-playing-the-matchmaker/</link>
		<comments>http://www.gigamegablog.com/2008/11/25/visual-studio-and-ibm-universe-playing-the-matchmaker/#comments</comments>
		<pubDate>Tue, 25 Nov 2008 23:05:39 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[UniVerse]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/2008/11/25/visual-studio-and-ibm-universe-playing-the-matchmaker/</guid>
		<description><![CDATA[It has been a couple of months since we switched database APIs for accessing our IBM U2 UniVerse database from .Net.&#160; We had a lot of reasons to leave UniOLEDB behind, and pretty high expectations from IBM&#8217;s new &#34;DB2 Client&#34; &#8230; <a href="http://www.gigamegablog.com/2008/11/25/visual-studio-and-ibm-universe-playing-the-matchmaker/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><html><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"></meta><meta content="text/html;charset=utf-8" http-equiv="Content-Type" id="metaid"></meta><meta content="pagewise" id="fntype"></meta><meta content="1-1" id="fnstyle"></meta><meta content="340" name="zid"><br />
<style id="styletagforeditor">body { border: 0px; font-family:verdana; font-size :10pt; direction :ltr; background-color :#ffffff; line-height :1.2; margin:0% 10% 0% 10%;}</style>
<style id="styletagtwoforeditor">table { font-size: 10pt;} p { margin-top:0px; margin-bottom:0px; }</style>
<link href="/styles/print.css" id="stylesheetforpreview" media="print" rel="stylesheet"></link>
<link href="/styles/print_preview.css" id="stylesheetforprintpreview" media="screen" rel="stylesheet"></link>
<link href="/styles/editor.css" id="stylesheetforeditor" rel="stylesheet"></link></meta></head><body>It has been a couple of months since we switched database APIs for accessing our <a href="http://www-01.ibm.com/software/data/u2/">IBM U2 UniVerse</a> database from .Net.&nbsp; We had a lot of reasons to leave UniOLEDB behind, and pretty high expectations from IBM&#8217;s new &quot;DB2 Client&quot; ADO.NET driver, but the 3 most important reasons behind the switch were:
<ol>
<li><span style="font-weight: bold;">Stability</span>.&nbsp; UniOLEDB&#8217;s intermittent &quot;memory is corrupt&quot; errors were driving me nuts.&nbsp; Upgrading the database server from UniVerse 10.1 to 10.2 improved UniOLEDB&#8217;s stability significantly, but switching to the ADO.NET driver has made things better still.&nbsp; Stability is no longer a concern &#8212; we&#8217;ve had no problems with dropped connections or failed queries.</li>
<p><br zid="189"/>
<li><span style="font-weight: bold;">Deployment</span>.&nbsp; UniOLEDB&#8217;s archaic install program was driving our clients&#8217; IT guys nuts.&nbsp; The fact that UniOLEDB had to be installed by manually on each desktop was a dealbreaker for the larger sites.&nbsp; The DB2 Client&#8217;s installation program has its own quirks,  <a href="http://gigamegablog.com/2008/10/01/silent-but-exasperating-automated-install-of-the-ibm-db2-client/">as I wrote about here</a>, but once we figured out the trick our clients have had no problems rolling it out with automated tools like Microsoft Systems Management Server.</li>
<p><br zid="190"/>
<li><span style="font-weight: bold;">Productivity</span>.&nbsp; The ability to have Visual Studio treat UniVerse like a full-fledged database would make it a lot easier to developer new forms.&nbsp; With UniOLEDB we had to laboriously handcraft the DataAdapters for each table: write the SELECT, INSERT, UPDATE and DELETE statements, set their parameters, use them to construct the DataAdapter, then write the code to populate and manage the DataSet tables.&nbsp; That was a lot of code, and we have a lot of tables!&nbsp; Wouldn&#8217;t it be nice to replace all of that with a simple drag-and-drop?</li>
</ol>
<p>Well, 2 out of 3 ain&#8217;t bad.<br zid="192"/><br zid="193"/>We haven&#8217;t quite reached that third goal yet.&nbsp;&nbsp;We&#8217;ve got a relatively messy UniVerse database: our master dictionary and most of our data dictionaries are littered with references to things that don&#8217;t exist or aren&#8217;t correctly defined.&nbsp; UniVerse itself ignores these obsolete entries, but it seems that the DB2 Client dutifully tries to make sense of them, each and every time that we connect.<br zid="192"/><br zid="193"/>As a result, any attempt to access a table through the Visual Studio IDE, be it from the Server Explorer or the Data Sources window, is painfully slooooooow. &nbsp; I have an idea for doing an end-run around this problem, and when I have time to pursue it I&#8217;ll write a blog post describing what I did and how it turned out.<br zid="194"/><br zid="195"/>But, for now, drag and drop isn&#8217;t an option.<br zid="196"/><br zid="197"/> Our internal developers are still accessing UniVerse data through a labour-intensive code-based approach, without using the Server Explorer or Data Sources IDE at all.&nbsp; That&#8217;s fine for us, since we&#8217;ve built a framework to support it, but when I was recently asked to help a client&#8217;s .Net developers get to our data, I knew I had to give them something easier.<br zid="198"/><br zid="199"/>My boss assured them that once they had the UniVerse 10.2 and its new IBM ADO.NET driver, UniVerse would be as easy to use as SQL Server.&nbsp; Heck, we&#8217;d even create Views for the data they want.<br zid="200"/><br zid="201"/>Well, not so fast.&nbsp; Even with an ADO.NET driver, UniVerse doesn&#8217;t support Views. There&#8217;s a node called &quot;Views&quot; sitting under the UniVerse data connection in Visual Studio&#8217;s Server Explorer, but it will always remain forlornly barren. &nbsp;There is simply no equivalent entity in the world of UniVerse.<br zid="202"/><br zid="203"/>When I asked IBM about this, they recommended using UniVerse subroutines instead.&nbsp; These are regarded by the ADO.NET driver as stored procedures, meaning that they can be viewed and invoked from the Server Explorer under the Procedures node. &nbsp; You can use them with Visual Studio&#8217;s Data Source Configuration Wizard to create DataSets and DataAdapters without having to write any code.<br zid="204"/><br zid="205"/>Pretty nifty, and that&#8217;s something you couldn&#8217;t do with UniOLEDB.&nbsp; (Predictably, it would throw up a &quot;memory is corrupted&quot; error if you tried).&nbsp; But the subroutines are written in dowdy old UniVerse Basic, and our clients&#8217; developers didn&#8217;t want to go there.&nbsp; They opted for SQL.<br zid="206"/><br zid="207"/>Running SQL SELECT statements against a UniVerse database is a lot easier with the new ADO.NET driver, but it&#8217;s still tricky, with quite a few pitfalls that aren&#8217;t mentioned in IBM&#8217;s tutorials or (as far as I know) anywhere else.<br zid="208"/><br zid="209"/>So, having just played matchmaker between UniVerse and some .Net developers, I thought it might be useful to describe the quickest path to getting your UniVerse data into a .Net grid.<br zid="210"/><br zid="211"/>My next post will describe what needs to be done to prepare the UniVerse dictionaries for .Net, and the following post will show how to create UniVerse-friendly SELECT statements and feed the results into a DataGridView.</body></html></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2008/11/25/visual-studio-and-ibm-universe-playing-the-matchmaker/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Silent But Exasperating: Automated Install of the IBM DB2 Client</title>
		<link>http://www.gigamegablog.com/2008/10/01/silent-but-exasperating-automated-install-of-the-ibm-db2-client/</link>
		<comments>http://www.gigamegablog.com/2008/10/01/silent-but-exasperating-automated-install-of-the-ibm-db2-client/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 23:24:17 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/2008/10/01/silent-but-exasperating-automated-install-of-the-ibm-db2-client/</guid>
		<description><![CDATA[Having made the leap over to IBM&#8217;s new &#34;DB2 Client&#34; ADO.Net driver for the U2 UniVerse database, we recently spent some time figuring out how to get it onto users&#8217; PCs.&#160; This turned out to be harder than I expected, &#8230; <a href="http://www.gigamegablog.com/2008/10/01/silent-but-exasperating-automated-install-of-the-ibm-db2-client/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><html><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"></meta><meta content="text/html;charset=utf-8" http-equiv="Content-Type" id="metaid">
<link href="/styles/editor.css" id="stylesheetforeditor" rel="stylesheet"></link>
<link href="/styles/print.css" id="stylesheetforpreview" media="print" rel="stylesheet"></link>
<link href="/styles/print_preview.css" id="stylesheetforprintpreview" media="screen" rel="stylesheet">
<style id="styletagforeditor">body { border: 0px; font-family:verdana; font-size :10pt; direction :ltr; background-color :#ffffff; line-height :1.2; margin:0% 10% 0% 10%;}</style>
<style id="styletagtwoforeditor">table { font-size: 10pt;} p { margin-top:0px; margin-bottom:0px; }</style>
<p><meta content="pagewise" id="fntype"></meta><meta content="1-1" id="fnstyle"></meta><meta content="86" name="zid"></meta></link></meta></head><body>Having <a href="http://gigamegablog.com/2008/09/16/u2-and-adonet-relatively-relational/" zid="35">made the leap</a> over to IBM&#8217;s new <a href="http://www-01.ibm.com/software/data/db2/support/db2_9/download.html" zid="36">&quot;DB2 Client&quot; ADO.Net driver</a> for the <a href="http://www-01.ibm.com/software/data/u2/" zid="37">U2 UniVerse database</a>, we recently spent some time figuring out how to get it onto users&#8217; PCs.&nbsp; This turned out to be harder than I expected, and harder than it should be.<br zid="4"/><br zid="5"/>The new Data Client&#8217;s installer was actually a big selling point for us.&nbsp; The previous database driver, UniOLEDB, used a proprietary install program that didn&#8217;t support automated, silent installs.&nbsp; This means that someone from the user&#8217;s IT department had to visit each user&#8217;s desktop and 1) launch the install program, 2) click Next a bunch of times, 3) phone us and complain about how annoying this is.&nbsp; Every install program that we&#8217;ve created or incorporated into our product for the last 10 years has supported silent installs, except this one.&nbsp;&nbsp;<br zid="6"/><br zid="7"/>I was so giddy at the prospect of moving on to a proper installer that I assured our clients that we would now fully support silent installs without (ahem) actually trying to do one.&nbsp; My optimism was based on the fact that 1) the new database client uses the same installer as IBM&#8217;s flagship database, DB2, 2) this installer was created using one of the industry standard tools, InstallShield, which has supported silent installs for ages, and 3) the <a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/index.jsp" zid="85">DB2 Information Center</a>&#8216;s extensive documentation includes a section entitled &quot;<a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/topic/com.ibm.swg.im.iis.prod.install.core.doc/topics/iiypisco-silent.html" zid="86">Silent Installation</a>&quot;.&nbsp; It sure looks easy when you read about it.<br zid="8"/><br zid="9"/>Unfortunately, it doesn&#8217;t quite work the way it&#8217;s described, and finding the specifics required quite a lot of Googling as well as some trial and error.&nbsp; <br zid="10"/><br zid="11"/>Here&#8217;s what doesn&#8217;t work:<br zid="38"/><br zid="12"/>1) Installing without a response file.&nbsp; This will launch the installer, but it will quickly abort, and the error message written to the log is enigmatic:<br zid="40"/><br zid="74"/><span style="font-family: courier new,courier,monospace;" zid="79">Action ended 20:06:46: DB2SetDB2INSTANCECA.2BC48F01_561E_4906_8321_946A9F5A90AA. Return value 3.</span><br style="font-family: courier new,courier,monospace;" zid="80"/><span style="font-family: courier new,courier,monospace;" zid="81">Action ended 20:06:46: INSTALL. Return value 3.</span><br style="font-family: courier new,courier,monospace;" zid="82"/><span style="font-family: courier new,courier,monospace;" zid="83">MSI (s) (E4:68) [20:06:46:607]: Product: IBM Data Server Runtime Client &#8211; DB2COPY1 &#8212; Configuration failed.</span><br /><br zid="84"/>Presumably, the response file is mandatory.<br zid="39"/><br zid="17"/>2) The standard InstallShield command line switch for generating a response file in the Windows folder (-r).&nbsp; I never thought that the Windows folder was a great place to put it &#8212; apparently IBM agrees.<br zid="56"/><br zid="13"/>3) The <a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/topic/com.ibm.db2.luw.qb.server.doc/doc/c0007508.html" zid="58">Response File Generator utility</a> (db2rspgn).&nbsp; Although this utility does, indeed, generate a response file, we had absolutely no luck when trying to use this response file to do an install.&nbsp; Googling the problem suggested that many others had the same result, but I still have no idea what the solution is, if any. <br zid="57"/><br zid="14"/>4) Manually editing one of the sample response files, <a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/topic/com.ibm.swg.im.iis.prod.install.core.doc/topics/iiypisco-silent.html" zid="15">as suggested by the Information Center</a>, might have worked if we actually had a sample response file.&nbsp; The sample response files are apparently located on the <span class="filepath" zid="59"></span><span zid="60">&quot;Information Integration Product DVD&quot;, but I&#8217;ve never seen such a beast.</span><br zid="18"/><br zid="19"/>Here&#8217;s what does work:<br zid="61"/><br zid="20"/>1) Run the installer normally (with no command line switches), then look in your %TEMP% folder.&nbsp; Sure, enough, there&#8217;s a .rsp file left behind in there.&nbsp; <br zid="62"/><br zid="21"/>2) This response file works just fine with the standard InstallShield parameters for a silent install.&nbsp; For the current version of the DB2 runtime client, this is :<br zid="63"/><br zid="64"/>v9.5fp2_nt32_rtcl_en.exe /v&quot;/qn RSP_FILE_PATH=&lt;path of the .rsp file&gt;.<br zid="22"/><br zid="24"/>The contents of the elusive response file are somewhat of a letdown.&nbsp; Unless you need to install 2 different versions of the database drivers, you&#8217;re unlikely to ever want to change a thing. &nbsp; Should you not have an Information Integration Product DVD at hand, feel free to use our response file as a sample:</p>
<pre class="brush: csharp; title: ; notranslate">
PROD=RUNTIME_CLIENT
INSTALL_TYPE=TYPICAL
DB2_COPY_NAME=DB2COPY1
DEFAULT_COPY=YES
DEFAULT_CLIENT_INTERFACE_COPY=YES
DEFAULT_INSTANCE=DB2
INSTANCE=DB2
DB2.NAME=DB2
LIC_AGREEMENT=ACCEPT
</pre>
<p></body></html></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2008/10/01/silent-but-exasperating-automated-install-of-the-ibm-db2-client/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>U2 and ADO.Net: Relatively Relational</title>
		<link>http://www.gigamegablog.com/2008/09/16/u2-and-adonet-relatively-relational/</link>
		<comments>http://www.gigamegablog.com/2008/09/16/u2-and-adonet-relatively-relational/#comments</comments>
		<pubDate>Tue, 16 Sep 2008 19:36:42 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/2008/09/16/u2-and-adonet-relatively-relational/</guid>
		<description><![CDATA[I come to bury UniOLEDB; not to praise it.Which won&#8217;t be a big surprise if you&#8217;ve seen by previous whining and kvetching on the subject.At the time we adopted UniOLEDB, it was only ADO.Net-compatible driver for our IBM U2 UniVerse &#8230; <a href="http://www.gigamegablog.com/2008/09/16/u2-and-adonet-relatively-relational/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><html><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"></meta><meta content="text/html;charset=utf-8" http-equiv="Content-Type" id="metaid"></meta><meta content="pagewise" id="fntype"></meta><meta content="1-1" id="fnstyle"></meta><meta content="340" name="zid"><br />
<style id="styletagforeditor">body { border: 0px; font-family:verdana; font-size :10pt; direction :ltr; background-color :#ffffff; line-height :1.2; margin:0% 10% 0% 10%;}</style>
<style id="styletagtwoforeditor">table { font-size: 10pt;} p { margin-top:0px; margin-bottom:0px; }</style>
<link href="/styles/print.css" id="stylesheetforpreview" media="print" rel="stylesheet"></link>
<link href="/styles/print_preview.css" id="stylesheetforprintpreview" media="screen" rel="stylesheet"></link>
<link href="/styles/editor.css" id="stylesheetforeditor" rel="stylesheet"></link></meta></head><body> I come to bury UniOLEDB; not to praise it.<br zid="208"/><br zid="209"/>Which won&#8217;t be a big surprise if you&#8217;ve seen by previous <a href="http://gigamegablog.com/2007/10/31/on-u2-and-net/" zid="210">whining</a> and <a href="http://gigamegablog.com/2008/05/26/unioledb-performance-optimization-hits-and-misses/" zid="211">kvetching</a> on the subject.<br zid="202"/><br zid="203"/>At the time we adopted UniOLEDB, it was only ADO.Net-compatible driver for our <a href="http://www-01.ibm.com/software/data/u2/">IBM U2</a> UniVerse database, other than some third party products with expensive runtime licenses.&nbsp; UniOLEDB was never widely used in the U2 developer community, with preference given instead to the venerable but decidedly non-relational UniObjects.Net API.&nbsp; <br zid="212"/><br zid="213"/>UniOLEDB does work &#8212; our app has been running live on it for 9 months with decent reliability and performance. &nbsp;However, in my experience UniOLEDB had a few significant drawbacks, in descending order of priority:<br zid="4"/><br zid="5"/>1) It is not reliable when updating the database: INSERT and UPDATE commands would often complete without any error message but leave some fields untouched.&nbsp; We never could find a pattern to this problem (it was more common with dates and numeric fields, but would also occur with plain vanilla strings), and IBM support wasn&#8217;t able to recreate it.&nbsp; I reluctantly decided to use UniObjects for all database updates, thus giving up some of the advantages of ADO.Net.<br zid="6"/><br zid="7"/>2) It has an alarming tendency to raise a &quot;protected memory&quot; error &#8212; alarming both because of the panic-inducing but (as far as I can tell) totally misleading wording of the error message, and because it is quite frequent.&nbsp; Most users of our system will encounter this error a few times each day (though, needless to say, we replaced the error message text with something less worrisome).&nbsp; I never found a workaround for this.<br zid="214"/><br zid="215"/><img align="baseline" alt border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=305886000000065001/1221519351978_MemoryIsCorruptError.png&#038;accId=305886000000002007" vspace="0" zid="216"/><br zid="8"/><br zid="9"/>3) It doesn&#8217;t play nicely with Visual Studio&#8217;s design-time database tools.&nbsp; If you use the Add Data Connection wizard to add a UniOLEDB database to Visual Studio you&#8217;ll promptly be greeted with the aforementioned &quot;protected memory&quot; error, and be unable to use the Data Connections tool to graphically view the database&#8217;s tables and fields.&nbsp; (You can, however, type in SQL statements and view their results).<br zid="10"/><br zid="11"/>4) For us, at least, it doesn&#8217;t work well with the latest version of UniVerse, 10.2.&nbsp; Our app would frequently encounter &quot;Native error: 930065&quot; exceptions &#8212; the error code indicates that the maximum number of database licenses has been reached, but it would occur randomly and with no apparent connection to license usage.&nbsp; IBM&#8217;s tech support was not able to recreate this problem, either, and though they tried adding patches in various point upgrades to 10.2, none of the patches worked for us.<br zid="22"/><br zid="23"/>5) In order to make the non-relational UniVerse database accessible to a relational database driver, a large amount of effort must be spent tinkering with the UniVerse data dictionary trying to map out the data.&nbsp; Even then, you&#8217;ll almost certainly end up with some parts of the database that UniOLEDB can&#8217;t read without resorting to the native UniVerse delimited string format.&nbsp; I list this as the least of the problems only because it&#8217;s one that I never really expected UniOLEDB to solve.&nbsp; As Barack Obama might say, &quot;you can put lipstick on a multivalue database, but it&#8217;s still a multivalue database&quot;.&nbsp; (No, not you, Sarah &#8212; I&#8217;m talking about UniVerse).<br zid="206"/><br zid="207"/>Late in 2007 IBM finally released a native ADO.Net driver for U2 which, for lack of a better name, I&#8217;ll refer to as &quot;the ADO.Net driver&quot;. (Not very ingenious, I admit, but inarguably a better name than IBM&#8217;s.&nbsp; Depending on where you look, IBM refers to it as the &quot;IBM Data Server Provider for .NET&quot;, or the &quot;IBM Data Server Client&quot; or the &quot;DB2 9.5 Client&quot;. <br zid="18"/><br zid="19"/>This driver, when combined with a separate piece of software called the &quot;IBM Database Add-Ins for Visual Studio&quot;, was primarily targeted at addressing the third of the above problems. However, given that U2 is a very small fish in IBM&#8217;s large database pond, I found it particularly reassuring to see that this is part of a unified driver which also covers their flagship DB2 product along with the database business they bought from Informix.&nbsp; Since this driver was, on the client side, a complete rewrite when compared to UniOLEDB,&nbsp;I was pretty confident that it would also fix the fourth problem, and somewhat optimistic about finally solving the first two.<br zid="14"/><br zid="15"/>About a month ago we finally found time in the project timetable to begin porting our UniOLEDB code to the ADO.Net driver.&nbsp; Since the new driver is fully supported only in UniVerse 10.2, and all of our user sites are still on 10.1, we have to support both UniOLEDB and ADO.Net for the time being.&nbsp; So, I was hoping that the conversion would require relatively few changes to our code.&nbsp; <br zid="16"/><br zid="17"/>I&#8217;m pleased to report that it was a pretty simple conversion.&nbsp; On the server side, ADO.Net requires the same dictionary entries as UniOLEDB (and ODBC before it), so there was virtually nothing to be done within the database itself.&nbsp; On the client side, a new namespace is required, IBM.Data.DB2.&nbsp; In this namespace are &quot;DB2&quot;-specific replacements on a one-for-one basis for the OLEDB objects, such as connections, data adapters and parameters. &nbsp;After making these 1-for-1 substitutions, almost all of our code &quot;just worked&quot;. We retested every SQL statement in the application and found only two compatibility problems between UniOLEDB and the ADO.Net driver, as described below.<br zid="24"/><br zid="25"/>Here&#8217;s a blow-by-blow description of what we needed to do to port UniOLEDB to ADO.Net:<br zid="26"/><br zid="27"/>1.&nbsp; Download and install the ADO.Net client software. This step is actually incredibly difficult, thanks to IBM&#8217;s byzantine web site.&nbsp; Currently the right page to use is <a href="http://www-01.ibm.com/software/data/db2/support/db2_9/download.html" zid="217">http://www-01.ibm.com/software/data/db2/support/db2_9/download.html</a>, &nbsp;and the file you are looking for is the &quot;IBM Data Server Driver for<br zid="218"/>ODBC, CLI, and .NET&quot; (as opposed to the &quot;IBM Data Server Client&quot; or the &quot;IBM Data Server Runtime Client&quot;).&nbsp; The file is named v9.5fp2_nt32_dsdriver_EN.exe (where fp2 refers to Fix Pack 2).&nbsp; The Visual Studio Add-In is somewhat easier to spot, and is named v9.5fp2_nt32_vsai.exe.&nbsp; Once you have the files, I&#8217;d strongly recommend that you use IBM&#8217;s excellent series of tutorials (Parts <a href="http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0711kumar/?S_TACT=105AGX11&#038;S_CMP=TUT" zid="219">one</a>, <a href="http://www.ibm.com/developerworks/edu/dm-dw-dm-0802kumar-i.html" zid="220">two</a> and <a href="http://www.ibm.com/developerworks/edu/dm-dw-dm-0805else-i.html" zid="221">three</a>) to walk you through installation and configuration, and to familiarize yourself with what the new driver can do.<br zid="43"/><span style="font-size: 12pt; font-family: &quot;Times New Roman&quot;;" zid="35"><br zid="44"/></span>2. OK, back to your code.&nbsp; As the tutorial explains, you&#8217;ll need to add a reference to your project to IBM.Data.DB2.dll in order to get the IBM.Data.DB2 namespace.&nbsp; Naturally, you&#8217;ll need to declare this namespace (e.g. &quot;using IBM.Data.DB2&quot;) at the top of your source code, along with System.Data.Common.&nbsp; You should be able to remove the &quot;System.Data.OleDB&#8217; declaration.<br zid="45"/><br zid="46"/>3. Replace the OleDBConnection object with a DbConnection object.<br zid="47"/><br zid="48"/>4. Replace the OLEDB Connection string parameters with those used by the DbConnection object.&nbsp; You&#8217;ll need to add a new &quot;ServerType&quot; parameter and set to to &quot;Universe&quot; (since IBM&#8217;s unified ADO.Net driver wouldn&#8217;t otherwise have any idea that you want to use a UniVerse database).&nbsp; Since connection pooling is turned on by default, unless you have a UniVerse license that supports pooling you&#8217;ll also have to add a parameter to turn it off: set &quot;Pooling&quot; to &quot;false&quot;.&nbsp; A couple of other connection string parameters, for the server and database, now have new names.&nbsp; When all is said and done, you should have a connection string that looks like this:<br zid="49"/><br zid="50"/></p>
<pre class="brush: csharp; title: ; notranslate">
string strConn = @&quot;User ID=JoeUser;Password=HisPassword;Database=c:accountpath;Server=ourserver;ServerType=universe;pooling=false&quot;;
</pre>
<p>Incidentally, you can now do away with the cryptic &quot;uci.config&quot; initialization file used by UniOLEDB.&nbsp; The ADO.Net driver does not require any configuration beyond what is in the code.&nbsp; Welcome to the 21st century!<br zid="60"/><br zid="37"/>5. Certain OleDB database objects need to be replaced with their ADO equivalents.&nbsp; Note that the syntax for DataReaders, Commands and Parameters is quite similar, with the main difference being that the ADO objects don&#8217;t have their own constructors.&nbsp; The DataAdapter, on the other hand, requires considerably more code to create using the ADO.Net driver:
<ul zid="89">
<li zid="65">OleDbCommand is now DbCommand</li>
</ul>
<pre class="brush: csharp; title: ; notranslate">
// UniOLEDB
public static OleDbCommand DB_GetCommand(string strSQL)
{
    OleDbCommand cmd = new OleDbCommand(strSQL, conn);
    return cmd;
}

// ADO.Net
public static DbCommand DB_GetCommand(string strSQL)
{
    DbCommand cmd = conn.CreateCommand();
    cmd.CommandText = strSQL;
    cmd.CommandType = CommandType.Text;
    return cmd;
}
</pre>
<ul zid="62">
<li zid="63">OleDbDataReader is now DbDataReader </li>
</ul>
<pre class="brush: csharp; title: ; notranslate">
// UniOLEDB:
public static DbDataReader DB_GetReader(string strSQL)
{
    OleDbCommand cmd = new OleDbCommand(strSQL, conn);
    DbDataReader rdr = cmd.ExecuteReader();
    return rdr;
}

// ADO.Net:
public static DbDataReader DB_GetReader(string strSQL)
{
    DbCommand cmdSQL = conn.CreateCommand();
    cmdSQL.CommandText = strSQL;
    cmdSQL.CommandType = CommandType.Text;
    DbDataReader rdr = cmdSQL.ExecuteReader();
    return rdr;
}
</pre>
<ul zid="121">
<li zid="68">OleDbDataAdapter is now DbDataAdapter</li>
</ul>
<pre class="brush: csharp; title: ; notranslate">
// UniOLEDB:
public static OleDbDataAdapter DB_GetAdapter()
{
    return new OleDbDataAdapter();
}

// ADO.Net:
public static DbDataAdapter DB_GetAdapter()
{
    DbProviderFactory factory = DbProviderFactories.GetFactory(&quot;IBM.Data.DB2&quot;);
    DbDataAdapter adapter = factory.CreateDataAdapter();
    return adapter;
}
</pre>
<ul zid="146">
<li zid="147">OleDbType is now Db2Type (since we needed to support both UniOLEDB and ADO.Net, I changed our code to use the generic DbType enum and added conversion methods for the types that we use):</li>
</ul>
<pre class="brush: csharp; title: ; notranslate">
// UniOLEDB:
public static OleDbType DB_GetOleDbType(DbType type)
{
    switch (type)
    {
        case DbType.Date:
            return OleDbType.DBDate;
        case DbType.Decimal:
            return OleDbType.Decimal;
        case DbType.String:
            return OleDbType.VarChar;
        case DbType.Int32:
            return OleDbType.Integer;
    }
}       

// ADO.Net:
private static DB2Type DB_GetDB2Type(DbType type)
{
    switch (type)
    {
        case DbType.Date:
            return DB2Type.Date;
        case DbType.Decimal:
            return DB2Type.Decimal;
        case DbType.String:
            return DB2Type.VarChar;
        case DbType.Int32:
            return DB2Type.Integer;
    }
}
</pre>
<ul zid="135">
<li zid="71">OleDbParameter is now DbParameter</li>
</ul>
<pre class="brush: csharp; title: ; notranslate">
// UniOLEDB:
public static void DB_AddParameter(OleDbCommand cmd, string strName, DbType type, int intSize, string strSourceColumn)
{
    OleDbType oleDbType = DB_GetOleDbType(type);
    cmd.Parameters.Add(strName, oleDbType, intSize, strSourceColumn);
}       

// ADO.Net:
public static void DB_AddParameter(DbCommand cmd, string strName, DbType type, int intSize, string strSourceColumn)
{
    DB2Type db2Type = DB_GetDB2Type(type);
    DbParameter param = new DB2Parameter(strName, db2Type, intSize, strSourceColumn);
    cmd.Parameters.Add(param);
}
</pre>
<p>6. Once all of the tedious but straight-forward &quot;a Quarter Pounder with Cheese is now a Royale with Cheese&quot; stuff is out of the way, you should find that the two drivers speak pretty much the same language and not many other code changes are required. When we fired up the app and tried out our SQL statements, we only found two cases where the same statement didn&#8217;t return the same data:<br zid="192"/><br zid="193"/>a. Subvalue markers (ASCII 252) are returned by the ADO.Net driver as carriage-return/line-feed (&quot;/r/n&quot;). &nbsp;Subvalues are a method used by UniVerse to stuff 3 levels of data into a single field: if a multivalued field can be thought of as representing a parent-child table relationship, then subvalues can be thought of as parent-child-grandchild.&nbsp; We don&#8217;t use them much, and it seems that most other developers don&#8217;t either, since IBM support wasn&#8217;t aware of this when I reported it to them.&nbsp; However, IBM intends to resolve this problem in Fix Pack 3.<br zid="194"/><br zid="195"/>b. The ADO.Net driver doesn&#8217;t support use of the virtual &quot;@ASSOC_ROW&quot; field in SQL statements.&nbsp; The UniOLEDB driver stored a row number in this field when converting a multivalued field into multiple virtual rows.&nbsp; SQL statements that rely on row numbers are almost certainly not a good idea in any database &#8212; you should be able to rewrite the SQL to avoid using them.<br zid="196"/><br zid="225"/><br zid="197"/>And there you have it &#8212; with a relatively small and straightforward set of code changes, you&#8217;re now accessing your UniVerse data with a true-blue ADO.Net driver.&nbsp; <br zid="198"/><br zid="199"/>As for the set of problems listed at the top of this article, I can report that the new driver solves problems #2 and #4.&nbsp; I haven&#8217;t tried doing database updates with ADO.Net yet, so I can&#8217;t say if problem #1 is solved.&nbsp; I noticed that IBM&#8217;s series of tutorials for the new driver recommends that database subroutines (written in UniVerse Basic) be used to handle updates, so I plan to stick to using UniObjects for the time being.&nbsp; <br zid="200"/><br zid="201"/><img align="right" alt border="0" hspace="3" src="http://writer.zoho.com:80/ImageDisplay.im?name=305886000000065001/1221524307573_ItMayTakeAWhile.png&#038;accId=305886000000002007" vspace="8" zid="226"/>We haven&#8217;t completely cracked problem #3 yet, partly because of the unavoidable &quot;multivalued database with lipstick&quot; issue.&nbsp; The Visual Studio add-in works great with the sample HS.SALES account, and every crusty old UniVerse Basic programmer that I&#8217;ve showed it too is quite surprised to see a graphical database design tool that works with UniVerse.&nbsp; Unfortunately, when we tried accessing our real world database we ran into a serious performance problem. &nbsp;HS.SALES has 749 entries in its master dictionary &#8212; our database has over 5 thousand.&nbsp; As a result, it took Visual Studio a few minutes to enumerate all of our schema objects.&nbsp; A few minutes might not seem so bad, but this enumeration is done not only when the database&#8217;s object tree is first displayed, but each and every time a new query is created from the Data Connection.&nbsp; It&#8217;s really cramping our style!<br zid="223"/><br zid="224"/>However, there is hope that Visual Studio and UniVerse can now get along.&nbsp; IBM provides a few different ways to filter the number of schema objects that are available to Visual Studio, and we&#8217;ll be trying out those methods in the future.&nbsp; I&#8217;ll write about that in a future article.<br zid="77"/></body></html></p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2008/09/16/u2-and-adonet-relatively-relational/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>UniOLEDB Performance Enhancements &#8211; Bullseye!</title>
		<link>http://www.gigamegablog.com/2008/06/02/unioledb-performance-enhancements-bullseye/</link>
		<comments>http://www.gigamegablog.com/2008/06/02/unioledb-performance-enhancements-bullseye/#comments</comments>
		<pubDate>Tue, 03 Jun 2008 03:15:21 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/2008/06/02/unioledb-performance-enhancements-bullseye/</guid>
		<description><![CDATA[My last post described various attempts to improve the response time of a large SELECT statement from a very large table in IBM Universe. I&#8217;m pleased to report that we finally found the trick, though it turned out to having &#8230; <a href="http://www.gigamegablog.com/2008/06/02/unioledb-performance-enhancements-bullseye/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>My <a href="http://gigamegablog.com/2008/05/26/unioledb-performance-optimization-hits-and-misses/">last post</a> described various attempts to improve the response time of a large SELECT statement from a very large table in IBM Universe.  I&#8217;m pleased to report that we finally found the trick, though it turned out to having nothing to do with .Net and very little with UniOLEDB.</p>
<p>As mentioned at the end of my last post, my effort to optimize the SELECT statement by changing the .Net code had topped out around the 5 minute mark, well short of the 45-second response time that a query written in Universe Basic could achieve.  I couldn&#8217;t see any way that .Net and UniOLEDB could replicate the technique used by the Universe Basic code, which involved building a native List structure from the keys, using a native Universe Basic command to extract the matching records from the large table, then running the SELECT on just the extracted records.</p>
<p>Fortunately my .Net code didn&#8217;t have to replicate this technical trickery; it could just stand back and let the Universe Basic code do the heavy lifting.  Thanks to the fact that Universe Basic subroutines can return resultsets to .Net, I simply passed my SELECT statement to our Universe Basic code, let it do its thing, and processed the results.</p>
<p><span style="font-family: courier new,courier,monospace">                OleDbCommand cmdTest = new OleDbCommand(â€CALL GET.RECORDSET(&#8216;SELECT yada yada yada&#8217;)â€³, conn);</span><br style="font-family: courier new,courier,monospace" /><span style="font-family: courier new,courier,monospace">                cmdTest.CommandType = CommandType.Text;</span><br style="font-family: courier new,courier,monospace" /><span style="font-family: courier new,courier,monospace">                dataAdapter = new OleDbDataAdapter(cmdTest);</span><br style="font-family: courier new,courier,monospace" /><span style="font-family: courier new,courier,monospace">                dataAdapter .Fill(dataSet, &#8220;Table1&#8243;);</span></p>
<p>From the point of view of the .Net application this change is totally transparent &#8212; the contents of the resultset are exactly the same as when my code submitted its own SELECT statement.  The Universe Basic subroutine had to be modified to extract the table name and key list from the SELECT statement, and it has since worked flawlessly in our testing, without stumbling over any rows or column types.</p>
<p>This turned out to be quite a good overall solution: virtually no .Net code changes, about half-a-day of coding for the Universe Basic programmer, and since the .Net code still uses SQL we maintained close compatibility with other databases.  If we were to replace Universe with a relational database, I would just have to change a couple of lines of code in the .Net application.</p>
<p>The performance improvement when reading large amounts of data from the very large table was dramatic: from a previous best of 310 seconds down to just 45.  Performance is slightly poorer than before on smaller SELECTs, but not enough to be noticeable to the user.</p>
<p>I&#8217;m a little disappointed that we couldn&#8217;t find a solution that only used .Net code. We already had to replace our INSERTs, UPDATEs and DELETEs with Universe-specific code as described in <a href="http://gigamegablog.com/2007/10/31/on-u2-and-net/">this post</a>, and now the last facade of seamless SQL support has fallen.  However, it was probably naive to think that we could transparently run SQL statements on a non-relational database like Universe.  When in Rome, do as the Romans do.  An appropriate axiom, considering that the Universe database is almost ancient history!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2008/06/02/unioledb-performance-enhancements-bullseye/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>UniOLEDB Performance Optimization: Hits and Misses</title>
		<link>http://www.gigamegablog.com/2008/05/26/unioledb-performance-optimization-hits-and-misses/</link>
		<comments>http://www.gigamegablog.com/2008/05/26/unioledb-performance-optimization-hits-and-misses/#comments</comments>
		<pubDate>Tue, 27 May 2008 03:29:24 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/2008/05/26/unioledb-performance-optimization-hits-and-misses/</guid>
		<description><![CDATA[Having made some progress on the .Net memory usage issue, my UniOLEDB application&#8217;s biggest performance problem is now the time required to retrieve large amounts of data from the Universe database. After working on this with Universe&#8217;s tech support team &#8230; <a href="http://www.gigamegablog.com/2008/05/26/unioledb-performance-optimization-hits-and-misses/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Having made some progress on the <a href="http://gigamegablog.com/2008/04/28/reducing-memory-usage-in-net-apps/">.Net memory usage</a> issue, my UniOLEDB application&#8217;s biggest performance problem is now the time required to retrieve large amounts of data from the Universe database.  After working on this with Universe&#8217;s tech support team for a couple of weeks I was hoping I&#8217;d be able to post a list of performance optimization tips, but I&#8217;ll have to settle for a list of tips which might help in your case, but didn&#8217;t do a whole lot for us.</p>
<p>First, let me define &#8220;large amounts of data&#8221;.  There is a grid in the application which lists media buys in a campaign &#8212; one row per &#8220;airing&#8221;.  A campaign often has hundreds of thousands of airings, and millions of airings isn&#8217;t unheard of.  In order to populate the grid the application may need to read tens of thousands of Universe records.  Due to the multi-valued nature of a Universe record, each of these contains sets of up to 100 subvalues, roughly equivalent to a 1-to-many relationship to another table.  The table from which this data is being retrieved contains billions of records &#8211; we ran our benchmarks with a table that was 11G in size and contained 11.6 billion records.  Because this table only has one index, the primary key, the fastest way to retrieve records is by listing each and every key in the WHERE clause.  The resulting SELECT statement is massive.  The one which I used when benchmarking contained over 29 thousand keys in the WHERE clause and was 740K in size.  Not the data, but the SELECT statement &#8212; 740K of text!</p>
<p>Given all this, I wasn&#8217;t terribly surprised that, prior to optimization, UniOLEDB performance was pretty poor.  The first time I tried it, the 29,000-key SELECT statement required about 12 minutes to run.</p>
<p>From the .Net application&#8217;s point of view, this 12 minutes was spent waiting for 1 instruction to complete:</p>
<p><span style="font-family: courier new,courier,monospace">            dataAdapter.Fill(dataSet);</span></p>
<p>Aside from the time spent transferring the data from the server to the desktop, which appears to be about 20 seconds based on the server and desktop CPU activity, all of this time was spent by Universe server process.  This, then, appeared to be a Universe performance issue rather than an issue with the .Net code or with the various API layers that sit between .Net and Universe (ADO.NET, the ADO.NET Data Provider for OLEDB, and UniOLEDB).</p>
<p>If 12 minutes is clearly unacceptable, what response time should we reasonably expect for this type of query?   Our Universe programmer tried running the same query (or so we thought) in Universe Basic code and it took 45 seconds to complete.  So, we had plenty of room for improvement and a reasonable expectation that we could cut the response time by 90%.</p>
<p>Here&#8217;s a list of what I&#8217;ve tried, and the result:</p>
<p><span style="font-weight: bold">1. Increase the Universe MAXSELBUF parameter.</span>  This is a server-side configuration parameter which defines the size of the buffer used to hold the results of SELECT statements.  The default is only 4K, and Universe tech support recommended increasing it to 8K.  This seemed a little like using a tablespoon instead of teaspoon to empty out the ocean, but like most Universe configuration parameters it was easy to try &#8212; just update the uvconfig text file on the server and restart the Universe service.  Result: response time dropped from 12 minutes to 8.  Whoa!  If an 8k buffer made things that much better, how about a 16K buffer?  Oddly, this had no effect on the response time.  Maybe if we get out the big guns and and bump it up to a &#8220;whopping&#8221; 128K?  No effect. I began to get suspicious and changed the setting back to its original 4K &#8212; response time remained at 8 minutes.  I ran the full application rather than just my benchmarking code and retrieved the same set of data &#8212; response time  was still 8 minutes.  <span style="font-weight: bold">Result: no effect, despite initial appearances.</span></p>
<p><span style="font-weight: bold">2. Restarting Universe.</span>  As you probably figured out, this gets credit for dropping response time from 12 minutes to 8.  Of course, this isn&#8217;t a practical optimization technique in a production environment &#8212; I can&#8217;t have my code restart the database before each large query.  <span style="font-weight: bold">Result: 33% improvement, but not a practical technique.</span></p>
<p><span style="font-weight: bold">3. Change the UVTSORT parameter.</span> This is another server-side configuration parameter &#8212; changing it from 0 (the default) to 1 turns on multithreading support for sorting data.  This seemed promising, since my query included an &#8220;ORDER BY&#8221; clause and I had noticed that only 1 of our server&#8217;s 4 CPUs was being used for most of the time the query was being processed.  But turning on this support had no apparent effect on either response time or CPU usage for this query.   <span style="font-weight: bold">Result: no effect.</span></p>
<p><span style="font-weight: bold">4. Remove the  ORDER BY clause.</span>  The UVTSORT parameter did get me thinking about the ORDER BY clause in the SELECT statement. It was originally put in there to improve performance &#8212; when processing the results of the query, the code could reduce the number of lookups it had to do if the data was returned in a certain order.  But in the course of processing a query only a dozen or so such lookups were required, even for a 29,000+ row resultset.  Their cumulative impact on response time would be a couple of seconds at most, and how much processing time was that ORDER BY clause costing me? The answer, it turns out, is &#8220;a lot&#8221;.  <span style="font-weight: bold">Result: 33% improvement.</span></p>
<p><span style="font-weight: bold">5. Run the SELECT statement as a Universe paragraph. </span> This idea came from Universe support, and was intended to see if the bottleneck was in one of the API layers between the .Net code and the database.  By packaging the SELECT statement as a Universe package, the 740K of SQL text was replaced by the following: &#8220;CALL TEST1&#8243;, where TEST1 was the name of the paragraph.   From the .Net application&#8217;s point of view, TEST1 is an ADO Command object that returns a resultset, kind of like  a stored procedure:</p>
<p><span style="font-family: courier new,courier,monospace">                OleDbCommand cmdTest = new OleDbCommand(&#8220;CALL TEST1&#8243;, conn);</span><br style="font-family: courier new,courier,monospace" /><span style="font-family: courier new,courier,monospace">                cmdTest.CommandType = CommandType.Text;</span><br style="font-family: courier new,courier,monospace" /><span style="font-family: courier new,courier,monospace">                dataAdapter = new OleDbDataAdapter(cmdTest);</span><br style="font-family: courier new,courier,monospace" /><span style="font-family: courier new,courier,monospace">                dataAdapter .Fill(dataSet, &#8220;Test1&#8243;);</span></p>
<p>The 740K of SQL text is stored in the Universe master dictionary, or VOC.  Getting it into the dictionary is actually easier said than done, since the usual method of editing a file is a Telnet session and Telnet wasn&#8217;t intended to handle 740K strings.  Fortunately, to Universe the VOC is just another table, so I wrote a bit of UniObjects code to insert a new record in the VOC with a 740K column.  Surprisingly, Universe has absolutely no problem with a 740K field &#8212; to Universe, every column is just a string, and 740K is well within its comfort zone for string lengths.</p>
<p>Unfortunately, while the operation was a success the patient died a bloody, inglorious death.  Not only did the SELECT statement take over 10 minutes to complete, but it returned the data as strings formatted for a Telnet display, one field per row, 1.3 million rows, totaling 38M of string data.  <span style="font-weight: bold">Result: don&#8217;t go there.</span></p>
<p><span style="font-weight: bold">6. Use the Universe Basic SQLExecDirect API.</span>  This idea is taken from an IBM Technote.  The .Net code is similar to that in the previous example, but now the CALL statement is invoking a Universe Basic subroutine which passes the 740K SQL statement to the SQLExecDirect API.  The .Fill method returns the same rows and columns as you get if you submit the SQL statement to UniOLEDB, so it was a seamless change for the .Net application.  Unfortunately, for us it was only marginally faster than UniOLEDB, reducing response time from 5:25 to 5:10.  <span style="font-weight: bold">Result: 5% improvement.</span></p>
<p>So, the search for the holy grail continues.  IBM&#8217;s new ADO.Net driver for Universe beckons on the horizon.</p>
<p>However, my faith in this crusade is wavering.  I&#8217;m starting to wonder whether this 45-second goal is a reasonable expectation.  It is based on a &#8220;query&#8221; done using native Universe Basic code that bears faint resemblance to a SQL query.</p>
<p>The apples-to-oranges comparison of Telnet to .Net is something that is never easy to reconcile: users love the extra freedom of the interface, but begrudge the extra sluggishness.  It&#8217;s DOS vs Windows all over again.  Maybe there&#8217;s a primal love for the command-line deep inside every user?  Or maybe I need to more closely embrace the strange ways of Universe Basic, tightening the link between .Net and Universe.</p>
<p>To be continued.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2008/05/26/unioledb-performance-optimization-hits-and-misses/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Asking for the Same Thing Twice</title>
		<link>http://www.gigamegablog.com/2007/12/17/asking-for-the-same-thing-twice/</link>
		<comments>http://www.gigamegablog.com/2007/12/17/asking-for-the-same-thing-twice/#comments</comments>
		<pubDate>Tue, 18 Dec 2007 00:52:38 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[IBM Universe (U2)]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/?p=19</guid>
		<description><![CDATA[Our .Net app has been running for over a week now with its new &#8220;persistent database connection&#8221; architecture intended to reduce the # of IBM Universe licenses (see &#8220;Failing to Let Go&#8221; ). The new design is having the desired &#8230; <a href="http://www.gigamegablog.com/2007/12/17/asking-for-the-same-thing-twice/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Our .Net app has been running for over a week now with its new &#8220;persistent database connection&#8221; architecture intended to reduce the # of IBM Universe licenses (see <a id="g--d" href="http://gigamegablog.com//?p=17">&#8220;Failing to Let Go&#8221;</a> ).</p>
<p>The new design is having the desired effect, but it resulted in one new problem which looks like a bug in the UniOLEDB / .Net Provider for OLEDB stack.  A tester found that &#8220;booking&#8221; (one of our application&#8217;s functions) a certain type of document without first saving it consistently resulted in a <font face="Courier New">&#8220;Not all parameter markers have been resolved&#8221;</font> error.  This exception was thrown by the Fill method which ran a SELECT statement on this document&#8217;s record.  The same action definitely worked fine with the previous design, where the .Net Data Provider would automatically open the database connection before running the Fill method, then close it again afterwards.</p>
<p>This bug was somewhat puzzling, since there had been no code changes specific to this SELECT statement, and the SELECT statement was pretty mundane: just one parameter, which was the key for the record.  Running the statement in the debugger confirmed that the parameter was, indeed, being set.</p>
<p>When UniOLEDB errors occur for reasons that aren&#8217;t obvious from the coder&#8217;s viewpoint, it can be helpful to look at the problem from UniOLEDB&#8217;s viewpoint.  This can be done by turning on the UniOLEDB trace facility, by setting the UniOLEDBTRACELEVEL and UniOLEDBTRACECATEGORY environment variables: I use settings of 4 and 4095, respectively.  A DRITrace.txt file will then be written to the folder that the .Net application is running in, chock full of mostly cryptic information about UniOLEDB&#8217;s activities:</p>
<p><font face="Courier New">00022990 CArICommandTextImpl(73761420)::SetCommandText<br />
00022991 CDRImCommandUCI::SetCommandText(SELECT &#8230;)<br />
00022992 CArCommand(73761420)::Execute()<br />
00022993 CDRImAdmin::ClearError<br />
00022994 CArCommand(73761420)::InternalSetParameters()<br />
00022995 CArCommand(73761420)::ParamData2DRIBuffer()<br />
00022996 CDRImCommandUCI::Execute(SELECT &#8230;)<br />
</font><br />
When I looked at the .Execute that failed,, I noticed that the trace entries which indicate a parameter (such as InternalSetParameters in the above example) were not present.  Or, as some would, say the &#8220;parameter marker&#8221; hadn&#8217;t been &#8220;resolved&#8221;.</p>
<p>I went back and the looked at a previous parameterized SELECT statement that succeeded, to confirm that setting the parameter did result in a trace file entry.  It did, but I noticed something else that I hadn&#8217;t expected: the previous SELECT statement was exactly the same as the one that had later failed.  Same command text, same parameter.  A check of my own log confirmed that it was the same parameter value too.</p>
<p>This turned out to be the root cause of the problem.  The only thing that we had (intentionally) changed between versions was the point that the database connection was opened &#8212; it used to be closed after each SELECT statement, and re-opened for the next one.  Now, it was left open between SELECTs.  So, some piece of code in the stack (maybe the .Net Provider for OLEDB, maybe UniOleDB) wasn&#8217;t impressed that we were asking for the same thing twice, and ignored part of the 2nd request.  Closing the database connection between these two requests solved the problem, and that&#8217;s the solution we went with for now.</p>
<p>In case you&#8217;re wondering, running the same SELECT statement twice wasn&#8217;t a bug on our part.  Booking an unsaved document required that the .Net application 1) save the document 2) invoke a &#8220;Universe Basic API&#8221; (basically, a stored procedure) to fill in some missing fields in the document record 3) read the document record (the first SELECT) 4) invoke another Universe Basic API to &#8220;book&#8221; the document 5) read the newly booked document record (the second SELECT).  Not the optimal way of handling this action, perhaps, but not such as unlikely series of events either.</p>
<p>I have a feeling that there are other parts of our .Net application which can run the same SELECT statement twice &#8212; if there aren&#8217;t, then there almost certainly will be some in the future.  So, a more generalized solution is going to be required.  I&#8217;m inclined to just do away with parameterized SELECT statements, embedding the parameter values into the SELECT statement instead.  While this will, in theory, adversely affect both the performance and security of the application, conventional coding wisdom doesn&#8217;t necessarily apply when sailing the mostly uncharted waters of UniOLEDB development.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2007/12/17/asking-for-the-same-thing-twice/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Failing to Let Go</title>
		<link>http://www.gigamegablog.com/2007/12/06/failing-to-let-go/</link>
		<comments>http://www.gigamegablog.com/2007/12/06/failing-to-let-go/#comments</comments>
		<pubDate>Fri, 07 Dec 2007 00:50:39 +0000</pubDate>
		<dc:creator>dwatts</dc:creator>
				<category><![CDATA[IBM Universe (U2)]]></category>

		<guid isPermaLink="false">http://gigamegatech.com/?p=17</guid>
		<description><![CDATA[Predictably, the first client roll-out of our new .Net / U2 (aka IBM Universe) application hit a snag and, predictably, it wasn&#8217;t one that I saw coming. And, boy, what a snag. The first time we tried to login to &#8230; <a href="http://www.gigamegablog.com/2007/12/06/failing-to-let-go/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Predictably, the first client roll-out of our new .Net / <a title="U2 (aka IBM Universe)" id="j8xs" href="http://www-306.ibm.com/software/data/u2/">U2 (aka IBM Universe)</a> application hit a snag and, predictably, it wasn&#8217;t one that I saw coming.</p>
<p>And, boy, what a snag.  The first time we tried to login to our application on-site, U2&#8242;s UniOLEDB driver threw a  &#8220;Native Error 930065&#8243; Exception.  The very first time, an error that I couldn&#8217;t remember ever seeing before.  Talk about a worst case scenario!</p>
<p>Like many things in the U2 world this particular error code isn&#8217;t documented, nor Googleable. (Go on, try Googling &#8220;UniOleDB&#8221; and &#8220;930065&#8243;. Feel Lucky?  I bet you end up back on this page).  However, Google Desktop came through when <a title="my real memory" id="atro" href="http://gigamegablog.com//?p=11">my real memory</a> failed by dredging up an old e-mail from IBM support stating (inaccurately) that a 930065 error that we hit when evaluating their U2 10.2 version meant that we were out of licenses.</p>
<p>This time, the &#8220;out of licenses&#8221; scenario seemed more plausible, since this client only had a few spare licenses.  But the very first user?  While logging in?  Our application is a strictly two-tiered architecture, and given that our clients have to pay for database licenses, we are reluctant to use U2&#8242;s add-on server-based connection pooling feature.  So our database connections are old school &#8212; the user desktop connects, does its stuff, and immediately disconnects to free up the license.</p>
<p>UniOLEDB actually co-operates fairly well with the .Net Data Provider for OLE DB.   You create your OleDBConnection object, set the connection string, login to the database, then immediately close the connection.  Thereafter, the connection is automatically reopened when needed, such as when you call a .Fill method to run a SELECT statement, and (so I thought) automatically closed afterwards .   This arrangement looked great during our many months of internal testing.   Connection management was never a concern &#8212; it just worked.</p>
<p>It turns out that the arrangement wasn&#8217;t working as well as I thought.  We have plenty of database licenses on our test server and we never come close to reaching the limit.  As a result, I never noticed a bug/feature concerning the way U2 handles the database connections.  In the course of handling a particular action (e.g. logging in), we might read from a dozen tables, resulting in the database connection being opened and closed a dozen times.  There is only one OleDBConnection object on the client end (a public static variable), which means there is only 1 database connection per client application.  But closing that connection does not immediately cause the database license to be freed up.  Depending upon the speed of the desktop PC and the load on the server, those dozen connections might result in 8-10 database licenses being briefly devoted to a single client.</p>
<p>Actually, much of this is conjecture on my part.   Since I couldn&#8217;t find any confirmation of this behaviour in IBM&#8217;s &#8220;Using UniOLEDB&#8221; manual, I e-mailed IBM support asking <span style="font-style: italic">&#8220;when I close a database connection is it possible that the Universe license is  not freed up instantaneously?&#8221;</span>  I received a rather philosophical response that <span style="font-style: italic">&#8220;In reality, there  is no such thing as instantaneous.  Everything takes a period of time, no matter  how tiny a period.&#8221;</span></p>
<p>The IBM tech support person went on to say that he tried closing his test application, then entering the U2 license command into a Telnet session, and he was never able to catch the license still being used.  He suggested  that, when the code encounters a 930065 error, it  should pause to let Universe &#8220;reclaim&#8221; the license, then try to connect again.<span style="font-style: italic" /></p>
<p>I wasn&#8217;t keen on the concept of adding speed bumps to the application, but his use of the word &#8220;reclaim&#8221; was enough of a hint for me that closing the connection doesn&#8217;t free up the license <span style="font-style: italic">synchronously</span>.  (Like that word better, Oh Zen Master of IBM?)  There was a period of time that would elapse before the license was freed up again, somewhere between 0 and the amount of time required for an IBM tech support guy to type &#8220;uvlictool report_lic&#8221; into a Telnet session.</p>
<p>While a dozen connections might chew up 12 licenses during that time, 1 connection couldn&#8217;t possibly chew up more than 1 license.  So, rather than relying on the (admittedly undocumented) ability of UniOLEDB to automatically connect and disconnect as needed, the safest solution seemed to be to take control of the connections in our code.  This meant a long evening of furiously adding calls to our connect and disconnect method at the start of and end of each user &#8220;action&#8221;, and a long day of testing that code, but it fixed the problem.  No more 930065 errors!</p>
<p>What I am still seeing, though, is that the license occasionally isn&#8217;t freed up at all. The UniOLEDB object gets closed, disposed and set to null and the license is still being used until the next database connection is made from that client. This isn&#8217;t a garbage collection timing issue, but a failure to let go.   With so many layers of code sitting between the user and the server, it&#8217;s hard to know which layer is failing to pass along the request to drop the license.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.gigamegablog.com/2007/12/06/failing-to-let-go/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

