Enterprise Library Sometimes Chops XML into 2033 Characters

This morning I began what I thought would be an uneventful task in .NET: connect to one database, download as XML some rows from a table that have changed since a given time, then pass that XML to a stored procedure in another database so that the changes can be merged. Just two tables: one relatively small, the other just a 2-column relationship table for the first table. Here’s a contrived snippet to serve the same purpose:

The SQL:

CREATE PROCEDURE dbo.GetXmlValue

AS

SELECT TOP 100
*
FROM sys.all_columns
FOR XML AUTO, ROOT('Root')

The Code:

Database db = GetDatabase();

DataSet set;

using (DbCommand cmd = db.GetStoredProcCommand("dbo.GetXmlValue"))
{
set = db.ExecuteDataSet(cmd);
}

In my application, it was this second table that tripped me a bit. The first only had a few changed rows, so the XML was only 500-1000 characters. The second table generated a much longer XML string – 3864 characters long. My initial plan was to return two tables, each 1 column and 1 row. When using Database.ExecuteDataSet to fetch the results, however, the second table yielded two rows. I backtracked, second guessed myself, and even grabbed a couple of guys in the hall to double check my code. No one could explain it. It seemed odd that this hasn’t come up before for someone here. I did a bit of Googling and only found a couple of results. This Microsoft Knowledgebase Article just says it’s “by design” and to use SQLCommand.ExecuteXmlReader.

The next question that came up was “Well, what does it do if I return a long XML value among other values in the same row?” I tested this out and everything worked as expected. All of the XML was in a single column value as it should be.

I still can’t exactly explain it. ExecuteScalar has a character limit of 2033 characters. I suspect that because each table in my result set is just a single column value, something somewhere is relying on ExecuteScalar.

My solution? In my stored procedure I just stored each of my table results as an XML typed variable, then returned the two together in the same row.

GTIN 12 UPC Check Digit Calculation in SQL Server 2008

I recently needed to generate the check digit for a GTIN-12 UPC code in SQL. The calculation method for the check digit varies depending on what kind of barcode you’re implementing, so I popped on over to Google to get the necessary algorithm. Naturally, and regardless of simplicity, I checked for any available code snippets. The only I found weren’t GTIN-12, and were in C or C++. So for anyone looking to do it (or something similar) in T-SQL, here’s a scalar function to do just that.

CREATE FUNCTION dbo.CalculateBarcodeGTIN12CheckDigit(@input CHAR(11))
RETURNS INT
AS
BEGIN
DECLARE @evenDigitSum INT = 0
,@oddDigitSum INT = 0
,@i TINYINT = 0
,@result INT;

-- check if given Barcode is Numeric , if not return error status -1
IF(ISNUMERIC(@input) = 0
OR LEN(RTRIM(LTRIM(@input))) != 11)
RETURN -1

-- start the compute BarCode checksum algorithm
SET @i = 1
WHILE (@i <= 11)
BEGIN
--Add odd and even digits separately;
IF((@i % 2) = 0)
SET @evenDigitSum += CONVERT(TINYINT, SUBSTRING(@input,@i,1))
ELSE
SET @oddDigitSum += CONVERT(TINYINT, SUBSTRING(@input,@i,1))
SET @i += 1
END

--As per: http://en.wikipedia.org/wiki/Universal_Product_Code
--Multiply odd sum by 3, add to even sum, and mod 10.
SET @result = ((@oddDigitSum * 3) + @evenDigitSum) % 10;
IF(@result = 0)
RETURN 0
ELSE
RETURN 10 - @result;

RETURN -1
END
GO

Scalar functions are killer, but I’ll only ever be using it for a single record.

Hatcher William

20110520-104025.jpg

So. Awesome. :)

Berlin – All Panoramas

Because I didn’t want to include all of the panoramas I took in my main Berlin summary post, here is a list of nearly all of them for those that care:

Apartment:
http://www.occip.it/pyh2l87gj

Park behind apartment:
http://www.occip.it/pyh30sy9j
http://www.occip.it/pyh80z5ij

Nazi war crimes trial exhibit:
http://www.occip.it/pyh405w8j
http://www.occip.it/pyhsssgj

Outside the Nazi war crimes courthouse:
http://www.occip.it/pyh7em0j
http://www.occip.it/pyh20eo5j

Outside our Nuremburg hotel:
http://www.occip.it/pyh78bnj

Church in Nuremburg (half):
http://www.occip.it/pygy00nksj

Bridge in Nuremburg:
http://www.occip.it/pyh203r7j
http://www.occip.it/pyh40yluj

Medieval Dungeon:
http://www.occip.it/pyhsunvj

Christmas markets:
http://www.occip.it/pyhsec8j
http://www.occip.it/pyh30wfjj
http://www.occip.it/pygy0t15j
http://www.occip.it/pyh30sfbj

Random Subway Station:
http://www.occip.it/pygz0cvgj

Main train station (Berlin Hauptbahnhof)
http://www.occip.it/pyhs0jsxj

Church:
http://www.occip.it/pyh30zyej
http://www.occip.it/pyh3006qxj
Outside: http://www.occip.it/pygy0v67j

Crypt:
http://www.occip.it/pyh50u4zj

Charlottenburg Palace:
http://www.occip.it/pyh69zfj

Holocaust Memorial:
http://www.occip.it/pyh80z4rj
http://www.occip.it/pyh3066kj
http://www.occip.it/pyh7i82j

Brandenberg Gate:
http://www.occip.it/pyh30dfsj — kind of messed up

Tiergarten:
http://www.occip.it/pyhsvm2j
http://www.occip.it/pygy0fraj

KaDeWe Restaraunt:
http://www.occip.it/pygz0ygrj

Gedächtniskirche:
http://www.occip.it/pyh80f95j