gStore/Main/gconsole.cpp

1100 lines
26 KiB
C++
Raw Normal View History

/*=============================================================================
# Filename: gconsole.cpp
2016-09-18 20:01:57 +08:00
# Author: Bookug Lobert, modified by Wang Libo
# Mail: 1181955272@qq.com
2016-09-18 20:01:57 +08:00
# Last Modified: 2016-07-20 19:28
# Description:
This is a console integrating all commands in Gstore System and others. It
provides completion of command names, line editing features, and access to the
2016-09-18 20:01:57 +08:00
history list.
2016-05-16 03:16:22 +08:00
NOTICE: no separators required in the end of your commands, and please just type
2016-09-18 20:01:57 +08:00
one command at a time. If there are many instructions to execute, please write
2016-05-16 03:16:22 +08:00
them in a file like test.sql, and tell the gconsole to use this file
=============================================================================*/
#include "../Database/Database.h"
#include "../Util/Util.h"
#include "GstoreConnector.h"
using namespace std;
2016-05-16 03:16:22 +08:00
//NOTICE: not imitate the usage of gload/gquery/gclient/gserver in command line
//but need to support the query scripts(so support parameters indirectly)
//The names of functions that actually do the manipulation.
//common commands
2016-09-18 20:01:57 +08:00
int help_handler (const vector<string>&);
int source_handler (const vector<string>&);
int quit_handler (const vector<string>&);
//C/S commands
2016-09-18 20:01:57 +08:00
int connect_handler (const vector<string>&);
int disconnect_handler (const vector<string>&);
//system commands
2016-09-18 20:01:57 +08:00
int list_handler (const vector<string>&);
int view_handler (const vector<string>&);
int rename_handler (const vector<string>&);
int stat_handler (const vector<string>&);
int pwd_handler (const vector<string>&);
int delete_handler (const vector<string>&);
int cd_handler (const vector<string>&);
// server commands
int start_handler (const vector<string>&);
int stop_handler (const vector<string>&);
//remote commands
2016-09-18 20:01:57 +08:00
int build_handler (const vector<string>&);
int drop_handler (const vector<string>&);
int load_handler (const vector<string>&);
int unload_handler (const vector<string>&);
int query_handler (const vector<string>&);
int show_handler (const vector<string>&);
//A structure which contains information on the commands this program can understand.
typedef struct {
2016-09-18 20:01:57 +08:00
const char *name; // User printable name of the function
int (*func)(const vector<string>&); // Function to call to do the job
const char *doc; // Documentation for this function
} COMMAND;
//
COMMAND native_commands[] = {
2016-09-18 20:01:57 +08:00
{ "help", help_handler, "Display this text." },
{ "?", help_handler, "Synonym for \"help\"." },
{ "source", source_handler, "Use a file containing SPARQL queries." },
{ "quit", quit_handler, "Quit this console." },
{ "connect", connect_handler, "Connect to a server running Gstore." },
{ "show", show_handler, "Show the database name which is used now." },
{ "build", build_handler, "Build a database from a dataset." },
{ "drop", drop_handler, "Drop a database according to the given path." },
{ "load", load_handler, "Load a existing database." },
{ "unload", unload_handler, "Unload the current used database." },
{ "query", query_handler, "Answer a SPARQL query." },
{ "start", start_handler, "Start local server." },
{ NULL, NULL, NULL }
};
//
COMMAND remote_commands[] = {
2016-09-18 20:01:57 +08:00
{ "help", help_handler, "Display this text." },
{ "?", help_handler, "Synonym for \"help\"." },
{ "source", source_handler, "Use a file containing SPARQL queries." },
{ "show", show_handler, "Show the database name which is used now." },
{ "build", build_handler, "Build a database from a dataset." },
{ "drop", drop_handler, "Drop a database according to the given path." },
{ "load", load_handler, "Load a existing database." },
{ "unload", unload_handler, "Unload the current used database." },
{ "query", query_handler, "Answer a SPARQL query." },
{ "disconnect", disconnect_handler, "Disconnect the current server connection." },
{ "stop", stop_handler, "Stop server and disconnect." },
{ NULL, NULL, NULL }
};
COMMAND *current_commands = native_commands; //according to gc ?= NULL
char *dupstr(const char*);
char *stripwhite(char *);
COMMAND *find_command(char *);
void initialize_readline();
int execute_line(char *);
2016-05-16 03:16:22 +08:00
int deal_with_script(char *);
2016-09-18 20:01:57 +08:00
bool parse_arguments(char *, vector<string>&);
int save_history();
int load_history();
// Global variables
//The name of this program, as taken from argv[0].
char *progname;
//
//When true, this global means the user is done using this program.
bool done = false; //still running
//server-client mode or local engine mode
GstoreConnector *gc = NULL; //local mode by default
//redirect mechanism, only useful for query
2016-09-18 20:01:57 +08:00
FILE* output = stdout;
//current using database in local
Database *current_database = NULL;
2016-09-18 20:01:57 +08:00
//TODO:redirect 2>&1 or adjust the fprintf->stderr to file pointer
int
main(int argc, char **argv)
{
2016-05-16 03:16:22 +08:00
//NOTICE:this is needed to ensure the file path is the work path
//chdir(dirname(argv[0]));
//NOTICE:this is needed to set several debug files
2016-09-18 20:01:57 +08:00
#ifdef DEBUG
Util util;
#endif
char *line, *s;
progname = argv[0];
2016-09-18 20:01:57 +08:00
system("clear");
2016-05-16 03:16:22 +08:00
//the info to be printed
2016-09-18 20:01:57 +08:00
cout << endl;
cout << "Gstore Console(gconsole), an interactive shell based utility to communicate with gStore repositories." << endl;
cout << "usage: start-gconsole [OPTION]" << endl;
cout << " -h, --help print this help" << endl;
cout << " -s, --source source the SPARQL script" << endl;
cout << "For bug reports and suggestions, see https://github.com/Caesar11/gStore" << endl << endl << endl;
if (argc > 1)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
cout << "Type \"?\" or \"help\" in the console to see info of all commands" << endl;
if (argc > 2) {
cerr << "Nonsense to add more parameters!" << endl;
}
return 0;
2016-05-16 03:16:22 +08:00
}
2016-09-18 20:01:57 +08:00
else if (strcmp(argv[1], "-s") == 0 || strcmp(argv[1], "--source") == 0)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
if (argc != 3)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
cerr << "You should just add one script file to be sourced!" << endl;
return 1;
2016-05-16 03:16:22 +08:00
}
return deal_with_script(argv[2]);
}
else
{
2016-09-18 20:01:57 +08:00
cerr << "Wrong option used, please see the help info first!" << endl;
return 1;
2016-05-16 03:16:22 +08:00
}
}
2016-09-18 20:01:57 +08:00
cout << "Notice that commands are a little different between native mode and remote mode." << endl;
cout << "Now is in native mode, please type your commands." << endl;
cout << "Please do not use any separators in the end." << endl << endl;
2016-09-18 20:01:57 +08:00
initialize_readline(); //Bind our completer
using_history();
load_history();
2016-09-18 20:01:57 +08:00
//Loop reading and executing lines until the user quits.
while (!done)
{
if (gc == NULL) {
line = readline("gstore>");
}
else {
line = readline("server>");
}
2016-09-18 20:01:57 +08:00
//BETTER:multi lines input in alignment?need separators like ';' in gclient.cpp
2016-05-16 03:16:22 +08:00
//For simplicity, we do not use this feature here.
2016-09-18 20:01:57 +08:00
if (line == NULL) //EOF or Ctrl-D
{
if (current_database != NULL)
{
2016-09-18 20:01:57 +08:00
cerr << endl << "Please unload your database before quiting!" << endl << endl;
continue;
}
2016-09-18 20:01:57 +08:00
cout << endl << endl;
break;
}
2016-09-18 20:01:57 +08:00
//Remove leading and trailing whitespace from the line.
//Then, if there is anything left, add it to the history
//list and execute it.
s = stripwhite(line);
if (*s)
{
add_history(s);
execute_line(s);
}
free(line);
}
save_history();
exit(0);
}
/* **************************************************************** */
/* */
/* Some Utilities */
/* */
/* **************************************************************** */
char *
dupstr(const char *s)
{
2016-09-18 20:01:57 +08:00
char *r;
int len = strlen(s) + 1;
r = (char *)malloc(len); //BETTER:xmalloc?
memset(r, 0, sizeof(char) * (len));
strcpy(r, s);
return r;
}
// Execute a command line
int
execute_line(char *line)
{
2016-09-18 20:01:57 +08:00
int i;
COMMAND *cmd;
char *word = NULL;
//to find if redirected
bool is_redirected = false;
int j = strlen(line) - 1;
while (j > -1)
{
if (line[j] == '"')
break;
else if (line[j] == '>')
{
is_redirected = true;
i = j;
break;
}
else
j--;
}
if (is_redirected)
{
j++;
while (line[j] && whitespace(line[j]))
{
j++;
}
cout << "The file is: " << (line + j) << endl;
output = fopen(line + j, "w+");
if (output == NULL) {
cout << "Failed to open " << (line + j) << endl;
output = stdout;
}
line[i] = '\0';
2016-09-18 20:01:57 +08:00
}
//BETTER: how about >> ?
2016-09-18 20:01:57 +08:00
//Isolate the command word.
i = 0;
while (line[i] && whitespace(line[i]))
i++;
2016-09-18 20:01:57 +08:00
word = line + i;
2016-09-18 20:01:57 +08:00
while (line[i] && !whitespace(line[i]))
i++;
2016-09-18 20:01:57 +08:00
if (line[i])
line[i++] = '\0';
2016-09-18 20:01:57 +08:00
cmd = find_command(word);
2016-09-18 20:01:57 +08:00
if (!cmd)
{
if (gc == NULL) {
cout << "Now is in native mode!" << endl;
}
else {
cout << "Now is in remote mode!" << endl;
}
cout << word << ": No such command for gconsole" << endl << endl;
if (output != stdout) {
fclose(output);
2016-09-18 20:01:57 +08:00
output = stdout;
}
return -1;
}
2016-09-18 20:01:57 +08:00
//Get argument to command, if any.
while (line[i] && whitespace(line[i]))
i++;
word = line + i;
//cout << word << endl; //debug
2016-09-18 20:01:57 +08:00
vector<string> args;
int ret;
if (parse_arguments(word, args)) {
ret = cmd->func(args);
}
else {
ret = -1;
}
2016-05-16 03:16:22 +08:00
#ifdef DEBUG_PRECISE
2016-09-18 20:01:57 +08:00
msg << "All done, now to close the file." << endl;
#endif
2016-09-18 20:01:57 +08:00
if (output != stdout) {
fclose(output);
output = stdout;
}
cout << endl;
return ret;
}
// Look up NAME as the name of a command, and return a pointer to that
// command. Return a NULL pointer if NAME isn't a command name.
COMMAND *
find_command(char *name)
{
2016-09-18 20:01:57 +08:00
int i;
2016-09-18 20:01:57 +08:00
for (i = 0; current_commands[i].name; i++)
{
2016-09-18 20:01:57 +08:00
if (strcmp(name, current_commands[i].name) == 0)
return &current_commands[i];
}
2016-09-18 20:01:57 +08:00
return (COMMAND*)NULL;
}
2016-09-18 20:01:57 +08:00
// Strip whitespace from the start and end of STRING. Return a pointer into STRING.
char *
stripwhite(char *string)
{
2016-09-18 20:01:57 +08:00
char *s, *t;
2016-09-18 20:01:57 +08:00
for (s = string; whitespace(*s); s++);
2016-09-18 20:01:57 +08:00
if (*s == 0)
return s;
2016-09-18 20:01:57 +08:00
t = s + strlen(s) - 1;
while (t > s && (whitespace(*t) || *t == '\r' || *t == '\n')) {
t--;
}
*++t = '\0';
2016-09-18 20:01:57 +08:00
return s;
}
2016-05-16 03:16:22 +08:00
//support commands scripts
//QUERY:source another file again(how about exactly this script twice or more)
2016-09-18 20:01:57 +08:00
int deal_with_script(char* file) {
2016-05-16 03:16:22 +08:00
FILE* fp = NULL;
2016-09-18 20:01:57 +08:00
if ((fp = fopen(file, "r")) == NULL)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
cerr << "Open error: " << file << endl;
2016-05-16 03:16:22 +08:00
return -1;
}
2016-09-18 20:01:57 +08:00
//WARN:the length of each line in the script should not exceed 500
2016-05-16 03:16:22 +08:00
char line[505], *s = NULL;
2016-09-18 20:01:57 +08:00
while ((fgets(line, 501, fp)) != NULL)
2016-05-16 03:16:22 +08:00
{
//NOTICE:empty line here also contains '\n'
2016-09-18 20:01:57 +08:00
if (strlen(line) == 1)
2016-05-16 03:16:22 +08:00
continue;
s = stripwhite(line);
2016-09-18 20:01:57 +08:00
if (*s)
2016-05-16 03:16:22 +08:00
{
execute_line(s);
}
}
2016-09-18 20:01:57 +08:00
2016-05-16 03:16:22 +08:00
//end of file
2016-09-18 20:01:57 +08:00
if (current_database != NULL)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
cerr << endl << "Please unload your database before quitting!" << endl << endl;
2016-05-16 03:16:22 +08:00
//TODO
}
2016-09-18 20:01:57 +08:00
if (gc != NULL)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
cerr << endl << "Please return to native mode before quitting!" << endl << endl;
2016-05-16 03:16:22 +08:00
//TODO
}
return 0;
}
2016-09-18 20:01:57 +08:00
// Parse arguments
bool parse_arguments(char* word, vector<string>& args) {
if (word == NULL) {
return true;
}
while (*word) {
int i = 0;
if (*word == '\"') {
i++;
while (word[i] && word[i] != '\"') {
i++;
}
char tmp = word[i + 1];
if (word[i] == '\"' && (whitespace(tmp) || tmp == '\0')) {
word[++i] = '\0';
args.push_back(string(word));
//cout << args.size() - 1 << '\t' << args.back() << endl; //debug
word[i] = tmp;
while (word[i] && whitespace(word[i])) {
i++;
}
word += i;
continue;
}
else {
cerr << "Invalid arguments!" << endl;
return false;
}
}
while (word[i] && !whitespace(word[i])) {
i++;
}
char tmp = word[i];
word[i] = '\0';
args.push_back(string(word));
//cout << args.size() - 1 << '\t' << args.back() << endl; //debug
word[i] = tmp;
while (word[i] && whitespace(word[i])) {
i++;
}
word += i;
}
return true;
}
// Save command history
// Notice that only by quitting gconsole normally can command history be saved
int save_history() {
//Limit the number of history to save
static const int max_history = 1024;
stifle_history(max_history);
HIST_ENTRY ** pHisList = history_list();
if (pHisList == NULL) {
return 0;
}
ofstream fout("bin/.gconsole_history", ios::out);
if (!fout) {
return -1;
}
while (pHisList[0] != NULL) {
fout << string(pHisList[0]->line) << endl;
pHisList++;
}
fout.close();
return 0;
}
// Load command history
int load_history() {
ifstream fin("bin/.gconsole_history", ios::in);
if (!fin) {
return -1;
}
const int line_length = 1024;
char line[line_length];
while (fin.getline(line, line_length)) {
add_history(line);
}
fin.close();
return 0;
}
/* **************************************************************** */
/* */
/* Interface to Readline Completion */
/* */
/* **************************************************************** */
2016-09-18 20:01:57 +08:00
char *command_generator (const char *, int);
char **gconsole_completion (const char *, int, int);
/* Tell the GNU Readline library how to complete. We want to try to complete
2016-09-18 20:01:57 +08:00
on command names if this is the first word in the line, or on filenames
if not. */
void
initialize_readline()
{
2016-09-18 20:01:57 +08:00
/* Allow conditional parsing of the ~/.inputrc file. */
rl_readline_name = "gconsole";
2016-09-18 20:01:57 +08:00
/* Tell the completer that we want a crack first. */
rl_attempted_completion_function = gconsole_completion;
}
2016-09-18 20:01:57 +08:00
/* Attempt to complete on the contents of TEXT. START and END bound the
region of rl_line_buffer that contains the word to complete. TEXT is
the word to complete. We can use the entire contents of rl_line_buffer
in case we want to do some simple parsing. Return the array of matches,
or NULL if there aren't any. */
char **
gconsole_completion(const char *text, int start, int end)
{
2016-09-18 20:01:57 +08:00
char **matches;
2016-09-18 20:01:57 +08:00
matches = (char **)NULL;
2016-09-18 20:01:57 +08:00
//If this word is at the start of the line, then it is a command
//to complete. Otherwise it is the name of a file in the current directory.
if (start == 0) {
matches = rl_completion_matches(text, command_generator);
}
2016-09-18 20:01:57 +08:00
return matches;
}
2016-09-18 20:01:57 +08:00
/* Generator function for command completion. STATE lets us know whether
to start from scratch; without any state(i.e. STATE == 0), then we
start at the top of the list. */
char *
command_generator(const char *text, int state)
{
2016-09-18 20:01:57 +08:00
static int list_index, len;
const char *name;
2016-09-18 20:01:57 +08:00
/* If this is a new word to complete, initialize now. This includes
saving the length of TEXT for efficiency, and initializing the index
variable to 0. */
if (!state)
{
list_index = 0;
len = strlen(text);
}
2016-09-18 20:01:57 +08:00
/* Return the next name which partially matches from the command list. */
while ((name = current_commands[list_index].name) != NULL)
{
list_index++;
if (strncmp(name, text, len) == 0)
return dupstr(name);
}
/* If no names matched, then return NULL. */
return (char *)NULL;
}
/* **************************************************************** */
/* */
/* gconsole commands */
/* */
/* **************************************************************** */
//Print out help for ARG, or for all of the commands if ARG is not present.
2016-09-18 20:01:57 +08:00
int help_handler(const vector<string>& args) {
switch (args.size()) {
case 0:
{
int i;
for (i = 0; current_commands[i].name; i++) {
cout << current_commands[i].name << "\t\t" << current_commands[i].doc << endl;
}
break;
}
case 1:
{
int i;
int printed = 0;
for (i = 0; current_commands[i].name; i++) {
if (args[0] == current_commands[i].name) {
cout << current_commands[i].name << "\t\t" << current_commands[i].doc << endl;
printed++;
break;
}
}
if (printed == 0) {
cerr << "No commands match \"" << args[0] << "\". Possibilities are:" << endl;
for (i = 0; current_commands[i].name; i++)
{
//Print in six columns.
if (printed == 6)
{
printed = 0;
cout << endl;
}
cout << current_commands[i].name << '\t';
printed++;
}
if (printed) {
cout << endl;
}
}
break;
}
default:
{
cerr << "Too many arguments!" << endl;
return -1;
}
}
return 0;
}
2016-05-16 03:16:22 +08:00
//NOTICE:the SPARQL file to be used should be placed in the local machine even when in remote mode
2016-09-18 20:01:57 +08:00
int source_handler(const vector<string>& args) {
if (args.size() != 1) {
cerr << "Exactly 1 argument required!" << endl;
return -1;
}
char* str = dupstr(args[0].c_str());
int ret = deal_with_script(str);
free(str);
return ret;
2016-05-16 03:16:22 +08:00
}
2016-09-18 20:01:57 +08:00
int quit_handler(const vector<string>& args) {
if (!args.empty()) {
cerr << "Too many arguments!" << endl;
return -1;
}
2016-09-18 20:01:57 +08:00
if (gc != NULL) {
cerr << "This command cannot be used when in remote mode." << endl;
return -1;
}
if (current_database != NULL) {
cerr << "Please unload your database before quitting." << endl;
return -1;
}
done = true;
return 0;
}
2016-09-18 20:01:57 +08:00
int connect_handler(const vector<string>& args) {
if (args.size() > 2) {
cerr << "Too many arguments!" << endl;
return -1;
}
if (gc != NULL) {
cerr << "This command cannot be used when in remote mode." << endl;
return -1;
}
if (current_database != NULL) {
cerr << "Please unload your database before entering remote mode." << endl;
return -1;
}
unsigned short port = GstoreConnector::defaultServerPort;
string ip = GstoreConnector::defaultServerIP;
if (args.size() == 2) {
if (!Util::isValidIP(args[0])) {
cerr << "Invalid IP: " << args[0] << endl;
return -1;
}
if (!Util::isValidPort(args[1])) {
cerr << "Invalid Port: " << args[1] << endl;
return -1;
}
ip = args[0];
stringstream(args[1]) >> port;
}
else if (args.size() == 1) {
if (Util::isValidIP(args[0])) {
ip = args[0];
}
else if (Util::isValidPort(args[0])) {
stringstream(args[0]) >> port;
}
else {
cerr << "Invalid argument, neither IP nor port: " << args[0] << endl;
return -1;
}
}
//initialize the GStore server's IP address and port.
gc = new GstoreConnector(ip, port);
if (!gc->test()) {
cerr << "Failed to connect to server at " << ip << ':' << port << endl;
delete gc;
gc = NULL;
return -1;
}
current_commands = remote_commands;
cout << "Now is in remote mode, please type your commands." << endl;
return 0;
}
2016-09-18 20:01:57 +08:00
int disconnect_handler(const vector<string>& args) {
if (!args.empty()) {
cerr << "Too many arguments!" << endl;
return -1;
}
if (gc == NULL) {
cerr << "This command cannot be used when in native mode." << endl;
return -1;
}
string show_ret = gc->show();
if (show_ret != "connect to server error"
&& show_ret != "send show command error."
&& show_ret != "\n[empty]\n") {
cerr << "Please unload your server database before entering native mode." << endl;
return -1;
}
delete gc;
gc = NULL;
current_commands = native_commands;
cout << "Now is in native mode, please type your commands." << endl;
return 0;
}
2016-09-18 20:01:57 +08:00
int show_handler(const vector<string>& args)
{
2016-09-18 20:01:57 +08:00
if (args.size() > 1) {
cerr << "Too many arguments!" << endl;
return -1;
}
2016-05-16 03:16:22 +08:00
bool flag = false;
2016-09-18 20:01:57 +08:00
if (args.size() == 1) {
if (args[0] == "all") {
flag = true;
}
else {
cerr << "Invalid argument: " << args[0] << endl;
return -1;
}
}
if (gc != NULL) {
string database = gc->show(flag);
cout << database << endl;
return 0;
}
//native mode
if (flag) {
2016-05-16 03:16:22 +08:00
string database = Util::getItemsFromDir(Util::db_home);
2016-09-18 20:01:57 +08:00
if (database.empty()) {
database = "No databases.";
}
cout << database << endl;
2016-05-16 03:16:22 +08:00
return 0;
}
2016-09-18 20:01:57 +08:00
if (current_database == NULL) {
cout << "No database used now." << endl;
}
else {
cout << current_database->getName() << endl;
}
return 0;
}
2016-05-16 03:16:22 +08:00
//NOTICE: for build() and load(), always keep database in the root of gStore
2016-09-18 20:01:57 +08:00
int build_handler(const vector<string>& args) {
if (args.size() != 2) {
cerr << "Exactly 2 arguments required!" << endl;
return -1;
}
2016-05-16 03:16:22 +08:00
2016-09-18 20:01:57 +08:00
string database = args[0];
2016-05-16 03:16:22 +08:00
//WARN:user better not end with ".db" by themselves!!!
2016-09-18 20:01:57 +08:00
if (database.length() > 3 && database.substr(database.length() - 3, 3) == ".db")
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
cerr << "Your db name to be built should not end with \".db\"." << endl;
2016-05-16 03:16:22 +08:00
return -1;
}
2016-09-18 20:01:57 +08:00
database += ".db";
//NOTICE: when in remote mode, the dataset should be placed in the server! And the exact path can only be got in the server
//we can deal with it in Database
2016-09-18 20:01:57 +08:00
string dataset = args[1];
//remote mode
if (gc != NULL) {
// QUERY:how to interact:string?dict(0:string)?json(service_id, service_args)?
// Here uses the Cpp API Wrapper
// build a new database by a RDF file.
// note that the relative path is related to gserver.
if (gc->build(database, dataset)) {
return 0;
}
else {
return -1;
}
}
2016-09-18 20:01:57 +08:00
if (current_database != NULL) {
cerr << "Please unload your database first." << endl;
return -1;
}
cout << "Import dataset to build database..." << endl;
cout << "DB_store: " << database << "\tRDF_data: " << dataset << endl;
current_database = new Database(database);
2016-09-18 20:01:57 +08:00
bool flag = current_database->build(dataset);
delete current_database;
current_database = NULL;
if (!flag) {
cerr << "Import RDF file to database failed." << endl;
string cmd = "rm -rf " + database;
system(cmd.c_str());
return -1;
}
cout << "Import RDF file to database done." << endl;
return 0;
}
2016-09-18 20:01:57 +08:00
int drop_handler(const vector<string>& args) {
if (args.size() != 1) {
cerr << "Exactly 1 argument required!" << endl;
return -1;
}
2016-05-16 03:16:22 +08:00
//only drop when *.db, avoid other files be removed
2016-09-18 20:01:57 +08:00
string database = args[0];
if (database.length() > 3 && database.substr(database.length() - 3, 3) == ".db") {
cerr << "You should use exactly the same db name as building, which should not end with \".db\"" << endl;
return -1;
}
database += ".db";
2016-05-16 03:16:22 +08:00
2016-09-18 20:01:57 +08:00
//remote mode
if (gc != NULL) {
if (gc->drop(database)) {
2016-05-16 03:16:22 +08:00
return 0;
2016-09-18 20:01:57 +08:00
}
else {
2016-05-16 03:16:22 +08:00
return -1;
2016-09-18 20:01:57 +08:00
}
}
if (current_database != NULL) {
cerr << "Please do not use this command when you are using a database." << endl;
return -1;
2016-05-16 03:16:22 +08:00
}
string cmd = string("rm -rf ") + database;
2016-09-18 20:01:57 +08:00
int ret = system(cmd.c_str());
cout << database << " dropped." << endl;
return ret;
}
2016-05-16 03:16:22 +08:00
//NOTICE+WARN:
2016-09-18 20:01:57 +08:00
//generally, datasets are very large while a query file cannot be too large.
2016-05-16 03:16:22 +08:00
//So, when in remote mode, we expect that datasets in the server are used, while
//queries in local machine are used(transformed to string and passed to server).
2016-09-18 20:01:57 +08:00
int load_handler(const vector<string>& args) {
if (args.size() != 1) {
cerr << "Exactly 1 argument is required!" << endl;
2016-05-16 03:16:22 +08:00
return -1;
}
2016-09-18 20:01:57 +08:00
string database = args[0];
if (database.length() > 3 && database.substr(database.length() - 3, 3) == ".db") {
cerr << "You should use exactly the same db name as building, which should not end with \".db\"" << endl;
return -1;
}
database += ".db";
//remote mode
if (gc != NULL) {
if (gc->load(database)) {
return 0;
}
2016-09-18 20:01:57 +08:00
else {
return -1;
}
}
2016-05-16 03:16:22 +08:00
2016-09-18 20:01:57 +08:00
if (current_database != NULL) {
cerr << "Please unload your database first!" << endl;
return -1;
}
current_database = new Database(database);
bool flag = current_database->load();
if (!flag) {
cerr << "Failed to load the database." << endl;
delete current_database;
current_database = NULL;
return -1;
}
cout << "Database loaded successfully." << endl;
return 0;
}
int unload_handler(const vector<string>& args) {
if (!args.empty()) {
cerr << "Too many arguments!" << endl;
return -1;
2016-05-16 03:16:22 +08:00
}
2016-09-18 20:01:57 +08:00
//remote mode
if (gc != NULL)
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
string database = gc->show();
if (database == "\n[empty]\n")
2016-05-16 03:16:22 +08:00
{
2016-09-18 20:01:57 +08:00
cerr << "No database used now." << endl;
return -1;
}
if (gc->unload(database.substr(1, database.length() - 2))) {
return 0;
2016-05-16 03:16:22 +08:00
}
2016-09-18 20:01:57 +08:00
else {
return -1;
}
}
if (current_database == NULL)
{
cerr << "No database used now." << endl;
2016-05-16 03:16:22 +08:00
return -1;
}
2016-09-18 20:01:57 +08:00
delete current_database;
current_database = NULL;
cout << "Database unloaded." << endl;
2016-09-18 20:01:57 +08:00
return 0;
}
2016-09-18 20:01:57 +08:00
int query_handler(const vector<string>& args) {
if (args.size() != 1) {
cerr << "Exactly 1 argument required!" << endl;
return -1;
}
if (current_database == NULL)
{
cerr << "No database in use!" << endl;
return -1;
}
string sparql;
if (args[0][0] == '\"') { //query quoted in string
sparql = args[0].substr(1, args[0].length() - 2);
}
else { //query in file indicated by this path
//NOTICE:the query is native, not in server!
2016-09-18 20:01:57 +08:00
string ret = Util::getExactPath(args[0].c_str());
const char *path = ret.c_str();
2016-09-18 20:01:57 +08:00
if (path == NULL)
{
2016-09-18 20:01:57 +08:00
cerr << "Invalid path of query." << endl;
return -1;
}
#ifdef DEBUG
2016-09-18 20:01:57 +08:00
cout << path << endl;
#endif
2016-09-18 20:01:57 +08:00
sparql = Util::getQueryFromFile(path);
}
2016-09-18 20:01:57 +08:00
if (sparql.empty()) {
cerr << "Empty SPARQL." << endl;
return -1;
}
#ifdef DEBUG
2016-09-18 20:01:57 +08:00
cout << sparql << endl;
#endif
2016-09-18 20:01:57 +08:00
//remote mode
if (gc != NULL) {
//QUERY:how to use query path in the server
2016-09-18 20:01:57 +08:00
//execute SPARQL query on this database.
string answer = gc->query(sparql);
fprintf(output, "%s\n", answer.c_str());
return 0;
}
ResultSet rs;
bool ret = current_database->query(sparql, rs, output);
if (ret) {
2016-05-16 03:16:22 +08:00
#ifdef DEBUG_PRECISE
2016-09-18 20:01:57 +08:00
cout << "query() returns true!" << endl;
#endif
2016-09-18 20:01:57 +08:00
return 0;
}
else {
#ifdef DEBUG
2016-09-18 20:01:57 +08:00
cout << "query() returns false!" << endl;
#endif
2016-09-18 20:01:57 +08:00
return -1;
}
}
2016-09-18 20:01:57 +08:00
int start_handler(const vector<string>& args) {
if (args.size() > 1) {
cerr << "Too many arguments!" << endl;
return -1;
}
2016-09-18 20:01:57 +08:00
unsigned short port = GstoreConnector::defaultServerPort;
2016-09-18 20:01:57 +08:00
if (!args.empty()) {
if (Util::isValidPort(args[0])) {
stringstream(args[0]) >> port;
}
else {
cerr << "Invalid port: " << args[0] << endl;
return -1;
}
}
2016-09-18 20:01:57 +08:00
static const int max = 20; // max length of time string
char time_str[max];
time_t timep;
time(&timep);
strftime(time_str, max, "%Y%m%d_%H%M%S_", gmtime(&timep));
string gserver_path = "bin/gserver";
stringstream ss;
ss << "logs/gserver_" << time_str << port;
string log_path = ss.str();
ss.str(string());
ss << gserver_path << ' ' << port << " >> " << log_path << " 2>&1 &";
string cmd = ss.str();
Util::create_dir("logs");
system(cmd.c_str());
cout << "Local gserve started at port " << port << '.' << endl;
cout << "Output redirected to: " << log_path << endl;
return 0;
}
2016-09-18 20:01:57 +08:00
int stop_handler(const vector<string>& args) {
if (!args.empty()) {
cerr << "Too many arguments!" << endl;
return -1;
}
2016-09-18 20:01:57 +08:00
if (gc == NULL) {
cerr << "This command cannot be used when in native mode." << endl;
return -1;
}
2016-09-18 20:01:57 +08:00
if (!gc->stop()) {
return -1;
}
2016-09-18 20:01:57 +08:00
delete gc;
gc = NULL;
current_commands = native_commands;
cout << "Now is in native mode, please type your commands." << endl;
return 0;
}