Drizzled Public API Documentation

console.cc
00001 /* Copyright (C) 2009 Sun Microsystems, Inc.
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 #include <config.h>
00017 #include <drizzled/field.h>
00018 #include <drizzled/gettext.h>
00019 #include <drizzled/plugin/listen_tcp.h>
00020 #include <drizzled/plugin/client.h>
00021 #include <drizzled/session.h>
00022 #include <drizzled/module/option_map.h>
00023 #include <drizzled/plugin/catalog.h>
00024 #include <drizzled/plugin.h>
00025 
00026 #include <iostream>
00027 
00028 #include <boost/program_options.hpp>
00029 
00030 #include <client/user_detect.h>
00031 
00032 using namespace std;
00033 using namespace drizzled;
00034 
00035 namespace po= boost::program_options;
00036 
00037 static bool enabled= false;
00038 static bool debug_enabled= false;
00039 
00040 
00041 class ClientConsole: public plugin::Client
00042 {
00043   bool is_dead;
00044   uint32_t column;
00045   uint32_t max_column;
00046   const std::string &username;
00047   const std::string &password;
00048   const std::string &schema;
00049   const std::string &_catalog;
00050 
00051 public:
00052   ClientConsole(const std::string &username_arg,
00053                 const std::string &password_arg,
00054                 const std::string &schema_arg,
00055                 const std::string &catalog_arg) :
00056     is_dead(false),
00057     column(0),
00058     max_column(0),
00059     username(username_arg),
00060     password(password_arg),
00061     schema(schema_arg),
00062     _catalog(catalog_arg)
00063   {}
00064 
00065   virtual void printDebug(const char *message)
00066   {
00067     if (debug_enabled)
00068       cout << "CONSOLE: " << message << endl;
00069   }
00070 
00071   catalog::Instance::shared_ptr catalog()
00072   {
00073     identifier::Catalog identifier(_catalog);
00074     catalog::Instance::shared_ptr tmp= plugin::Catalog::getInstance(identifier);
00075     if (not tmp)
00076     {
00077       std::cerr << "Invalid catalog '" << identifier << "', resorting to 'local' catalog" << std::endl;
00078     }
00079     return tmp;
00080   }
00081 
00082   virtual int getFileDescriptor(void)
00083   {
00084     printDebug("getFileDescriptor");
00085     return 0;
00086   }
00087 
00088   virtual bool isConnected(void)
00089   {
00090     printDebug("isConnected");
00091     return true;
00092   }
00093 
00094   virtual bool flush(void)
00095   {
00096     printDebug("flush");
00097     return false;
00098   }
00099 
00100   virtual void close(void)
00101   {
00102     printDebug("close");
00103     is_dead= true;
00104   }
00105 
00106   virtual bool authenticate(void)
00107   {
00108     printDebug("authenticate");
00109     identifier::user::mptr user= identifier::User::make_shared();
00110     user->setUser(username);
00111     session->setUser(user);
00112 
00113     return session->checkUser(password, schema);
00114   }
00115 
00116   virtual bool readCommand(char **packet, uint32_t& packet_length)
00117   {
00118     uint32_t length;
00119 
00120     if (is_dead)
00121       return false;
00122 
00123     cout << "drizzled> ";
00124 
00125     length= 1024;
00126     *packet= NULL;
00127 
00128     /* Start with 1 byte offset so we can set command. */
00129     packet_length= 1;
00130 
00131     do
00132     {
00133       *packet= (char *)realloc(*packet, length);
00134       if (*packet == NULL)
00135         return false;
00136 
00137       cin.clear();
00138       cin.getline(*packet + packet_length, length - packet_length, ';');
00139       packet_length+= cin.gcount();
00140       length*= 2;
00141     }
00142     while (cin.eof() == false && cin.fail() == true);
00143 
00144     if ((packet_length == 1 && cin.eof() == true) or
00145         not strncasecmp(*packet + 1, "quit", 4) or
00146         not strncasecmp(*packet + 1, "exit", 4) or
00147         not strncasecmp(*packet + 1, "shutdown", sizeof("shutdown") -1))
00148     {
00149       is_dead= true;
00150       packet_length= 1;
00151       (*packet)[0]= COM_SHUTDOWN;
00152 
00153       return true;
00154     }
00155 
00156     /* Skip \r and \n for next time. */
00157     cin.ignore(2, '\n');
00158 
00159     (*packet)[0]= COM_QUERY;
00160 
00161     return true;
00162   }
00163 
00164   virtual void sendOK(void)
00165   {
00166     cout << "OK" << endl;
00167   }
00168 
00169   virtual void sendEOF(void)
00170   {
00171     printDebug("sendEOF");
00172   }
00173 
00174   virtual void sendError(const drizzled::error_t sql_errno, const char *err)
00175   {
00176     cout << "Error: " << static_cast<long>(sql_errno) << " " << err << endl;
00177   }
00178 
00179   virtual void sendFields(List<Item>& list)
00180   {
00181     List<Item>::iterator it(list.begin());
00182 
00183     column= 0;
00184     max_column= 0;
00185 
00186     while (Item* item=it++)
00187     {
00188       SendField field;
00189       item->make_field(&field);
00190       cout << field.col_name << "\t";
00191       max_column++;
00192     }
00193     cout << endl;
00194   }
00195 
00196   virtual void checkRowEnd(void)
00197   {
00198     if (++column % max_column == 0)
00199       cout << endl;
00200   }
00201 
00202   using Client::store;
00203 
00204   virtual void store(Field *from)
00205   {
00206     if (from->is_null())
00207       return store();
00208 
00209     char buff[MAX_FIELD_WIDTH];
00210     String str(buff, sizeof(buff), &my_charset_bin);
00211     from->val_str_internal(&str);
00212     return store(str.ptr(), str.length());
00213   }
00214 
00215   virtual void store(void)
00216   {
00217     cout << "NULL" << "\t";
00218     checkRowEnd();
00219   }
00220 
00221   virtual void store(int32_t from)
00222   {
00223     cout << from << "\t";
00224     checkRowEnd();
00225   }
00226 
00227   virtual void store(uint32_t from)
00228   {
00229     cout << from << "\t";
00230     checkRowEnd();
00231   }
00232 
00233   virtual void store(int64_t from)
00234   {
00235     cout << from << "\t";
00236     checkRowEnd();
00237   }
00238 
00239   virtual void store(uint64_t from)
00240   {
00241     cout << from << "\t";
00242     checkRowEnd();
00243   }
00244 
00245   virtual void store(double from, uint32_t decimals, String *buffer)
00246   {
00247     buffer->set_real(from, decimals, &my_charset_bin);
00248     store(buffer->ptr(), buffer->length());
00249   }
00250 
00251   virtual void store(const char *from, size_t length)
00252   {
00253     cout.write(from, length);
00254     cout << "\t";
00255     checkRowEnd();
00256   }
00257 
00258   virtual bool haveError()
00259   {
00260     printDebug("haveError");
00261     return false;
00262   }
00263 
00264   virtual bool wasAborted()
00265   {
00266     printDebug("wasAborted");
00267     return false;
00268   }
00269 
00270   bool isConsole() const
00271   {
00272     return true;
00273   }
00274 
00275   bool isInteractive() const
00276   {
00277     return true;
00278   }
00279 };
00280 
00281 class ListenConsole: public plugin::Listen
00282 {
00283   int pipe_fds[2];
00284   const std::string username;
00285   const std::string password;
00286   const std::string schema;
00287   const std::string _catalog;
00288 
00289 public:
00290   ListenConsole(const std::string &name_arg,
00291                 const std::string &username_arg,
00292                 const std::string &password_arg,
00293                 const std::string &schema_arg,
00294                 const std::string &catalog_arg) :
00295     plugin::Listen(name_arg),
00296     username(username_arg),
00297     password(password_arg),
00298     schema(schema_arg),
00299     _catalog(catalog_arg)
00300   {
00301     pipe_fds[0]= -1;
00302   }
00303 
00304   virtual ~ListenConsole()
00305   {
00306     if (pipe_fds[0] != -1)
00307     {
00308       close(pipe_fds[0]);
00309       close(pipe_fds[1]);
00310     }
00311   }
00312 
00313   virtual bool getFileDescriptors(std::vector<int> &fds)
00314   {
00315     if (debug_enabled)
00316       enabled= true;
00317 
00318     if (not enabled)
00319       return false;
00320 
00321     if (pipe(pipe_fds) == -1)
00322     {
00323       errmsg_printf(error::ERROR, _("pipe() failed with errno %d"), errno);
00324       return true;
00325     }
00326 
00327     fds.push_back(pipe_fds[0]);
00328     assert(write(pipe_fds[1], "\0", 1) == 1);
00329     return false;
00330   }
00331 
00332   virtual drizzled::plugin::Client *getClient(int fd)
00333   {
00334     char buffer[1];
00335     assert(read(fd, buffer, 1) == 1);
00336 
00337     return new ClientConsole(username, password, schema, _catalog);
00338   }
00339 };
00340 
00341 static int init(drizzled::module::Context &context)
00342 {
00343   const module::option_map &vm= context.getOptions();
00344   context.add(new ListenConsole("console", vm["username"].as<string>(), 
00345     vm["password"].as<string>(), vm["schema"].as<string>(), vm["catalog"].as<string>()));
00346   return 0;
00347 }
00348 
00349 static void init_options(drizzled::module::option_context &context)
00350 {
00351   context("enable",
00352           po::value<bool>(&enabled)->default_value(false)->zero_tokens(),
00353           N_("Enable the console."));
00354   context("debug",
00355           po::value<bool>(&debug_enabled)->default_value(false)->zero_tokens(),
00356           N_("Turn on extra debugging."));
00357   UserDetect detected_user;
00358   const char* shell_user= detected_user.getUser();
00359   context("username",
00360           po::value<string>()->default_value(shell_user ? shell_user : ""),
00361           N_("User to use for auth."));
00362   context("password",
00363           po::value<string>()->default_value(""),
00364           N_("Password to use for auth."));
00365   context("catalog",
00366           po::value<string>()->default_value("LOCAL"),
00367           N_("Default catalog to use."));
00368   context("schema",
00369           po::value<string>()->default_value(""),
00370           N_("Default schema to use."));
00371 }
00372 
00373 DRIZZLE_DECLARE_PLUGIN
00374 {
00375   DRIZZLE_VERSION_ID,
00376   "console",
00377   "0.2",
00378   "Eric Day",
00379   "Console Client",
00380   PLUGIN_LICENSE_BSD,
00381   init,   /* Plugin Init */
00382   NULL,   /* depends */
00383   init_options    /* config options */
00384 }
00385 DRIZZLE_DECLARE_PLUGIN_END;