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