2

This legacy code is called from a gazillion places in the app:

    public void DBCommand(string dynSQL, bool Silent)
    {
        checkConnection();
        SqlCeCommand cmd = objCon.CreateCommand();
        SqlCeTransaction trans = this.GetConnection().BeginTransaction();
        cmd.Transaction = trans;

        try
        {
            cmd.CommandText = dynSQL;
            cmd.ExecuteNonQuery();
            trans.Commit();
        }
        catch (Exception ex)
        {
            MessageBox.Show(
                string.Format("DBCommand Except in DBConnection.DBCommand: {0}. InnerException: {1}", ex.Message, ex.InnerException));//TODO: Remove
            try 
            {
                trans.Rollback();
            }
            catch (SqlCeException) 
            {
                // Handle possible exception here
            }
//              MessageBox.Show(
//                  string.Format("DBCommand Except in DBConnection.DBCommand: {0}. InnerException: {1}", ex.Message, ex.InnerException));//TODO: Remove
                WriteDBCommandException(dynSQL, ex, Silent);
            }
        }

When a particular file is loaded and its contents inserted into a database, I get this message five times. Yet the exception's Message and InnerException are always empty strings.

I even (somewhat superstitiously or illogically, perhaps) moved the MessageBox.Show() from one location to another to see if that would make any difference (it doesn't).

The exception displays, but without giving any useful information about what the problem is; I've looked (manually, or more precisely, I guess literally scanned optically) at the data in question, and it all seems okay.

So why is this exception message weeping and wailing, but without being communicative about what the problem is, like a colicky but mute baby (mouth wide open, tears streaming down, but no sound escaping)?

UPDATE

Okay, I adapted ErikEJ's code snippet (could not use HelpLink or StringIsNullOrEmpty as I'm using tools from a time long, long, ago, in the days of Alley Oop, Bertha Butt, and Artie Shaw):

            // from method that throws the exception
            catch (SqlCeException sqlfail)
            {
                MessageBox.Show(GetSQLCEErrorInfo(sqlfail));
            }
            catch (Exception ex)
. . .

        public static string GetSQLCEErrorInfo(SqlCeException args)
        {
            SqlCeErrorCollection errorCollection = args.Errors;

            StringBuilder bld = new StringBuilder();
            Exception inner = args.InnerException;

            if (null != inner)
            {
                bld.Append("\nInner Exception: " + inner.ToString());
            }
            // Enumerate the errors to a message box.
            foreach (SqlCeError err in errorCollection)
            {
                bld.Append("\n Error Code: " + err.HResult.ToString("X", 
System.Globalization.CultureInfo.InvariantCulture));
                bld.Append("\n Message   : " + err.Message);
                bld.Append("\n Minor Err.: " + err.NativeError);
                bld.Append("\n Source    : " + err.Source);
                // Enumerate each numeric parameter for the error.
                foreach (int numPar in err.NumericErrorParameters)
                {
                    if (0 != numPar) bld.Append("\n Num. Par. : " + numPar);
                }
                // Enumerate each string parameter for the error.
                foreach (string errPar in err.ErrorParameters)
                {
                    if ((null != errPar) && (errPar.Trim() != string.Empty))  //IsNullOrEmpty(errPar))
                    {
                        bld.Append("\n Err. Par. : " + errPar);
                    }
                }
            }
            return bld.ToString();
        }

...and I see the following:

Error Code: 80040E14
Message : There was an error parsing the query. [Token line number, Token line offset,, Token in error,,]
Minor Err.: 25501
Source : Microsoft SQL Server 2000 Windows CE Edition
Num. Par. : 1
Num. Par. : 47
Err. Par. " [

...then:

Exception: SLQ Server CE does not support parallel transactions.
Location. DBConnection.GetInstance(siteNo)

(I get both of those twice); but why only twice? It inserts a few hundred records...one would think that if it would fail once, it would fail every time.

B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
  • what is the exception? what are the is the message? what is in the file? – Jason Jun 04 '13 at 16:56
  • 3
    I don't know the answer to your question but here's something to consider: when a database call fails, the db doesn't know if the failure is a bug or *the result of an attack by a hostile party attempting to subvert the database*. If you are in the latter case, the last thing you want to do is provide detailed information about the nature of the failure to the attacker; they're going to use that to craft a better attack. If it's a genuine bug then you *do* want to report detailed information. The database might be "failing to the safe mode" because it does not know the client is benign. – Eric Lippert Jun 04 '13 at 16:59
  • @Jason: That's what I don't know - it won't tell me. – B. Clay Shannon-B. Crow Raven Jun 04 '13 at 17:01
  • yeah, woops, obvs you don't know the exception. but do you know what's in the file? have you tried using a profiler to see what's going on? – Jason Jun 04 '13 at 17:03
  • @Eric: Good point; in this case, I think the hostile party attacking is the former programmer (IOW, unintentional hostility, like when a moose steps on a rabbit). – B. Clay Shannon-B. Crow Raven Jun 04 '13 at 17:03
  • i don't know if this will work with CE, or if there are other tools like it designed for CE. but essentially this lets you monitor what's going on with the db in real time: http://msdn.microsoft.com/en-us/library/ms181091.aspx – Jason Jun 04 '13 at 17:06
  • This method is fundamentally broken in a more important way: it forces you to build sql queries that are vulnerable to sql injection. The method should include another argument for accepting parameter data and code for including that data with the query. – Joel Coehoorn Jun 04 '13 at 17:31
  • @Joel: Yes, you're right, but the entire app is broken almost beyond repair; my nickname for it is Humpty Dumpty. I don't touch it any more than I absolutely have to because if I poke it in the belly, its toe starts to itch, and the resulting reflex reaction results in me getting kicked right in the gut (or worse). – B. Clay Shannon-B. Crow Raven Jun 04 '13 at 17:33
  • "All the king's horses and all the king's men couldn't put Humpty Dumpty back together again." I never understood that sage little bit of doggerel until recently. – B. Clay Shannon-B. Crow Raven Jun 04 '13 at 18:20

1 Answers1

3

You are doing it wrong, You need to catch the more specialized SqlCeException caused by ExecuteNonQuery before catching the general Exception. And for SqlCeExcpetion, special handling is required, you can use something like this to get all relevant info:

public static string ShowErrors(System.Data.SqlServerCe.SqlCeException e)
{
System.Data.SqlServerCe.SqlCeErrorCollection errorCollection = e.Errors;

StringBuilder bld = new StringBuilder();
Exception inner = e.InnerException;

if (!string.IsNullOrEmpty(e.HelpLink))
{
    bld.Append("\nCommand text: ");
    bld.Append(e.HelpLink);
}

if (null != inner)
{
    bld.Append("\nInner Exception: " + inner.ToString());
}
// Enumerate the errors to a message box.
foreach (System.Data.SqlServerCe.SqlCeError err in errorCollection)
{
    bld.Append("\n Error Code: " + err.HResult.ToString("X", System.Globalization.CultureInfo.InvariantCulture));
    bld.Append("\n Message   : " + err.Message);
    bld.Append("\n Minor Err.: " + err.NativeError);
    bld.Append("\n Source    : " + err.Source);

    // Enumerate each numeric parameter for the error.
    foreach (int numPar in err.NumericErrorParameters)
    {
        if (0 != numPar) bld.Append("\n Num. Par. : " + numPar);
    }

    // Enumerate each string parameter for the error.
    foreach (string errPar in err.ErrorParameters)
    {
        if (!string.IsNullOrEmpty(errPar)) bld.Append("\n Err. Par. : " + errPar);
    }
  }
  return bld.ToString();
}
ErikEJ
  • 40,951
  • 5
  • 75
  • 115