Drizzled Public API Documentation

console.cc
1 /* Copyright (C) 2009 Sun Microsystems, Inc.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include <config.h>
17 #include <drizzled/field.h>
18 #include <drizzled/gettext.h>
19 #include <drizzled/plugin/listen_tcp.h>
20 #include <drizzled/plugin/client.h>
21 #include <drizzled/session.h>
23 #include <drizzled/plugin/catalog.h>
24 #include <drizzled/plugin.h>
25 
26 #include <iostream>
27 
28 #include <boost/program_options.hpp>
29 
30 #include <client/user_detect.h>
31 
32 using namespace std;
33 using namespace drizzled;
34 
35 namespace po= boost::program_options;
36 
37 static bool enabled= false;
38 static bool debug_enabled= false;
39 
40 
41 class ClientConsole: public plugin::Client
42 {
43  bool is_dead;
44  uint32_t column;
45  uint32_t max_column;
46  const std::string &username;
47  const std::string &password;
48  const std::string &schema;
49  const std::string &_catalog;
50 
51 public:
52  ClientConsole(const std::string &username_arg,
53  const std::string &password_arg,
54  const std::string &schema_arg,
55  const std::string &catalog_arg) :
56  is_dead(false),
57  column(0),
58  max_column(0),
59  username(username_arg),
60  password(password_arg),
61  schema(schema_arg),
62  _catalog(catalog_arg)
63  {}
64 
65  virtual void printDebug(const char *message)
66  {
67  if (debug_enabled)
68  cout << "CONSOLE: " << message << endl;
69  }
70 
71  catalog::Instance::shared_ptr catalog()
72  {
73  identifier::Catalog identifier(_catalog);
74  catalog::Instance::shared_ptr tmp= plugin::Catalog::getInstance(identifier);
75  if (not tmp)
76  {
77  std::cerr << "Invalid catalog '" << identifier << "', resorting to 'local' catalog" << std::endl;
78  }
79  return tmp;
80  }
81 
82  virtual int getFileDescriptor(void)
83  {
84  printDebug("getFileDescriptor");
85  return 0;
86  }
87 
88  virtual bool isConnected(void)
89  {
90  printDebug("isConnected");
91  return true;
92  }
93 
94  virtual bool flush(void)
95  {
96  printDebug("flush");
97  return false;
98  }
99 
100  virtual void close(void)
101  {
102  printDebug("close");
103  is_dead= true;
104  }
105 
106  virtual bool authenticate(void)
107  {
108  printDebug("authenticate");
109  identifier::user::mptr user= identifier::User::make_shared();
110  user->setUser(username);
111  session->setUser(user);
112 
113  return session->checkUser(password, schema);
114  }
115 
116  virtual bool readCommand(char **packet, uint32_t& packet_length)
117  {
118  uint32_t length;
119 
120  if (is_dead)
121  return false;
122 
123  cout << "drizzled> ";
124 
125  length= 1024;
126  *packet= NULL;
127 
128  /* Start with 1 byte offset so we can set command. */
129  packet_length= 1;
130 
131  do
132  {
133  *packet= (char *)realloc(*packet, length);
134  if (*packet == NULL)
135  return false;
136 
137  cin.clear();
138  cin.getline(*packet + packet_length, length - packet_length, ';');
139  packet_length+= cin.gcount();
140  length*= 2;
141  }
142  while (cin.eof() == false && cin.fail() == true);
143 
144  if ((packet_length == 1 && cin.eof() == true) or
145  not strncasecmp(*packet + 1, "quit", 4) or
146  not strncasecmp(*packet + 1, "exit", 4) or
147  not strncasecmp(*packet + 1, "shutdown", sizeof("shutdown") -1))
148  {
149  is_dead= true;
150  packet_length= 1;
151  (*packet)[0]= COM_SHUTDOWN;
152 
153  return true;
154  }
155 
156  /* Skip \r and \n for next time. */
157  cin.ignore(2, '\n');
158 
159  (*packet)[0]= COM_QUERY;
160 
161  return true;
162  }
163 
164  virtual void sendOK(void)
165  {
166  cout << "OK" << endl;
167  }
168 
169  virtual void sendEOF(void)
170  {
171  printDebug("sendEOF");
172  }
173 
174  virtual void sendError(const drizzled::error_t sql_errno, const char *err)
175  {
176  cout << "Error: " << static_cast<long>(sql_errno) << " " << err << endl;
177  }
178 
179  virtual void sendFields(List<Item>& list)
180  {
181  List<Item>::iterator it(list.begin());
182 
183  column= 0;
184  max_column= 0;
185 
186  while (Item* item=it++)
187  {
188  SendField field;
189  item->make_field(&field);
190  cout << field.col_name << "\t";
191  max_column++;
192  }
193  cout << endl;
194  }
195 
196  virtual void checkRowEnd(void)
197  {
198  if (++column % max_column == 0)
199  cout << endl;
200  }
201 
202  using Client::store;
203 
204  virtual void store(Field *from)
205  {
206  if (from->is_null())
207  return store();
208 
209  char buff[MAX_FIELD_WIDTH];
210  String str(buff, sizeof(buff), &my_charset_bin);
211  from->val_str_internal(&str);
212  return store(str.ptr(), str.length());
213  }
214 
215  virtual void store(void)
216  {
217  cout << "NULL" << "\t";
218  checkRowEnd();
219  }
220 
221  virtual void store(int32_t from)
222  {
223  cout << from << "\t";
224  checkRowEnd();
225  }
226 
227  virtual void store(uint32_t from)
228  {
229  cout << from << "\t";
230  checkRowEnd();
231  }
232 
233  virtual void store(int64_t from)
234  {
235  cout << from << "\t";
236  checkRowEnd();
237  }
238 
239  virtual void store(uint64_t from)
240  {
241  cout << from << "\t";
242  checkRowEnd();
243  }
244 
245  virtual void store(double from, uint32_t decimals, String *buffer)
246  {
247  buffer->set_real(from, decimals, &my_charset_bin);
248  store(buffer->ptr(), buffer->length());
249  }
250 
251  virtual void store(const char *from, size_t length)
252  {
253  cout.write(from, length);
254  cout << "\t";
255  checkRowEnd();
256  }
257 
258  virtual bool haveError()
259  {
260  printDebug("haveError");
261  return false;
262  }
263 
264  virtual bool wasAborted()
265  {
266  printDebug("wasAborted");
267  return false;
268  }
269 
270  bool isConsole() const
271  {
272  return true;
273  }
274 
275  bool isInteractive() const
276  {
277  return true;
278  }
279 };
280 
281 class ListenConsole: public plugin::Listen
282 {
283  int pipe_fds[2];
284  const std::string username;
285  const std::string password;
286  const std::string schema;
287  const std::string _catalog;
288 
289 public:
290  ListenConsole(const std::string &name_arg,
291  const std::string &username_arg,
292  const std::string &password_arg,
293  const std::string &schema_arg,
294  const std::string &catalog_arg) :
295  plugin::Listen(name_arg),
296  username(username_arg),
297  password(password_arg),
298  schema(schema_arg),
299  _catalog(catalog_arg)
300  {
301  pipe_fds[0]= -1;
302  }
303 
304  virtual ~ListenConsole()
305  {
306  if (pipe_fds[0] != -1)
307  {
308  close(pipe_fds[0]);
309  close(pipe_fds[1]);
310  }
311  }
312 
313  virtual bool getFileDescriptors(std::vector<int> &fds)
314  {
315  if (debug_enabled)
316  enabled= true;
317 
318  if (not enabled)
319  return false;
320 
321  if (pipe(pipe_fds) == -1)
322  {
323  errmsg_printf(error::ERROR, _("pipe() failed with errno %d"), errno);
324  return true;
325  }
326 
327  fds.push_back(pipe_fds[0]);
328  assert(write(pipe_fds[1], "\0", 1) == 1);
329  return false;
330  }
331 
332  virtual drizzled::plugin::Client *getClient(int fd)
333  {
334  char buffer[1];
335  assert(read(fd, buffer, 1) == 1);
336 
337  return new ClientConsole(username, password, schema, _catalog);
338  }
339 };
340 
341 static int init(drizzled::module::Context &context)
342 {
343  const module::option_map &vm= context.getOptions();
344  context.add(new ListenConsole("console", vm["username"].as<string>(),
345  vm["password"].as<string>(), vm["schema"].as<string>(), vm["catalog"].as<string>()));
346  return 0;
347 }
348 
349 static void init_options(drizzled::module::option_context &context)
350 {
351  context("enable",
352  po::value<bool>(&enabled)->default_value(false)->zero_tokens(),
353  N_("Enable the console."));
354  context("debug",
355  po::value<bool>(&debug_enabled)->default_value(false)->zero_tokens(),
356  N_("Turn on extra debugging."));
357  UserDetect detected_user;
358  const char* shell_user= detected_user.getUser();
359  context("username",
360  po::value<string>()->default_value(shell_user ? shell_user : ""),
361  N_("User to use for auth."));
362  context("password",
363  po::value<string>()->default_value(""),
364  N_("Password to use for auth."));
365  context("catalog",
366  po::value<string>()->default_value("LOCAL"),
367  N_("Default catalog to use."));
368  context("schema",
369  po::value<string>()->default_value(""),
370  N_("Default schema to use."));
371 }
372 
373 DRIZZLE_DECLARE_PLUGIN
374 {
375  DRIZZLE_VERSION_ID,
376  "console",
377  "0.2",
378  "Eric Day",
379  N_("Console client"),
380  PLUGIN_LICENSE_BSD,
381  init,
382  NULL,
383  init_options
384 }
385 DRIZZLE_DECLARE_PLUGIN_END;
bool checkUser(const std::string &passwd, const std::string &db)
Definition: session.cc:659
TODO: Rename this file - func.h is stupid.
An Proxy Wrapper around boost::program_options::variables_map.