00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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,
00382 NULL,
00383 init_options
00384 }
00385 DRIZZLE_DECLARE_PLUGIN_END;