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 void parse(drizzled::Session&, const char *inBuf, uint32_t length);
00036 
00037 namespace statement {
00038 
00039 Execute::Execute(Session *in_session,
00040                  execute_string_t to_execute_arg,
00041                  bool is_quiet_arg,
00042                  bool is_concurrent_arg,
00043                  bool should_wait_arg) :
00044   Statement(in_session),
00045   is_quiet(is_quiet_arg),
00046   is_concurrent(is_concurrent_arg),
00047   should_wait(should_wait_arg),
00048   to_execute(to_execute_arg)
00049 {
00050 }
00051   
00052 
00053 bool statement::Execute::parseVariable()
00054 {
00055   if (to_execute.isVariable())
00056   {
00057     user_var_entry *var= session().getVariable(to_execute, false);
00058 
00059     if (var && var->length && var->value && var->type == STRING_RESULT)
00060     {
00061       lex_string_t tmp_for_var;
00062       tmp_for_var.assign(var->value, var->length); 
00063       to_execute.set(tmp_for_var);
00064 
00065       return true;
00066     }
00067   }
00068 
00069   return false;
00070 }
00071 
00072 
00073 bool statement::Execute::runStatement(plugin::NullClient& client, const std::string &arg)
00074 {
00075   client.pushSQL(arg);
00076   if (not session().executeStatement())
00077     return true;
00078 
00079   if (session().is_error())
00080     return true;
00081 
00082   return false;
00083 }
00084 
00085 
00086 bool statement::Execute::execute()
00087 {
00088   bool ret= execute_shell();
00089 
00090   // We have to restore ourselves at the top for delete() to work.
00091   lex().statement= this;
00092 
00093   return ret;
00094 }
00095 
00096 
00097 bool statement::Execute::execute_shell()
00098 {
00099   if (to_execute.size() == 0)
00100   {
00101     my_error(ER_WRONG_ARGUMENTS, MYF(0), "Invalid Variable");
00102     return false;
00103   }
00104 
00105   if (to_execute.isVariable())
00106   {
00107     if (not parseVariable())
00108     {
00109       my_error(ER_WRONG_ARGUMENTS, MYF(0), "Invalid Variable");
00110       return false;
00111     }
00112   }
00113 
00114   if (is_concurrent)
00115   {
00116     if (not session().isConcurrentExecuteAllowed())
00117     {
00118       my_error(ER_WRONG_ARGUMENTS, MYF(0), "A Concurrent Execution Session can not launch another session.");
00119       return false;
00120     }
00121 
00122     drizzled::Execute executer(session(), should_wait);
00123     executer.run(to_execute);
00124   }
00125   else // Non-concurrent run.
00126   {
00127     if (is_quiet)
00128     {
00129       plugin::Client *temp= session().getClient();
00130       boost::scoped_ptr<plugin::NullClient> null_client(new plugin::NullClient);
00131 
00132       session().setClient(null_client.get());
00133       
00134       bool error_occured= false;
00135       bool is_savepoint= false;
00136       {
00137         std::string start_sql;
00138         if (session().inTransaction())
00139         {
00140           // @todo Figure out something a bit more solid then this.
00141           start_sql= "SAVEPOINT execute_internal_savepoint";
00142           is_savepoint= true;
00143         }
00144         else
00145         {
00146           start_sql= "START TRANSACTION";
00147         }
00148 
00149         error_occured= runStatement(*null_client, start_sql);
00150       }
00151 
00152       // @note this is copied from code in NULL client, all of this belongs
00153       // in the pluggable parser pieces.  
00154       if (not error_occured)
00155       {
00156         typedef boost::tokenizer<boost::escaped_list_separator<char> > Tokenizer;
00157         std::string full_string(to_execute.data(), to_execute.size());
00158         Tokenizer tok(full_string, boost::escaped_list_separator<char>("\\", ";", "\""));
00159 
00160         for (Tokenizer::iterator iter= tok.begin(); iter != tok.end(); ++iter)
00161         {
00162           if (session().getKilled() == Session::KILL_CONNECTION)
00163             break;
00164           if (runStatement(*null_client, *iter))
00165           {
00166             error_occured= true;
00167             break;
00168           }
00169         }
00170 
00171         // @todo Encapsulate logic later to method
00172         {
00173           std::string final_sql;
00174           if (is_savepoint)
00175           {
00176             final_sql= error_occured ? 
00177               "ROLLBACK TO SAVEPOINT execute_internal_savepoint" : 
00178               "RELEASE SAVEPOINT execute_internal_savepoint";
00179           }
00180           else
00181           {
00182             final_sql= error_occured ? "ROLLBACK" : "COMMIT";
00183           }
00184 
00185           // Run the cleanup command, we currently ignore if an error occurs
00186           // here.
00187           (void)runStatement(*null_client, final_sql);
00188         }
00189       }
00190 
00191       session().setClient(temp);
00192       if (session().is_error())
00193       {
00194         session().clear_error(true);
00195       }
00196       else
00197       {
00198         session().clearDiagnostics();
00199       }
00200 
00201       session().my_ok();
00202 
00203       null_client->close();
00204     }
00205     else
00206     {
00207       parse(session(), to_execute.data(), to_execute.size());
00208     }
00209   }
00210 
00211   return true;
00212 }
00213 
00214 } /* namespace statement */
00215 } /* namespace drizzled */
00216