diff --git a/src/console/CMakeLists.txt b/src/console/CMakeLists.txt index 93e24feb06a92c868af03e79f27db80487eb29ae..04831c89422105b1fed502b52679e8d48b1e00da 100644 --- a/src/console/CMakeLists.txt +++ b/src/console/CMakeLists.txt @@ -6,7 +6,6 @@ add_executable( GraphDbConsole.cpp $<TARGET_OBJECTS:console_obj> $<TARGET_OBJECTS:client_cpp_obj> - $<TARGET_OBJECTS:dataman_obj> $<TARGET_OBJECTS:base_obj> $<TARGET_OBJECTS:vgraph_thrift_obj> $<TARGET_OBJECTS:time_obj> diff --git a/src/console/CliManager.cpp b/src/console/CliManager.cpp index f4f8848c5f2d30412d39757e0871eae7cc771a36..c03a0097ae4e07b3c379215d6d058eef2b0bd5da 100644 --- a/src/console/CliManager.cpp +++ b/src/console/CliManager.cpp @@ -64,14 +64,14 @@ bool CliManager::connect(const std::string& addr, username_ = user; auto client = std::make_unique<GraphDbClient>(addr_, port_); - int32_t err = client->connect(user, pass); - if (!err) { + cpp2::ErrorCode res = client->connect(user, pass); + if (res == cpp2::ErrorCode::SUCCEEDED) { std::cerr << "\nWelcome to vGraph (Version 0.1)\n\n"; cmdProcessor_ = std::make_unique<CmdProcessor>(std::move(client)); return true; } else { // There is an error - std::cout << "Authentication failed: " << client->getErrorStr() << "\n"; + std::cout << "Authentication failed\n"; return false; } } diff --git a/src/console/CmdProcessor.cpp b/src/console/CmdProcessor.cpp index 46d911ad3e07982e96abeacfed1a75055228a295..a4ef04215abccbc30765fd75445cf03b9565435c 100644 --- a/src/console/CmdProcessor.cpp +++ b/src/console/CmdProcessor.cpp @@ -7,89 +7,189 @@ #include "base/Base.h" #include "console/CmdProcessor.h" #include "time/Duration.h" -#include "dataman/RowSetReader.h" -#include "dataman/RowReader.h" namespace vesoft { namespace vgraph { #define GET_VALUE_WIDTH(VT, FN, FMT) \ - VT val; \ - if (fieldIt->get ## FN (val) == ResultType::SUCCEEDED) { \ - int32_t len = folly::stringPrintf(FMT, val).size(); \ - if (widths[fieldIdx] < len) { \ - widths[fieldIdx] = len; \ - } \ + VT val = col.get_ ## FN(); \ + size_t len = folly::stringPrintf(FMT, val).size(); \ + if (widths[idx] < len) { \ + widths[idx] = len; \ + genFmt = true; \ } -std::vector<int16_t> CmdProcessor::calColumnWidths( - const RowSetReader* dataReader) const { - std::vector<int16_t> widths; +void CmdProcessor::calColumnWidths( + const cpp2::ExecutionResponse& resp, + std::vector<size_t>& widths, + std::vector<std::string>& formats) const { + widths.clear(); + formats.clear(); // Check column names first - auto* schema = dataReader->schema(); - for (int i = 0; i < schema->getNumFields(0); i++) { - widths.emplace_back(strlen(schema->getFieldName(i, 0))); + if (resp.get_column_names() != nullptr) { + for (size_t i = 0; i < resp.get_column_names()->size(); i++) { + widths.emplace_back(resp.get_column_names()->at(i).size()); + } + } + if (widths.size() == 0) { + return; } - // TODO Then check data width - auto rowIt = dataReader->begin(); - while (bool(rowIt)) { - int32_t fieldIdx = 0; - auto fieldIt = rowIt->begin(); - while (bool(fieldIt)) { - switch (schema->getFieldType(fieldIdx, 0)->get_type()) { - case cpp2::SupportedType::BOOL: { + std::vector<cpp2::ColumnValue::Type> types( + widths.size(), cpp2::ColumnValue::Type::__EMPTY__); + formats.resize(widths.size()); + // Then check data width + for (auto& row : *(resp.get_rows())) { + size_t idx = 0; + for (auto& col : row.get_columns()) { + CHECK(types[idx] == cpp2::ColumnValue::Type::__EMPTY__ + || types[idx] == col.getType()); + bool genFmt = types[idx] == cpp2::ColumnValue::Type::__EMPTY__; + if (types[idx] == cpp2::ColumnValue::Type::__EMPTY__) { + types[idx] = col.getType(); + } else { + CHECK_EQ(types[idx], col.getType()); + } + + switch (col.getType()) { + case cpp2::ColumnValue::Type::__EMPTY__: { + break; + } + case cpp2::ColumnValue::Type::boolean: { // Enough to hold "false" - if (widths[fieldIdx] < 5) { - widths[fieldIdx] = 5; + if (widths[idx] < 5UL) { + widths[idx] = 5UL; + genFmt = true; + } + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%lds |", widths[idx]); } break; } - case cpp2::SupportedType::INT: { - GET_VALUE_WIDTH(int64_t, Int, "%ld") + case cpp2::ColumnValue::Type::integer: { + GET_VALUE_WIDTH(int64_t, integer, "%ld") + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%ldld |", widths[idx]); + } break; } - case cpp2::SupportedType::FLOAT: { - GET_VALUE_WIDTH(float, Float, "%f") + case cpp2::ColumnValue::Type::id: { + // Enough to hold "0x{16 letters}" + if (widths[idx] < 18UL) { + widths[idx] = 18UL; + genFmt = true; + } + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%ldX |", widths[idx]); + } break; } - case cpp2::SupportedType::DOUBLE: { - GET_VALUE_WIDTH(double, Double, "%lf") + case cpp2::ColumnValue::Type::single_precision: { + GET_VALUE_WIDTH(float, single_precision, "%f") + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%ldf |", widths[idx]); + } break; } - case cpp2::SupportedType::STRING: { - folly::StringPiece val; - if (fieldIt->getString(val) == ResultType::SUCCEEDED) { - if (widths[fieldIdx] < static_cast<int64_t>(val.size())) { - widths[fieldIdx] = val.size(); - } + case cpp2::ColumnValue::Type::double_precision: { + GET_VALUE_WIDTH(double, double_precision, "%lf") + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%ldf |", widths[idx]); } break; } - case cpp2::SupportedType::VID: { - // Enough to hold "0x{16 letters}" - if (widths[fieldIdx] < 18) { - widths[fieldIdx] = 18; + case cpp2::ColumnValue::Type::str: { + size_t len = col.get_str().size(); + if (widths[idx] < len) { + widths[idx] = len; + genFmt = true; + } + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%lds |", widths[idx]); + } + break; + } + case cpp2::ColumnValue::Type::timestamp: { + GET_VALUE_WIDTH(int64_t, timestamp, "%ld") + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%ldld |", widths[idx]); + } + break; + } + case cpp2::ColumnValue::Type::year: { + if (widths[idx] < 4UL) { + widths[idx] = 4UL; + genFmt = true; + } + if (genFmt) { + formats[idx] = folly::stringPrintf(" %%%ldd |", widths[idx]); + } + break; + } + case cpp2::ColumnValue::Type::month: { + if (widths[idx] < 7UL) { + widths[idx] = 7UL; + genFmt = true; + } + if (genFmt) { + formats[idx] = folly::stringPrintf(" %%%ldd/%%02d |", + widths[idx] - 3); + } + break; + } + case cpp2::ColumnValue::Type::date: { + if (widths[idx] < 10UL) { + widths[idx] = 10UL; + genFmt = true; + } + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%ldd/%%02d/%%02d |", + widths[idx] - 6); } break; } - default: { + case cpp2::ColumnValue::Type::datetime: { + if (widths[idx] < 26UL) { + widths[idx] = 26UL; + genFmt = true; + } + if (genFmt) { + formats[idx] = + folly::stringPrintf(" %%%ldd/%%02d/%%02d" + " %%02d:%%02d:%%02d" + ".%%03d%%03d |", + widths[idx] - 22); + } + break; } } - ++fieldIt; - ++fieldIdx; + ++idx; } - ++rowIt; } - - return std::move(widths); } #undef GET_VALUE_WIDTH -int32_t CmdProcessor::printResult(const RowSetReader* dataReader) const { - std::vector<int16_t> widths = calColumnWidths(dataReader); +void CmdProcessor::printResult(const cpp2::ExecutionResponse& resp) const { + std::vector<size_t> widths; + std::vector<std::string> formats; + + calColumnWidths(resp, widths, formats); + + if (widths.size() == 0) { + return; + } + + // Calculate the total width int32_t sum = 0; for (auto w : widths) { sum += w; @@ -99,117 +199,109 @@ int32_t CmdProcessor::printResult(const RowSetReader* dataReader) const { std::string rowLine(sum + 3 * widths.size() + 1, '-'); std::cout << headerLine << "\n|"; - std::vector<std::string> formats = printHeader(dataReader, widths); + printHeader(resp, widths); std::cout << headerLine << "\n"; - int32_t numRows = printData(dataReader, rowLine, formats); - return numRows; + printData(resp, rowLine, widths, formats); } -std::vector<std::string> CmdProcessor::printHeader( - const RowSetReader* dataReader, - const std::vector<int16_t>& widths) const { - std::vector<std::string> formats; +void CmdProcessor::printHeader( + const cpp2::ExecutionResponse& resp, + const std::vector<size_t>& widths) const { + size_t idx = 0; + if (resp.get_column_names() == nullptr) { + return; + } - auto* schema = dataReader->schema(); - for (int i = 0; i < schema->getNumFields(0); i++) { - std::string fmt = folly::stringPrintf(" %%%ds |", widths[i]); - std::cout << folly::stringPrintf(fmt.c_str(), schema->getFieldName(i, 0)); - switch (schema->getFieldType(i, 0)->get_type()) { - case cpp2::SupportedType::BOOL: { - formats.emplace_back(folly::stringPrintf(" %%%ds |", widths[i])); - break; - } - case cpp2::SupportedType::INT: { - formats.emplace_back(folly::stringPrintf(" %%%dld |", widths[i])); - break; - } - case cpp2::SupportedType::FLOAT: { - formats.emplace_back(folly::stringPrintf(" %%%df |", widths[i])); - break; - } - case cpp2::SupportedType::DOUBLE: { - formats.emplace_back(folly::stringPrintf(" %%%df |", widths[i])); - break; - } - case cpp2::SupportedType::STRING: { - formats.emplace_back(folly::stringPrintf(" %%%ds |", widths[i])); - break; - } - case cpp2::SupportedType::VID: { - formats.emplace_back(folly::stringPrintf(" %%%dX |", widths[i])); - break; - } - default: { - formats.emplace_back(" *ERROR* |"); - } - } + for (auto& cname : (*resp.get_column_names())) { + std::string fmt = folly::stringPrintf(" %%%lds |", widths[idx]); + std::cout << folly::stringPrintf(fmt.c_str(), cname.c_str()); } std::cout << "\n"; - - return std::move(formats); } -#define PRINT_FIELD_VALUE(VT, FN, VAL) \ - VT val; \ - if (fIt->get ## FN (val) == ResultType::SUCCEEDED) { \ - std::cout << folly::stringPrintf(formats[fIdx].c_str(), (VAL)); \ - } else { \ - std::cout << " *BAD* |"; \ - } +#define PRINT_FIELD_VALUE(...) \ + std::cout << folly::stringPrintf(formats[cIdx].c_str(), __VA_ARGS__) -int32_t CmdProcessor::printData(const RowSetReader* dataReader, - const std::string& rowLine, - const std::vector<std::string>& formats) const { - int32_t numRows = 0; +void CmdProcessor::printData(const cpp2::ExecutionResponse& resp, + const std::string& rowLine, + const std::vector<size_t>& widths, + const std::vector<std::string>& formats) const { + if (resp.get_rows() == nullptr) { + return; + } - auto* schema = dataReader->schema(); - auto rowIt = dataReader->begin(); - while (bool(rowIt)) { - int32_t fIdx = 0; - auto fIt = rowIt->begin(); + for (auto& row : (*resp.get_rows())) { + int32_t cIdx = 0; std::cout << "|"; - while (bool(fIt)) { - switch (schema->getFieldType(fIdx, 0)->get_type()) { - case cpp2::SupportedType::BOOL: { - PRINT_FIELD_VALUE(bool, Bool, (val ? "true" : "false")) + for (auto& col : row.get_columns()) { + switch (col.getType()) { + case cpp2::ColumnValue::Type::__EMPTY__: { + std::string fmt = folly::stringPrintf(" %%%ldc |", widths[cIdx]); + std::cout << folly::stringPrintf(fmt.c_str(), ' '); + break; + } + case cpp2::ColumnValue::Type::boolean: { + PRINT_FIELD_VALUE(col.get_boolean() ? "true" : "false"); + break; + } + case cpp2::ColumnValue::Type::integer: { + PRINT_FIELD_VALUE(col.get_integer()); break; } - case cpp2::SupportedType::INT: { - PRINT_FIELD_VALUE(int64_t, Int, val) + case cpp2::ColumnValue::Type::id: { + PRINT_FIELD_VALUE(col.get_id()); break; } - case cpp2::SupportedType::FLOAT: { - PRINT_FIELD_VALUE(float, Float, val) + case cpp2::ColumnValue::Type::single_precision: { + PRINT_FIELD_VALUE(col.get_single_precision()); break; } - case cpp2::SupportedType::DOUBLE: { - PRINT_FIELD_VALUE(double, Double, val) + case cpp2::ColumnValue::Type::double_precision: { + PRINT_FIELD_VALUE(col.get_double_precision()); break; } - case cpp2::SupportedType::STRING: { - PRINT_FIELD_VALUE(folly::StringPiece, String, val.toString().c_str()) + case cpp2::ColumnValue::Type::str: { + PRINT_FIELD_VALUE(col.get_str().c_str()); break; } - case cpp2::SupportedType::VID: { - PRINT_FIELD_VALUE(int64_t, Vid, val) + case cpp2::ColumnValue::Type::timestamp: { + PRINT_FIELD_VALUE(col.get_timestamp()); break; } - default: { - std::cout << " *ERROR* |"; + case cpp2::ColumnValue::Type::year: { + PRINT_FIELD_VALUE(col.get_year()); + break; + } + case cpp2::ColumnValue::Type::month: { + cpp2::YearMonth month = col.get_month(); + PRINT_FIELD_VALUE(month.get_year(), month.get_month()); + break; + } + case cpp2::ColumnValue::Type::date: { + cpp2::Date date = col.get_date(); + PRINT_FIELD_VALUE(date.get_year(), date.get_month(), date.get_day()); + break; + } + case cpp2::ColumnValue::Type::datetime: { + cpp2::DateTime dt = col.get_datetime(); + PRINT_FIELD_VALUE(dt.get_year(), + dt.get_month(), + dt.get_day(), + dt.get_hour(), + dt.get_minute(), + dt.get_second(), + dt.get_millisec(), + dt.get_microsec()); + break; } } - ++fIt; - ++fIdx; + ++cIdx; } std::cout << "\n" << rowLine << "\n"; - ++numRows; - ++rowIt; } - - return numRows; } #undef PRINT_FIELD_VALUE @@ -231,23 +323,27 @@ bool CmdProcessor::processClientCmd(folly::StringPiece cmd, void CmdProcessor::processServerCmd(folly::StringPiece cmd) { time::Duration dur; - std::unique_ptr<RowSetReader> dataReader; - int32_t res = client_->execute(cmd, dataReader); - if (!res) { + cpp2::ExecutionResponse resp; + cpp2::ErrorCode res = client_->execute(cmd, resp); + if (res == cpp2::ErrorCode::SUCCEEDED) { // Succeeded - auto* schema = dataReader->schema(); - UNUSED(schema); - int32_t numRows = 0; - if (dataReader->schema()) { - // Only print when the schema is no empty - numRows = printResult(dataReader.get()); + printResult(resp); + if (resp.get_rows() != nullptr) { + std::cout << "Got " << resp.get_rows()->size() + << " rows (Time spent: " + << resp.get_latency_in_ms() << "/" + << dur.elapsedInMSec() << " ms)\n"; + } else { + std::cout << "Execution succeeded (Time spent: " + << resp.get_latency_in_ms() << "/" + << dur.elapsedInMSec() << " ms)\n"; } - std::cout << "Got " << numRows << " rows (Time spent: " - << client_->getServerLatency() << "/" - << dur.elapsedInMSec() << " ms)\n"; } else { - std::cout << "[ERROR (" << res << ")] " - << client_->getErrorStr() << "\n"; + // TODO(sye) Need to print human-readable error strings + auto msg = resp.get_error_msg(); + std::cout << "[ERROR (" << static_cast<int32_t>(res) + << ")]: " << (msg != nullptr ? *msg : "") + << "\n"; } } diff --git a/src/console/CmdProcessor.h b/src/console/CmdProcessor.h index 88b5a1be8ed1af1fb461d30512d523837fb5752a..8de95f7c96bc9e3af1da0fc02c3112789d92b2e4 100644 --- a/src/console/CmdProcessor.h +++ b/src/console/CmdProcessor.h @@ -34,15 +34,17 @@ private: void processServerCmd(folly::StringPiece cmd); - std::vector<int16_t> calColumnWidths(const RowSetReader* dataReader) const; - - int32_t printResult(const RowSetReader* dataReader) const; - std::vector<std::string> printHeader(const RowSetReader* dataReader, - const std::vector<int16_t>& widths) const; - // The method returns the total number of rows - int32_t printData(const RowSetReader* dataReader, - const std::string& rowLine, - const std::vector<std::string>& formats) const; + void calColumnWidths(const cpp2::ExecutionResponse& resp, + std::vector<size_t>& widths, + std::vector<std::string>& formats) const; + + void printResult(const cpp2::ExecutionResponse& resp) const; + void printHeader(const cpp2::ExecutionResponse& resp, + const std::vector<size_t>& widths) const; + void printData(const cpp2::ExecutionResponse& resp, + const std::string& rowLine, + const std::vector<size_t>& widths, + const std::vector<std::string>& formats) const; }; } // namespace vgraph