Drizzled Public API Documentation

execute.cc
00001 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Brian Aker
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <drizzled/statement/execute.h>
00024 #include <drizzled/session.h>
00025 #include <drizzled/execute.h>
00026 #include <drizzled/user_var_entry.h>
00027 #include <drizzled/plugin/listen.h>
00028 #include <drizzled/plugin/client.h>
00029 #include <drizzled/plugin/null_client.h>
00030 #include <drizzled/plugin/client/concurrent.h>
00031 #include <drizzled/sql_lex.h>
00032 
00033 namespace drizzled
00034 {
00035 
00036 void parse(drizzled::Session *session, const char *inBuf, uint32_t length);
00037 
00038 namespace statement
00039 {
00040 
00041 Execute::Execute(Session *in_session,
00042                  drizzled::execute_string_t to_execute_arg,
00043                  bool is_quiet_arg,
00044                  bool is_concurrent_arg,
00045                  bool should_wait_arg) :
00046   Statement(in_session),
00047   is_quiet(is_quiet_arg),
00048   is_concurrent(is_concurrent_arg),
00049   should_wait(should_wait_arg),
00050   to_execute(to_execute_arg)
00051 {
00052 }
00053   
00054 
00055 bool statement::Execute::parseVariable()
00056 {
00057   if (to_execute.isVariable())
00058   {
00059     user_var_entry *var= session().getVariable(to_execute, false);
00060 
00061     if (var && var->length && var->value && var->type == STRING_RESULT)
00062     {
00063       LEX_STRING tmp_for_var;
00064       tmp_for_var.str= var->value; 
00065       tmp_for_var.length= var->length; 
00066       to_execute.set(tmp_for_var);
00067 
00068       return true;
00069     }
00070   }
00071 
00072   return false;
00073 }
00074 
00075 
00076 bool statement::Execute::runStatement(plugin::NullClient *client, const std::string &arg)
00077 {
00078   client->pushSQL(arg);
00079   if (not session().executeStatement())
00080     return true;
00081 
00082   if (session().is_error())
00083     return true;
00084 
00085   return false;
00086 }
00087 
00088 
00089 bool statement::Execute::execute()
00090 {
00091   bool ret= execute_shell();
00092 
00093   // We have to restore ourselves at the top for delete() to work.
00094   lex().statement= this;
00095 
00096   return ret;
00097 }
00098 
00099 
00100 bool statement::Execute::execute_shell()
00101 {
00102   if (to_execute.length == 0)
00103   {
00104     my_error(ER_WRONG_ARGUMENTS, MYF(0), "Invalid Variable");
00105     return false;
00106   }
00107 
00108   if (to_execute.isVariable())
00109   {
00110     if (not parseVariable())
00111     {
00112       my_error(ER_WRONG_ARGUMENTS, MYF(0), "Invalid Variable");
00113       return false;
00114     }
00115   }
00116 
00117   if (is_concurrent)
00118   {
00119     if (not session().isConcurrentExecuteAllowed())
00120     {
00121       my_error(ER_WRONG_ARGUMENTS, MYF(0), "A Concurrent Execution Session can not launch another session.");
00122       return false;
00123     }
00124 
00125     drizzled::Execute executer(session(), should_wait);
00126     executer.run(to_execute.str, to_execute.length);
00127   }
00128   else // Non-concurrent run.
00129   {
00130     if (is_quiet)
00131     {
00132       plugin::Client *temp= session().getClient();
00133       plugin::NullClient *null_client= new plugin::NullClient;
00134 
00135       session().setClient(null_client);
00136       
00137       bool error_occured= false;
00138       bool is_savepoint= false;
00139       {
00140         std::string start_sql;
00141         if (session().inTransaction())
00142         {
00143           // @todo Figure out something a bit more solid then this.
00144           start_sql.append("SAVEPOINT execute_internal_savepoint");
00145           is_savepoint= true;
00146         }
00147         else
00148         {
00149           start_sql.append("START TRANSACTION");
00150         }
00151 
00152         error_occured= runStatement(null_client, start_sql);
00153       }
00154 
00155       // @note this is copied from code in NULL client, all of this belongs
00156       // in the pluggable parser pieces.  
00157       if (not error_occured)
00158       {
00159         typedef boost::tokenizer<boost::escaped_list_separator<char> > Tokenizer;
00160         std::string full_string(to_execute.str, to_execute.length);
00161         Tokenizer tok(full_string, boost::escaped_list_separator<char>("\\", ";", "\""));
00162 
00163         for (Tokenizer::iterator iter= tok.begin();
00164              iter != tok.end() and session().getKilled() != Session::KILL_CONNECTION;
00165              ++iter)
00166         {
00167           if (runStatement(null_client, *iter))
00168           {
00169             error_occured= true;
00170             break;
00171           }
00172         }
00173 
00174         // @todo Encapsulate logic later to method
00175         {
00176           std::string final_sql;
00177           if (is_savepoint)
00178           {
00179             if (error_occured)
00180             {
00181               final_sql.append("ROLLBACK TO SAVEPOINT execute_internal_savepoint");
00182             }
00183             else
00184             {
00185               final_sql.append("RELEASE SAVEPOINT execute_internal_savepoint");
00186             }
00187           }
00188           else
00189           {
00190             if (error_occured)
00191             {
00192               final_sql.append("ROLLBACK");
00193             }
00194             else
00195             {
00196               final_sql.append("COMMIT");
00197             }
00198           }
00199 
00200           // Run the cleanup command, we currently ignore if an error occurs
00201           // here.
00202           (void)runStatement(null_client, final_sql);
00203         }
00204       }
00205 
00206       session().setClient(temp);
00207       if (session().is_error())
00208       {
00209         session().clear_error(true);
00210       }
00211       else
00212       {
00213         session().clearDiagnostics();
00214       }
00215 
00216       session().my_ok();
00217 
00218       null_client->close();
00219       delete null_client;
00220     }
00221     else
00222     {
00223       parse(&session(), to_execute.str, to_execute.length);
00224     }
00225   }
00226 
00227   return true;
00228 }
00229 
00230 } /* namespace statement */
00231 } /* namespace drizzled */
00232