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
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
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
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,
00412 NULL,
00413 init_options
00414 }
00415 DRIZZLE_DECLARE_PLUGIN_END;