Drizzled Public API Documentation

execute.cc
1 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2010 Brian Aker
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <config.h>
22 
23 #include <drizzled/statement/execute.h>
24 #include <drizzled/session.h>
25 #include <drizzled/execute.h>
26 #include <drizzled/user_var_entry.h>
27 #include <drizzled/plugin/listen.h>
28 #include <drizzled/plugin/client.h>
29 #include <drizzled/plugin/null_client.h>
30 #include <drizzled/plugin/client/concurrent.h>
31 #include <drizzled/sql_lex.h>
32 
33 namespace drizzled {
34 
35 void parse(drizzled::Session&, const char *inBuf, uint32_t length);
36 
37 namespace statement {
38 
39 Execute::Execute(Session *in_session,
40  execute_string_t to_execute_arg,
41  bool is_quiet_arg,
42  bool is_concurrent_arg,
43  bool should_wait_arg) :
44  Statement(in_session),
45  is_quiet(is_quiet_arg),
46  is_concurrent(is_concurrent_arg),
47  should_wait(should_wait_arg),
48  to_execute(to_execute_arg)
49 {
50 }
51 
52 
53 bool statement::Execute::parseVariable()
54 {
55  if (to_execute.isVariable())
56  {
57  user_var_entry *var= session().getVariable(to_execute, false);
58 
59  if (var && var->length && var->value && var->type == STRING_RESULT)
60  {
61  lex_string_t tmp_for_var;
62  tmp_for_var.assign(var->value, var->length);
63  to_execute.set(tmp_for_var);
64 
65  return true;
66  }
67  }
68 
69  return false;
70 }
71 
72 
73 bool statement::Execute::runStatement(plugin::NullClient& client, const std::string &arg)
74 {
75  client.pushSQL(arg);
76  if (not session().executeStatement())
77  return true;
78 
79  if (session().is_error())
80  return true;
81 
82  return false;
83 }
84 
85 
87 {
88  bool ret= execute_shell();
89 
90  // We have to restore ourselves at the top for delete() to work.
91  lex().statement= this;
92 
93  return ret;
94 }
95 
96 
97 bool statement::Execute::execute_shell()
98 {
99  if (to_execute.size() == 0)
100  {
101  my_error(ER_WRONG_ARGUMENTS, MYF(0), "Invalid Variable");
102  return false;
103  }
104 
105  if (to_execute.isVariable())
106  {
107  if (not parseVariable())
108  {
109  my_error(ER_WRONG_ARGUMENTS, MYF(0), "Invalid Variable");
110  return false;
111  }
112  }
113 
114  if (is_concurrent)
115  {
116  if (not session().isConcurrentExecuteAllowed())
117  {
118  my_error(ER_WRONG_ARGUMENTS, MYF(0), "A Concurrent Execution Session can not launch another session.");
119  return false;
120  }
121 
122  drizzled::Execute executer(session(), should_wait);
123  executer.run(to_execute);
124  }
125  else // Non-concurrent run.
126  {
127  if (is_quiet)
128  {
129  plugin::Client *temp= session().getClient();
130  boost::scoped_ptr<plugin::NullClient> null_client(new plugin::NullClient);
131 
132  session().setClient(null_client.get());
133 
134  bool error_occured= false;
135  bool is_savepoint= false;
136  {
137  std::string start_sql;
138  if (session().inTransaction())
139  {
140  // @todo Figure out something a bit more solid then this.
141  start_sql= "SAVEPOINT execute_internal_savepoint";
142  is_savepoint= true;
143  }
144  else
145  {
146  start_sql= "START TRANSACTION";
147  }
148 
149  error_occured= runStatement(*null_client, start_sql);
150  }
151 
152  // @note this is copied from code in NULL client, all of this belongs
153  // in the pluggable parser pieces.
154  if (not error_occured)
155  {
156  typedef boost::tokenizer<boost::escaped_list_separator<char> > Tokenizer;
157  std::string full_string(to_execute.data(), to_execute.size());
158  Tokenizer tok(full_string, boost::escaped_list_separator<char>("\\", ";", "\""));
159 
160  for (Tokenizer::iterator iter= tok.begin(); iter != tok.end(); ++iter)
161  {
162  if (session().getKilled() == Session::KILL_CONNECTION)
163  break;
164  if (runStatement(*null_client, *iter))
165  {
166  error_occured= true;
167  break;
168  }
169  }
170 
171  // @todo Encapsulate logic later to method
172  {
173  std::string final_sql;
174  if (is_savepoint)
175  {
176  final_sql= error_occured ?
177  "ROLLBACK TO SAVEPOINT execute_internal_savepoint" :
178  "RELEASE SAVEPOINT execute_internal_savepoint";
179  }
180  else
181  {
182  final_sql= error_occured ? "ROLLBACK" : "COMMIT";
183  }
184 
185  // Run the cleanup command, we currently ignore if an error occurs
186  // here.
187  (void)runStatement(*null_client, final_sql);
188  }
189  }
190 
191  session().setClient(temp);
192  if (session().is_error())
193  {
194  session().clear_error(true);
195  }
196  else
197  {
198  session().clearDiagnostics();
199  }
200 
201  session().my_ok();
202 
203  null_client->close();
204  }
205  else
206  {
207  parse(session(), to_execute.data(), to_execute.size());
208  }
209  }
210 
211  return true;
212 }
213 
214 } /* namespace statement */
215 } /* namespace drizzled */
216