Exemplo n.º 1
0
 internal void RaiseStartScope(RoutineInfo r)
 {
   if (OnStartScope != null)
     OnStartScope(r);
 }
Exemplo n.º 2
0
 internal void RaiseEndScope(RoutineInfo r)
 {
   if (OnEndScope != null)
     OnEndScope(r);
 }
Exemplo n.º 3
0
 /// <summary>
 /// Generates a call statement for a given routine.
 /// The routine has already been instrumented.
 /// </summary>
 /// <param name="t"></param>
 /// <param name="ArgsValues"></param>
 private void MakeScopeCreateProc(RoutineInfo ri, string[] ArgsValues, string[] InOutArgsValues)
 {
   CommonTree t = ri.ParsedTree;
   StringBuilder sb = new StringBuilder();
   string spName = ri.Name;
   // build call
   StringBuilder sbCall = new StringBuilder(string.Format("call `{0}`( ", spName));
   // adds inout arguments definition before the call statement
   if (InOutArgsValues != null && InOutArgsValues.Length > 0)
     sbCall.Insert(0, "SET " + string.Join(";SET ", InOutArgsValues) + ";");
   if (ArgsValues != null)
   {
     foreach (string val in ArgsValues)
     {
       sbCall.Append(val).Append(',');
     }
   }
   sbCall.Length--;
   sbCall.Append(");");
   // Parse & create scope
   CommonTokenStream cts;
   CommonTree callTree = (CommonTree)(ParseSql(sbCall.ToString(), false, out sb, out cts).Tree);
   if (callTree.IsNil)
     callTree = (CommonTree)callTree.GetChild(0);
   _scope.Push(
     new RoutineScope() {
       OwningRoutine = new RoutineInfo() {
         ParsedTree = callTree,
         Name = "<main>",
         TokenStream = cts,
         SourceCode = sbCall.ToString() },
       Variables = new Dictionary<string, StoreType>() });
 }
Exemplo n.º 4
0
 private RoutineInfo MakeRoutineInfo(CommonTree t, CommonTokenStream cts, string sql)
 {
   string name = Debugger.GetRoutineName(t);
   RoutineInfo ri = new RoutineInfo() {
     Name = name,
     SourceCode = sql,
     ParsedTree = t,
     Type = RoutineInfoType.Procedure,
     TokenStream = cts
   };
   return ri;
 }
Exemplo n.º 5
0
 internal void RegisterRoutine(string sName, RoutineInfo r)
 {
   _preinstrumentedRoutines.Add(sName, r);
 }
Exemplo n.º 6
0
 private void AddToPreinstrumentedRoutines(RoutineInfo ri)
 {
   _preinstrumentedRoutines.Add(string.Format("{0}", ri.GetFullName(_connection.Database)), ri);
 }
Exemplo n.º 7
0
    private void RegisterNewOldVars(RoutineInfo ri, Dictionary<string, StoreType> vars)
    {
      string sql = string.Format(
@"select column_name, data_type, numeric_precision, numeric_scale, character_maximum_length, column_type 
  from information_schema.columns where table_name = '{0}' and table_schema = '{1}'",
ri.TriggerInfo.Table, ri.TriggerInfo.ObjectSchema);
      MySqlCommand cmd = new MySqlCommand(sql, _utilCon);
      MySqlDataReader r = cmd.ExecuteReader();
      try
      {
        while (r.Read())
        {
          StoreType st;
          if( ( ri.TriggerInfo.Event == TriggerEvent.Insert ) ||
            ( ri.TriggerInfo.Event == TriggerEvent.Update ))
          {
            st = GetStoreType(r, "new");
            vars.Add(st.Name, st);
          }
          if ((ri.TriggerInfo.Event == TriggerEvent.Delete) ||
            (ri.TriggerInfo.Event == TriggerEvent.Update))
          {
            st = GetStoreType(r, "old");
            vars.Add(st.Name, st);
          }
        }
      }
      finally
      {
        r.Close();
      }
    }
Exemplo n.º 8
0
 private RoutineScope GetRoutineScopeFromRoutineInfo(RoutineInfo ri)
 {
   RoutineScope rs = new RoutineScope() { OwningRoutine = ri, Variables = new Dictionary<string,StoreType>() };
   foreach (StoreType st in ri.Locals.Values)
   {
     rs.Variables.Add(st.Name, new StoreType(st));
   }
   return rs;
 }
Exemplo n.º 9
0
 private void GenerateInstrumentedCodeRecursive(
   IList<ITree> children,
   RoutineInfo routine,
   StringBuilder sql)
 {
   IToken tkTmp;
   ITree trTmp;
   CommonTokenStream tokenStream = routine.TokenStream;
   string PreInstrumentationCode = routine.PreInstrumentationCode;
   string PostInstrumentationCode = routine.PostInstrumentationCode;
   // The following statements are qualified to have "statement lists"
   // begin_end, if, while, repeat, loop, declare condition, declare handler, 
   // case's when, then, else.
   if (children == null) return;
   foreach (ITree ic in children)
   {
     CommonTree tc = (CommonTree)ic;
     if( !routine._endOfDeclare && ( routine.BeginEnd.Children == children ))
     {
       if ((Cmp(tc.Text, "declare") != 0) && (Cmp(tc.Text, "declare_handler") != 0) )
       {
         routine._endOfDeclare = true;
         // Emit begin scope code
         EmitBeginScopeCode(sql, routine);
       }
     }
     switch (tc.Text.ToLowerInvariant())
     {
       case "begin_end":
         {
           if (Cmp(tc.GetChild(0).Text, "label") == 0)
           {
             sql.Append(tc.GetChild(0).GetChild(0).Text).Append(" : ");
           }
           sql.AppendLine("begin");
           GenerateInstrumentedCodeRecursive(tc.Children, routine, sql);
           tkTmp = tokenStream.GetTokens(tc.TokenStopIndex, tc.TokenStopIndex).Last();
           EmitInstrumentationCode(sql, routine, tkTmp.Line, tkTmp.CharPositionInLine);
           // TODO: Add END token to AST, so you can put breakpoints in the END
           //routine.RegisterStatement(tc);
           sql.AppendLine("end;");
         }
         break;
       case "if":
         {
           int i = 0, j = 0;
           int idxThen = -1;
           EmitInstrumentationCode(sql, routine, tc.Line, tc.CharPositionInLine);
           routine.RegisterStatement(tc);
           do
           {
             while (i < tc.ChildCount &&
               ((Debugger.Cmp(tc.GetChild(i).Text, "if_cond") != 0) &&
               (Debugger.Cmp(tc.GetChild(i).Text, "elseif") != 0)))
               i++;
             if (i == tc.ChildCount) break;
             CommonTree child = (CommonTree)tc.GetChild(i);
             j = 0;
             while (j < tc.ChildCount && Debugger.Cmp(child.GetChild(j).Text, "then") != 0)
               j++;
             idxThen = j;
             CommonTree thenTree = (CommonTree)child.GetChild(idxThen);
             CommonTree exprTree = (CommonTree)child.GetChild(idxThen - 1);
             // Concat "elseif/if ... then"
             if (Cmp(child.Text, "if_cond") == 0)
               sql.Append("if ");
             else
               sql.Append("elseif ");
             ConcatTokens(sql, tokenStream, exprTree.TokenStartIndex, exprTree.TokenStopIndex, true );
             sql.AppendLine(" then ");
             GenerateInstrumentedCodeRecursive(thenTree.Children, routine, sql);
             i++;
           } while (true);
           // look for else
           i = 0;
           while (i < tc.ChildCount && Debugger.Cmp(tc.GetChild(i).Text, "else") != 0)
             i++;
           if (i < tc.ChildCount)
           {
             CommonTree elseTree = (CommonTree)tc.GetChild(i);
             // concat "else"
             ConcatTokens(sql, tokenStream, elseTree.TokenStartIndex, elseTree.GetChild(0).TokenStartIndex - 1);
             GenerateInstrumentedCodeRecursive(elseTree.Children, routine, sql);
           }
           sql.AppendLine("end if;");
         }
         break;
       case "while":
         {
           EmitInstrumentationCode(sql, routine, tc.Line, tc.CharPositionInLine);
           bool hasLabel = false;
           if (Cmp(tc.GetChild(0).Text, "label") == 0)
           {
             sql.Append(tc.GetChild(0).GetChild(0).Text).Append(" : ");
             hasLabel = true;
           }
           // Concat "while ... do"
           sql.Append(" while ");
           ConcatTokens(sql, tokenStream, tc.GetChild( 0 ).TokenStartIndex, tc.GetChild(0).TokenStopIndex, false);
           sql.Append(" do ");
           if (!hasLabel)
           {
             GenerateInstrumentedCodeRecursive(
               // skip while condition
               tc.Children.Skip(1).ToList(), routine, sql);
           }
           else
           {
             GenerateInstrumentedCodeRecursive(
               // skip while condition & label
               tc.Children.Skip(2).ToList(), routine, sql);
           }
           sql.AppendLine("end while;");
         }
         break;
       case "repeat":
         {
           bool hasLabel = false;
           if (Cmp(tc.GetChild(0).Text, "label") == 0)
           {
             sql.Append(tc.GetChild(0).GetChild(0).Text).Append(" : ");
             hasLabel = true;
           }
           IList<ITree> childColl = tc.Children;
           sql.AppendLine("repeat");
           if (!hasLabel)
           {
             GenerateInstrumentedCodeRecursive(
               // skip until & until-condition
                childColl.Take(childColl.Count - 2).ToList(), routine, sql);
           }
           else
           {
             GenerateInstrumentedCodeRecursive(
               // skip label, until & until-condition
                childColl.Take(childColl.Count - 2).Skip(1).ToList(), routine, sql);
           }
           trTmp = tc.GetChild(tc.ChildCount - 1);
           EmitInstrumentationCode(sql, routine, trTmp.Line, trTmp.CharPositionInLine);
           sql.Append("until ");
           // Concat until condition
           ConcatTokens(sql, tokenStream, 
             childColl[childColl.Count - 1].TokenStartIndex, 
             childColl[childColl.Count - 1].TokenStopIndex, true );
           sql.AppendLine( " end repeat; " );
         }
         break;
       case "loop":
         {
           bool hasLabel = false;
           if (Cmp(tc.GetChild(0).Text, "label") == 0)
           {
             sql.Append(tc.GetChild(0).GetChild(0).Text).Append(" : ");
             hasLabel = true;
           }
           sql.AppendLine("loop");
           if (hasLabel)
           {
             // skip label children
             GenerateInstrumentedCodeRecursive(tc.Children.Skip(1).ToList(), routine, sql);
           }
           else
           {
             GenerateInstrumentedCodeRecursive(tc.Children, routine, sql);
           }
           sql.AppendLine("end loop;");
         }
         break;
       case "declare_handler":
         {
           CommonTree beginEnd = (CommonTree)tc.GetChild(2);
           // Concat declare handler ... (until before begin)
           ConcatTokens(sql, tokenStream, tc.TokenStartIndex, beginEnd.TokenStartIndex - 1);
           if (Cmp("begin_end", beginEnd.Text) != 0)
           {
             // if there is no begin/end block, need to rewrite code so it appears to be one.
             List<ITree> nodes = new List<ITree>();
             nodes.Add(beginEnd);
             sql.AppendLine(" begin ");
             GenerateInstrumentedCodeRecursive(nodes, routine, sql);
             sql.AppendLine(" end; ");
           }
           else
           {
             GenerateInstrumentedCodeRecursive( tc.Children.Skip( 2 ).ToList(), routine, sql );
           }
         }
         break;
       case "case_stmt":
         {
           int i = 0;
           routine.RegisterStatement(tc);
           EmitInstrumentationCode(sql, routine, tc.Line, tc.CharPositionInLine);
           sql.AppendLine("case");
           CommonTree whenCt = (CommonTree)tc.GetChild(0);
           if (Cmp(whenCt.Text, "when") != 0)
           {
             CommonTree firstCt = whenCt;
             ConcatTokens(sql, tokenStream, firstCt.TokenStartIndex, firstCt.TokenStopIndex );
             whenCt = (CommonTree)tc.GetChild(1);
           }
           while (Cmp(whenCt.Text, "when") == 0)
           {
             CommonTree whenExpr = ( CommonTree )whenCt.GetChild( 0 );
             sql.Append(" when ");
             ConcatTokens(sql, tokenStream, whenExpr.TokenStartIndex, whenExpr.TokenStopIndex, false);
             sql.Append(" then ");
             GenerateInstrumentedCodeRecursive( whenCt.Children.Skip( 1 ).ToList(), routine, sql );
             if (++i >= tc.ChildCount) break;
             whenCt = (CommonTree)tc.GetChild(i);
           }
           if (i < tc.ChildCount)
           {
             CommonTree elseCt = (CommonTree)tc.GetChild(tc.ChildCount - 1);
             sql.Append(" else");
             GenerateInstrumentedCodeRecursive( elseCt.Children, routine, sql);
           }
           sql.AppendLine("end case;");
         }
         break;
       case "call":
         {
           routine.RegisterStatement(tc);
           EmitInstrumentationCode(sql, routine, tc.Line, tc.CharPositionInLine);
           ConcatTokens(sql, tokenStream, tc.TokenStartIndex, tc.TokenStopIndex);
           // Workaround: sometimes last token of declare statement is not the expected semicolon, if so, add it.
           if (Cmp(tokenStream.Get(tc.TokenStopIndex).Text, ";") != 0)
           {
             sql.Append(';');
           }
           // end workaround
         }
         break;
       case "label":
         // nothing
         break;
       case "leave":
         {
           routine.RegisterStatement(tc);
           string label = tc.GetChild(0).Text;
           EmitInstrumentationCode(sql, routine, tc.Line, tc.CharPositionInLine);
           if (routine._leaveLabel == label)
           {
             EmitEndScopeCode(sql);
           }
           ConcatTokens(sql, tokenStream, tc.TokenStartIndex, tc.TokenStopIndex);
         }
         break;
       case "return":
         {
           routine.RegisterStatement(tc);
           EmitInstrumentationCode(sql, routine, tc.Line, tc.CharPositionInLine);
           EmitEndScopeCode(sql);
           ConcatTokens(sql, tokenStream, tc.TokenStartIndex, tc.TokenStopIndex);
           // Workaround: sometimes last token of declare statement is not the expected semicolon, if so, add it.
           if (Cmp(tokenStream.Get(tc.TokenStopIndex).Text, ";") != 0)
           {
             sql.Append(';');
           }
           // end workaround
           sql.AppendLine();
         }
         break;
       default:
         // not compound code, skip over local variables.
         if (Cmp(tc.Text, "declare") != 0)
         {
           routine.RegisterStatement(tc);
           EmitInstrumentationCode(sql, routine, tc.Line, tc.CharPositionInLine);
           ConcatTokens(sql, tokenStream, tc.TokenStartIndex, tc.TokenStopIndex);
         }
         else
         {
           ConcatTokens(sql, tokenStream, tc.TokenStartIndex, tc.TokenStopIndex);
         }
         // Workaround: sometimes last token of declare statement is not the expected semicolon, if so, add it.
         if (Cmp(tokenStream.Get(tc.TokenStopIndex).Text, ";") != 0)
         {
           sql.Append(';');
         }
         // end workaround
         sql.AppendLine();
         break;
     }
   }
 }
Exemplo n.º 10
0
 private void EmitBeginScopeCode( StringBuilder sql, RoutineInfo ri )
 {
   sql.AppendFormat("if {0} = 0 then ", VAR_DBG_NO_DEBUGGING);
   sql.AppendLine();
   sql.Append("update `serversidedebugger`.`DebugData` set `serversidedebugger`.`DebugData`.`Val` = `serversidedebugger`.`DebugData`.`Val` + 1 where `serversidedebugger`.`DebugData`.`Id` = 1;");
   sql.AppendLine();
   sql.AppendFormat("call `serversidedebugger`.`Push`( {0}, '{1}' );", DebugSessionId, ri.FullName );
   sql.AppendLine();
   sql.Append("end if;");
   sql.AppendLine();
 }
Exemplo n.º 11
0
 private void EmitInstrumentationCode(StringBuilder sql, RoutineInfo routine, int lineno, int colno)
 {
   sql.AppendFormat("if {0} = 0 then ", VAR_DBG_NO_DEBUGGING);
   sql.AppendLine();
   sql.AppendFormat(routine.PreInstrumentationCode, VAR_DBG_SCOPE_LEVEL, lineno, routine.FullName, DebugSessionId, colno);
   sql.AppendLine(string.Format("call `serversidedebugger`.`ExitEnterCriticalSection`( '{0}', {1} );", routine.Name, lineno ));
   sql.AppendFormat(routine.PostInstrumentationCode, VAR_DBG_SCOPE_LEVEL, DebugSessionId);
   sql.AppendLine(" end if;");
 }
Exemplo n.º 12
0
 private void GenerateInstrumentedCode(
   RoutineInfo routine,
   StringBuilder sql)
 {
   // Get initial begin_end,
   // TODO: there may be no begin/end.
   CommonTree t = routine.ParsedTree;
   CommonTree beginEnd = null;
   int i = 0;
   while (i < t.ChildCount && Debugger.Cmp(t.GetChild(i).Text, "begin_end") != 0)
     i++;
   beginEnd = (CommonTree)t.GetChild(i);
   routine.BeginEnd = beginEnd;
   // generate stub method "create proc... begin"
   ConcatTokens(sql, routine.TokenStream, t.TokenStartIndex, beginEnd.TokenStartIndex - 1);
   if( Cmp( beginEnd.GetChild( 0 ).Text, "label" ) == 0 )
   {
     routine._leaveLabel = beginEnd.GetChild(0).GetChild(0).Text;
   }
   
   // Generate scope entry:
   if (!string.IsNullOrEmpty(routine._leaveLabel))
   {
     sql.Append(routine._leaveLabel).Append(" : ");
   }
   sql.AppendLine( "begin" );
   sql.AppendLine("#begin scope");
   // Generate recursive code:
   routine._endOfDeclare = false;
   GenerateInstrumentedCodeRecursive(beginEnd.Children, routine, sql);
   // Generate scope exit:
   if (routine.Type != RoutineInfoType.Function)
   {
     IToken tk = routine.TokenStream.Get(beginEnd.TokenStopIndex);
     EmitInstrumentationCode(sql, routine, tk.Line, tk.CharPositionInLine);
   }
   sql.AppendLine("#end scope");
   if (routine.Type != RoutineInfoType.Function)
   {
     // Generate code to cleanup scope.
     EmitEndScopeCode(sql);
   }
   sql.AppendLine("end;");
 }
Exemplo n.º 13
0
    /// <summary>
    /// Instruments a routine.
    /// </summary>
    /// <param name="routine"></param>
    private void InstrumentRoutine( RoutineInfo routine )
    {
      /*
       * - Parse formal arguments.
       * - Parse begin block.
       * - For each begin block parse declare's, then instructions.
       * - When finish parsing tree, make a backup.
       * - Then instrument it.
       * */
      // Parse args
      StringBuilder sb = new StringBuilder();
      CommonTokenStream tokenStream;
      MySQL51Parser.program_return tree = 
        ParseSql(routine.SourceCode, false, out sb, out tokenStream);
      routine.ParsedTree = ( CommonTree )( tree.Tree );
      if (routine.ParsedTree.IsNil)
      {
        routine.ParsedTree = ( CommonTree )routine.ParsedTree.GetChild(0);
      }
      routine.TokenStream = tokenStream;
      Dictionary<string, StoreType> args = ParseArgs( routine.ParsedTree );
      
      
      // Parse Begin block
      CommonTree beginEnd = GetBeginEnd(routine.ParsedTree);
      // There won't be always a begin/end block.
      if (beginEnd == null)
      {
        // begin/end block
        StringBuilder sbNewRoutineSql = new StringBuilder();
        ITree lastChild = routine.ParsedTree.GetChild(routine.ParsedTree.ChildCount - 1);
        ConcatTokens(sbNewRoutineSql, routine.TokenStream, 0, lastChild.TokenStartIndex - 1);
        sbNewRoutineSql.AppendLine();
        sbNewRoutineSql.AppendLine("begin");
        ConcatTokens(sbNewRoutineSql, routine.TokenStream, lastChild.TokenStartIndex, lastChild.TokenStopIndex);
        if ( Cmp( routine.TokenStream.Get( lastChild.TokenStopIndex ).Text, ";" ) != 0 )
        {
          sbNewRoutineSql.Append(';');
        }
        sbNewRoutineSql.AppendLine();
        sbNewRoutineSql.AppendLine( "end" );
        StringBuilder sbErrors;
        tokenStream = null;
        string sSql = sbNewRoutineSql.ToString();
        tree = ParseSql(sSql, false, out sbErrors, out tokenStream);
        routine.TokenStream = tokenStream;
        routine.SourceCode = sSql;
        routine.ParsedTree = (CommonTree)(tree.Tree);
        if (routine.ParsedTree.IsNil)
        {
          routine.ParsedTree = (CommonTree)routine.ParsedTree.GetChild(0);
        }
        // No need to reparse args, just begin/end
        beginEnd = GetBeginEnd(routine.ParsedTree);
      }
      // Get declare variables, sessions, new & old
      ParseDeclares(beginEnd, args);
      ParseSessions(tokenStream, args);
      RegisterInternalVars(args);
      if (routine.Type == RoutineInfoType.Trigger)
      {
        RegisterNewOldVars(routine, args);
      }

      // forces to backup the routine
      if (Scope.Count == 0)
      {
        RoutineScope tempScope = new RoutineScope();
        tempScope.OwningRoutine = routine;
        tempScope.GetFileName();
      }
      else
        CurrentScope.GetFileName();

      // generate instrumentation code
      StringBuilder preInscode = new StringBuilder();
      // track internal variables...
      // Workaround: row_count() is affected by any precious SET statement, so must be first
      preInscode.AppendFormat("set {0} = row_count();", VAR_DBG_ROW_COUNT);
      preInscode.AppendLine();
      preInscode.AppendFormat("set {0} = last_insert_id();", VAR_DBG_LAST_INSERT_ID);
      preInscode.AppendLine();
      preInscode.AppendFormat("set {0} = found_rows();", VAR_DBG_FOUND_ROWS);
      preInscode.AppendLine();
      preInscode.Append(" call `serversidedebugger`.`SetDebugScopeVar`( {3}, {0}, '@@@lineno', {1} );" ).AppendLine();      
      preInscode.Append(" call `serversidedebugger`.`SetDebugScopeVar`( {3}, {0}, '@@@colno', {4} );").AppendLine();      
      // ...and user variables
      foreach (StoreType st in args.Values)
      {
        if (st.VarKind == VarKindEnum.Internal) continue;        
        preInscode.AppendLine("call `serversidedebugger`.`SetDebugScopeVar`( {3}, {0}, ").
          AppendFormat("'{0}', cast( {0} as binary ) );", st.Name).AppendLine();
      }
      StringBuilder postInscode = new StringBuilder();
      foreach (StoreType st in args.Values)
      {
        if (st.VarKind == VarKindEnum.Internal) continue;
        postInscode.AppendFormat(
          @"set {0} = ( select cast( `serversidedebugger`.`DebugScope`.`VarValue` as {1} ) from `serversidedebugger`.`DebugScope` where `serversidedebugger`.`DebugScope`.`DebugSessionId` = {2} ", st.Name, st.GetCastExpressionFromBinary(), DebugSessionId).
          AppendFormat(" and `serversidedebugger`.`DebugScope`.`DebugScopeLevel` = {0} and `serversidedebugger`.`DebugScope`.`VarName` = '{1}' and `serversidedebugger`.`DebugScope`.`Id` = ( select max( `serversidedebugger`.`DebugScope`.`Id` ) from `serversidedebugger`.`DebugScope` where `serversidedebugger`.`DebugScope`.`DebugSessionId` = {2} and `serversidedebugger`.`DebugScope`.`DebugScopeLevel` = {0} and `serversidedebugger`.`DebugScope`.`VarName` = '{1}' ));",
            "{0}", st.Name, DebugSessionId );
        postInscode.AppendLine();
      }
      routine.PreInstrumentationCode = preInscode.ToString();
      routine.PostInstrumentationCode = postInscode.ToString();
      routine.Locals = args;
      // finally instrument.
      StringBuilder sql = new StringBuilder();
      // Instrumeting code...
      GenerateInstrumentedCode(routine, sql);
      routine.InstrumentedSourceCode = sql.ToString();
      string sqlDrop = string.Format("drop {0} {1}", routine.Type.ToString(), routine.Name);
      string db = _utilCon.Database;
      if (!string.IsNullOrEmpty(routine.Schema))
      {
        ExecuteRaw(string.Format("use `{0}`", routine.Schema ));
      }
      ExecuteRaw(sqlDrop);
      try
      {
        ExecuteRaw(string.Format("delimiter //\n{0}\n//", routine.InstrumentedSourceCode));
      }
      catch (Exception)
      {
        // In case of exception restore previous non-instrumented version.
        ExecuteRaw(string.Format("delimiter //\n{0}\n//", routine.SourceCode));
        throw;
      }
      finally
      {
        ExecuteRaw(string.Format("use `{0}`", db));
      }
    }