diff --git a/ci/test.sh b/ci/test.sh
index 5dcb5285afd4ba661211e41a0b6c432537282fef..8ba5d84aaa1e81affe1789bf02ef838aa085a33d 100755
--- a/ci/test.sh
+++ b/ci/test.sh
@@ -87,6 +87,7 @@ function run_test() {
$PROJ_DIR/tests/query/v1/* \
$PROJ_DIR/tests/query/v2/* \
$PROJ_DIR/tests/query/stateless/test_schema.py \
+ $PROJ_DIR/tests/query/stateless/test_admin.py \
$PROJ_DIR/tests/query/stateless/test_if_exists.py \
$PROJ_DIR/tests/query/stateless/test_range.py \
$PROJ_DIR/tests/query/stateless/test_go.py \
diff --git a/resources/gflags.json b/resources/gflags.json
index bdc747278792a1460dd9f24ef1c8e3ed1918df57..c265b9cd19e3b1671755d7e69caeb62cb2539520 100644
--- a/resources/gflags.json
+++ b/resources/gflags.json
@@ -1,69 +1,15 @@
{
- "IMMUTABLE": [
- ],
- "REBOOT": [
- ],
"MUTABLE": [
- "load_data_interval_secs",
"max_edge_returned_per_vertex",
"minloglevel",
"v",
"heartbeat_interval_secs",
"meta_client_retry_times",
"slow_op_threshhold_ms",
- "wal_ttl"
- ],
- "IGNORED": [
- "logging",
- "flagfile",
- "fromenv",
- "tryfromenv",
- "undefok",
- "tab_completion_columns",
- "tab_completion_word",
- "alsologtostderr",
- "drop_log_memory",
- "log_backtrace_at",
- "log_dir",
- "log_link",
- "log_prefix",
- "logbuflevel",
- "logbufsecs",
- "logemaillevel",
- "logfile_mode",
- "logmailer",
- "logtostderr",
- "max_log_size",
- "stderrthreshold",
- "stop_logging_if_full_disk",
- "symbolize_stacktrace",
- "vmodule",
- "help",
- "helpon",
- "helpxml",
- "helpfull",
- "helpmatch",
- "helpshort",
- "alsologtoemail",
- "version",
- "helppackage",
- "sasl_policy",
- "codel_enabled",
- "codel_interval",
- "colorlogtostderr",
- "dcache_unit_test",
- "service_identity",
- "thrift_ssl_policy",
- "codel_target_delay",
- "pending_interval",
- "threadtimeout_ms",
- "pin_service_identity",
- "thrift_pcap_logging_prohibit",
- "thrift_security_kill_switch_file",
- "thrift_cpp2_protocol_reader_string_limit",
- "thrift_cpp2_protocol_reader_container_limit",
- "zlib_compressor_buffer_growth",
- "gflags_mode_json"
+ "wal_ttl",
+ "enable_reservoir_sampling",
+ "custom_filter_interval_secs",
+ "enable_multi_versions"
],
"NESTED": [
"rocksdb_db_options",
@@ -71,3 +17,4 @@
"rocksdb_block_based_table_options"
]
}
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f62da9c0606ff8a6d24761da57f707c9b385f894..8811ab4d918a12053889ef3a43ec53affae89edd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,6 @@
# This source code is licensed under Apache 2.0 License,
# attached with Common Clause Condition 1.0, found in the LICENSES directory.
-#nebula_add_subdirectory(graph)
nebula_add_subdirectory(daemons)
nebula_add_subdirectory(service)
nebula_add_subdirectory(parser)
@@ -11,6 +10,5 @@ nebula_add_subdirectory(planner)
nebula_add_subdirectory(validator)
nebula_add_subdirectory(exec)
nebula_add_subdirectory(util)
-nebula_add_subdirectory(mock)
nebula_add_subdirectory(context)
nebula_add_subdirectory(scheduler)
diff --git a/src/daemons/CMakeLists.txt b/src/daemons/CMakeLists.txt
index a05778776e7c9d5275ff4cc8e27899d7e204a2de..400f105d2d1fd3cb1fdfb04250478e2fa63dfa9a 100644
--- a/src/daemons/CMakeLists.txt
+++ b/src/daemons/CMakeLists.txt
@@ -42,7 +42,6 @@ nebula_add_executable(
$<TARGET_OBJECTS:common_meta_obj>
$<TARGET_OBJECTS:common_ws_obj>
$<TARGET_OBJECTS:common_ws_common_obj>
- # $<TARGET_OBJECTS:meta_gflags_man_obj>
$<TARGET_OBJECTS:common_thread_obj>
$<TARGET_OBJECTS:common_fs_obj>
$<TARGET_OBJECTS:common_base_obj>
@@ -54,6 +53,7 @@ nebula_add_executable(
$<TARGET_OBJECTS:common_encryption_obj>
$<TARGET_OBJECTS:common_function_manager_obj>
$<TARGET_OBJECTS:common_agg_function_obj>
+ $<TARGET_OBJECTS:common_conf_obj>
LIBRARIES
proxygenhttpserver
proxygenlib
diff --git a/src/exec/CMakeLists.txt b/src/exec/CMakeLists.txt
index 711d850419440bfba9a78ac7e09bbca4661ba056..ed3347441412ca64d2a64a3ee4def3ffda6545b8 100644
--- a/src/exec/CMakeLists.txt
+++ b/src/exec/CMakeLists.txt
@@ -38,6 +38,7 @@ nebula_add_library(
mutate/InsertExecutor.cpp
mutate/DeleteExecutor.cpp
mutate/UpdateExecutor.cpp
+ admin/ConfigExecutor.cpp
)
nebula_add_subdirectory(query/test)
diff --git a/src/exec/Executor.cpp b/src/exec/Executor.cpp
index e49012a3e81ab04404e037486ce8a3bcc058bd7c..407ecf5d4dbddeee33b6a70c71cdeb971fa83832 100644
--- a/src/exec/Executor.cpp
+++ b/src/exec/Executor.cpp
@@ -20,6 +20,7 @@
#include "exec/admin/SwitchSpaceExecutor.h"
#include "exec/admin/PartExecutor.h"
#include "exec/admin/CharsetExecutor.h"
+#include "exec/admin/ConfigExecutor.h"
#include "exec/logic/LoopExecutor.h"
#include "exec/logic/MultiOutputsExecutor.h"
#include "exec/logic/SelectExecutor.h"
@@ -403,6 +404,27 @@ Executor *Executor::makeExecutor(const PlanNode *node,
exec->dependsOn(input);
break;
}
+ case PlanNode::Kind::kShowConfigs: {
+ auto showConfigs = asNode<ShowConfigs>(node);
+ auto input = makeExecutor(showConfigs->dep(), qctx, visited);
+ exec = new ShowConfigsExecutor(showConfigs, qctx);
+ exec->dependsOn(input);
+ break;
+ }
+ case PlanNode::Kind::kSetConfig: {
+ auto setConfig = asNode<SetConfig>(node);
+ auto input = makeExecutor(setConfig->dep(), qctx, visited);
+ exec = new SetConfigExecutor(setConfig, qctx);
+ exec->dependsOn(input);
+ break;
+ }
+ case PlanNode::Kind::kGetConfig: {
+ auto getConfig = asNode<GetConfig>(node);
+ auto input = makeExecutor(getConfig->dep(), qctx, visited);
+ exec = new GetConfigExecutor(getConfig, qctx);
+ exec->dependsOn(input);
+ break;
+ }
case PlanNode::Kind::kSubmitJob: {
auto submitJob = asNode<SubmitJob>(node);
auto input = makeExecutor(submitJob->dep(), qctx, visited);
diff --git a/src/exec/admin/ConfigExecutor.cpp b/src/exec/admin/ConfigExecutor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3bfb4a56435dd3df9ce52ac1bca19e51de115bbb
--- /dev/null
+++ b/src/exec/admin/ConfigExecutor.cpp
@@ -0,0 +1,101 @@
+/* Copyright (c) 2020 vesoft inc. All rights reserved.
+*
+* This source code is licensed under Apache 2.0 License,
+* attached with Common Clause Condition 1.0, found in the LICENSES directory.
+*/
+
+#include "common/conf/Configuration.h"
+#include "exec/admin/ConfigExecutor.h"
+#include "planner/Admin.h"
+#include "util/SchemaUtil.h"
+#include "context/QueryContext.h"
+#include "util/ScopedTimer.h"
+
+namespace nebula {
+namespace graph {
+
+std::vector<Value> ConfigBaseExecutor::generateColumns(const meta::cpp2::ConfigItem& item) {
+ std::vector<Value> columns;
+ columns.resize(5);
+ auto value = item.get_value();
+ columns[0].setStr(meta::cpp2::_ConfigModule_VALUES_TO_NAMES.at(item.get_module()));
+ columns[1].setStr(item.get_name());
+ columns[2].setStr(value.typeName());
+ columns[3].setStr(meta::cpp2::_ConfigMode_VALUES_TO_NAMES.at(item.get_mode()));
+ columns[4] = std::move(value);
+ return columns;
+}
+
+DataSet ConfigBaseExecutor::generateResult(const std::vector<meta::cpp2::ConfigItem> &items) {
+ DataSet result;
+ result.colNames = {"module", "name", "type", "mode", "value"};
+ for (const auto &item : items) {
+ auto columns = generateColumns(item);
+ result.rows.emplace_back(std::move(columns));
+ }
+ return result;
+}
+
+folly::Future<Status> ShowConfigsExecutor::execute() {
+ SCOPED_TIMER(&execTime_);
+
+ auto *scNode = asNode<ShowConfigs>(node());
+ return qctx()->getMetaClient()->listConfigs(scNode->getModule())
+ .via(runner())
+ .then([this, scNode](StatusOr<std::vector<meta::cpp2::ConfigItem>> resp) {
+ if (!resp.ok()) {
+ auto module = meta::cpp2::_ConfigModule_VALUES_TO_NAMES.at(scNode->getModule());
+ LOG(ERROR) << "Show configs `" << module
+ << "' failed: " << resp.status();
+ return Status::Error("Show config `%s' failed: %s",
+ module,
+ resp.status().toString().c_str());
+ }
+
+ auto result = generateResult(resp.value());
+ return finish(ResultBuilder().value(Value(std::move(result))).finish());
+ });
+}
+
+folly::Future<Status> SetConfigExecutor::execute() {
+ SCOPED_TIMER(&execTime_);
+
+ auto *scNode = asNode<SetConfig>(node());
+ return qctx()->getMetaClient()->setConfig(scNode->getModule(),
+ scNode->getName(),
+ scNode->getValue())
+ .via(runner())
+ .then([scNode](StatusOr<bool> resp) {
+ if (!resp.ok()) {
+ LOG(ERROR) << "Set config `" << scNode->getName()
+ << "' failed: " << resp.status();
+ return Status::Error("Set config `%s' failed: %s",
+ scNode->getName().c_str(),
+ resp.status().toString().c_str());
+ }
+ return Status::OK();
+ });
+}
+
+folly::Future<Status> GetConfigExecutor::execute() {
+ SCOPED_TIMER(&execTime_);
+
+ auto *gcNode = asNode<GetConfig>(node());
+ return qctx()->getMetaClient()->getConfig(gcNode->getModule(),
+ gcNode->getName())
+ .via(runner())
+ .then([this, gcNode](StatusOr<std::vector<meta::cpp2::ConfigItem>> resp) {
+ if (!resp.ok()) {
+ LOG(ERROR) << "Get config `" << gcNode->getName()
+ << "' failed: " << resp.status();
+ return Status::Error("Get config `%s' failed: %s",
+ gcNode->getName().c_str(),
+ resp.status().toString().c_str());
+ }
+ auto result = generateResult(resp.value());
+ return finish(ResultBuilder().value(Value(std::move(result))).finish());
+ });
+}
+
+} // namespace graph
+} // namespace nebula
diff --git a/src/exec/admin/ConfigExecutor.h b/src/exec/admin/ConfigExecutor.h
new file mode 100644
index 0000000000000000000000000000000000000000..3084fdab50478c3593e1e71f0adbf6d8015885a6
--- /dev/null
+++ b/src/exec/admin/ConfigExecutor.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2020 vesoft inc. All rights reserved.
+ *
+ * This source code is licensed under Apache 2.0 License,
+ * attached with Common Clause Condition 1.0, found in the LICENSES directory.
+ */
+
+#ifndef EXEC_ADMIN_CONFIGEXECUTOR_H_
+#define EXEC_ADMIN_CONFIGEXECUTOR_H_
+
+#include "exec/Executor.h"
+#include "common/interface/gen-cpp2/meta_types.h"
+
+namespace nebula {
+namespace graph {
+
+class ConfigBaseExecutor : public Executor {
+public:
+ ConfigBaseExecutor(const std::string &name, const PlanNode *node, QueryContext *ectx)
+ : Executor(name, node, ectx) {}
+
+protected:
+ std::vector<Value> generateColumns(const meta::cpp2::ConfigItem &item);
+ DataSet generateResult(const std::vector<meta::cpp2::ConfigItem> &items);
+};
+
+class ShowConfigsExecutor final : public ConfigBaseExecutor {
+public:
+ ShowConfigsExecutor(const PlanNode *node, QueryContext *ectx)
+ : ConfigBaseExecutor("ShowConfigsExecutor", node, ectx) {}
+
+ folly::Future<Status> execute() override;
+};
+
+class SetConfigExecutor final : public ConfigBaseExecutor {
+public:
+ SetConfigExecutor(const PlanNode *node, QueryContext *ectx)
+ : ConfigBaseExecutor("SetConfigExecutor", node, ectx) {}
+
+ folly::Future<Status> execute() override;
+
+private:
+ std::string name_;
+ Value value_;
+};
+
+class GetConfigExecutor final : public ConfigBaseExecutor {
+public:
+ GetConfigExecutor(const PlanNode *node, QueryContext *ectx)
+ : ConfigBaseExecutor("GetConfigExecutor", node, ectx) {}
+
+ folly::Future<Status> execute() override;
+
+private:
+ std::string name_;
+};
+
+} // namespace graph
+} // namespace nebula
+
+#endif // EXEC_ADMIN_CONFIGEXECUTOR_H_
diff --git a/src/parser/AdminSentences.cpp b/src/parser/AdminSentences.cpp
index e772a0d8ee1c404ce45dc257b0cd88f4b3cc34a9..5592f6fe6f966e74822d9042946595c14a0f46f8 100644
--- a/src/parser/AdminSentences.cpp
+++ b/src/parser/AdminSentences.cpp
@@ -104,18 +104,16 @@ std::string ConfigRowItem::toString() const {
return "";
}
-std::string ConfigSentence::toString() const {
- switch (subType_) {
- case SubType::kShow:
- return std::string("SHOW CONFIGS ") + configItem_->toString();
- case SubType::kSet:
- return std::string("SET CONFIGS ") + configItem_->toString();
- case SubType::kGet:
- return std::string("GET CONFIGS ") + configItem_->toString();
- default:
- FLOG_FATAL("Type illegal");
- }
- return "Unknown";
+std::string ShowConfigsSentence::toString() const {
+ return std::string("SHOW CONFIGS ") + configItem_->toString();
+}
+
+std::string SetConfigSentence::toString() const {
+ return std::string("SET CONFIGS ") + configItem_->toString();
+}
+
+std::string GetConfigSentence::toString() const {
+ return std::string("GET CONFIGS ") + configItem_->toString();
}
std::string BalanceSentence::toString() const {
diff --git a/src/parser/AdminSentences.h b/src/parser/AdminSentences.h
index 0cda54e91594bc0eddd6b5768a62dc83f864168d..268df1c67a971c48eac9d9aca450eed6a62af9d8 100644
--- a/src/parser/AdminSentences.h
+++ b/src/parser/AdminSentences.h
@@ -296,97 +296,91 @@ private:
std::unique_ptr<std::string> spaceName_;
};
-enum ConfigModule {
- ALL, GRAPH, META, STORAGE
-};
-
class ConfigRowItem {
public:
- explicit ConfigRowItem(ConfigModule module) {
- module_ = std::make_unique<ConfigModule>(module);
+ explicit ConfigRowItem(meta::cpp2::ConfigModule module) {
+ module_ = module;
}
- ConfigRowItem(ConfigModule module, std::string* name, Expression* value) {
- module_ = std::make_unique<ConfigModule>(module);
+ ConfigRowItem(meta::cpp2::ConfigModule module, std::string* name, Expression* value) {
+ module_ = module;
name_.reset(name);
value_.reset(value);
}
- ConfigRowItem(ConfigModule module, std::string* name) {
- module_ = std::make_unique<ConfigModule>(module);
+ ConfigRowItem(meta::cpp2::ConfigModule module, std::string* name) {
+ module_ = module;
name_.reset(name);
}
- ConfigRowItem(ConfigModule module, std::string* name, UpdateList *items) {
- module_ = std::make_unique<ConfigModule>(module);
+ ConfigRowItem(meta::cpp2::ConfigModule module, std::string* name, UpdateList *items) {
+ module_ = module;
name_.reset(name);
updateItems_.reset(items);
}
- const ConfigModule* getModule() {
- return module_.get();
+ meta::cpp2::ConfigModule getModule() const {
+ return module_;
}
- const std::string* getName() {
+ const std::string* getName() const {
return name_.get();
}
- const Expression* getValue() {
+ Expression* getValue() const {
return value_.get();
}
- const UpdateList* getUpdateItems() {
+ const UpdateList* getUpdateItems() const {
return updateItems_.get();
}
std::string toString() const;
private:
- std::unique_ptr<ConfigModule> module_;
+ meta::cpp2::ConfigModule module_;
std::unique_ptr<std::string> name_;
std::unique_ptr<Expression> value_;
std::unique_ptr<UpdateList> updateItems_;
};
-class ConfigSentence final : public Sentence {
+class ConfigBaseSentence : public Sentence {
public:
- enum class SubType : uint32_t {
- kUnknown,
- kShow,
- kSet,
- kGet,
- };
-
- explicit ConfigSentence(SubType subType) {
- kind_ = Kind::kConfig;
- subType_ = std::move(subType);
+ explicit ConfigBaseSentence(Kind kind, ConfigRowItem* item) {
+ kind_ = kind;
+ configItem_.reset(item);
}
- ConfigSentence(SubType subType, ConfigRowItem* item, bool force = false) {
- kind_ = Kind::kConfig;
- subType_ = std::move(subType);
- configItem_.reset(item);
- isForce_ = force;
+ ConfigRowItem* configItem() {
+ return configItem_.get();
}
+protected:
+ std::unique_ptr<ConfigRowItem> configItem_;
+};
+
+class ShowConfigsSentence final : public ConfigBaseSentence {
+public:
+ explicit ShowConfigsSentence(ConfigRowItem* item)
+ : ConfigBaseSentence(Kind::kShowConfigs, item) {}
+
std::string toString() const override;
+};
- SubType subType() const {
- return subType_;
- }
+class SetConfigSentence final : public ConfigBaseSentence {
+public:
+ explicit SetConfigSentence(ConfigRowItem* item)
+ : ConfigBaseSentence(Kind::kSetConfig, item) {}
- ConfigRowItem* configItem() {
- return configItem_.get();
- }
+ std::string toString() const override;
+};
- bool isForce() {
- return isForce_;
- }
+class GetConfigSentence final : public ConfigBaseSentence {
+public:
+ explicit GetConfigSentence(ConfigRowItem* item)
+ : ConfigBaseSentence(Kind::kGetConfig, item) {}
-private:
- SubType subType_{SubType::kUnknown};
- bool isForce_{false};
- std::unique_ptr<ConfigRowItem> configItem_;
+ std::string toString() const override;
};
class HostList final {
diff --git a/src/parser/Sentence.h b/src/parser/Sentence.h
index e91a088954f453e6dca998c95cccc84e0f90f470..a640af1322f38590e24fdf46979d2511d18d7ef5 100644
--- a/src/parser/Sentence.h
+++ b/src/parser/Sentence.h
@@ -91,7 +91,9 @@ public:
kDownload,
kIngest,
kOrderBy,
- kConfig,
+ kShowConfigs,
+ kSetConfig,
+ kGetConfig,
kFetchVertices,
kFetchEdges,
kBalance,
diff --git a/src/parser/parser.yy b/src/parser/parser.yy
index b90d63814a8d168be6c70a901ac0c0bc0495536b..1b80a7d541693b690288ba158cfcecf974ebfd00 100644
--- a/src/parser/parser.yy
+++ b/src/parser/parser.yy
@@ -89,7 +89,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
nebula::SchemaPropItem *alter_schema_prop_item;
nebula::OrderFactor *order_factor;
nebula::OrderFactors *order_factors;
- nebula::ConfigModule config_module;
+ nebula::meta::cpp2::ConfigModule config_module;
nebula::ConfigRowItem *config_row_item;
nebula::EdgeKey *edge_key;
nebula::EdgeKeys *edge_keys;
@@ -1862,7 +1862,7 @@ show_sentence
$$ = new ShowRolesSentence($4);
}
| KW_SHOW KW_CONFIGS show_config_item {
- $$ = new ConfigSentence(ConfigSentence::SubType::kShow, $3);
+ $$ = new ShowConfigsSentence($3);
}
| KW_SHOW KW_CREATE KW_SPACE name_label {
$$ = new ShowCreateSpaceSentence($4);
@@ -1897,9 +1897,9 @@ show_sentence
;
config_module_enum
- : KW_GRAPH { $$ = ConfigModule::GRAPH; }
- | KW_META { $$ = ConfigModule::META; }
- | KW_STORAGE { $$ = ConfigModule::STORAGE; }
+ : KW_GRAPH { $$ = meta::cpp2::ConfigModule::GRAPH; }
+ | KW_META { $$ = meta::cpp2::ConfigModule::META; }
+ | KW_STORAGE { $$ = meta::cpp2::ConfigModule::STORAGE; }
;
get_config_item
@@ -1907,7 +1907,7 @@ get_config_item
$$ = new ConfigRowItem($1, $3);
}
| name_label {
- $$ = new ConfigRowItem(ConfigModule::ALL, $1);
+ $$ = new ConfigRowItem(meta::cpp2::ConfigModule::ALL, $1);
}
;
@@ -1916,13 +1916,13 @@ set_config_item
$$ = new ConfigRowItem($1, $3, $5);
}
| name_label ASSIGN expression {
- $$ = new ConfigRowItem(ConfigModule::ALL, $1, $3);
+ $$ = new ConfigRowItem(meta::cpp2::ConfigModule::ALL, $1, $3);
}
| config_module_enum COLON name_label ASSIGN L_BRACE update_list R_BRACE {
$$ = new ConfigRowItem($1, $3, $6);
}
| name_label ASSIGN L_BRACE update_list R_BRACE {
- $$ = new ConfigRowItem(ConfigModule::ALL, $1, $4);
+ $$ = new ConfigRowItem(meta::cpp2::ConfigModule::ALL, $1, $4);
}
;
@@ -2070,16 +2070,13 @@ revoke_sentence
get_config_sentence
: KW_GET KW_CONFIGS get_config_item {
- $$ = new ConfigSentence(ConfigSentence::SubType::kGet, $3);
+ $$ = new GetConfigSentence($3);
}
;
set_config_sentence
: KW_UPDATE KW_CONFIGS set_config_item {
- $$ = new ConfigSentence(ConfigSentence::SubType::kSet, $3);
- }
- | KW_UPDATE KW_CONFIGS set_config_item KW_FORCE {
- $$ = new ConfigSentence(ConfigSentence::SubType::kSet, $3, true);
+ $$ = new SetConfigSentence($3);
}
;
diff --git a/src/planner/Admin.cpp b/src/planner/Admin.cpp
index 81e2e97170b131ce9dda4a4b90ecb34778af8cdb..98e3e015ab2f433512bbd621f11e5e38221224b3 100644
--- a/src/planner/Admin.cpp
+++ b/src/planner/Admin.cpp
@@ -51,5 +51,26 @@ std::unique_ptr<cpp2::PlanNodeDescription> ShowParts::explain() const {
addDescription("partIds", folly::toJson(util::toJson(partIds_)), desc.get());
return desc;
}
+
+std::unique_ptr<cpp2::PlanNodeDescription> ShowConfigs::explain() const {
+ auto desc = SingleInputNode::explain();
+ addDescription("module", meta::cpp2::_ConfigModule_VALUES_TO_NAMES.at(module_), desc.get());
+ return desc;
+}
+
+std::unique_ptr<cpp2::PlanNodeDescription> SetConfig::explain() const {
+ auto desc = SingleInputNode::explain();
+ addDescription("module", meta::cpp2::_ConfigModule_VALUES_TO_NAMES.at(module_), desc.get());
+ addDescription("name", name_, desc.get());
+ addDescription("value", value_.toString(), desc.get());
+ return desc;
+}
+
+std::unique_ptr<cpp2::PlanNodeDescription> GetConfig::explain() const {
+ auto desc = SingleInputNode::explain();
+ addDescription("module", meta::cpp2::_ConfigModule_VALUES_TO_NAMES.at(module_), desc.get());
+ addDescription("name", name_, desc.get());
+ return desc;
+}
} // namespace graph
} // namespace nebula
diff --git a/src/planner/Admin.h b/src/planner/Admin.h
index a745e60d0115e8cb5db1161440777c065064f77b..4e45230af6af1e2aa76b4cfa4559a7acec86afae 100644
--- a/src/planner/Admin.h
+++ b/src/planner/Admin.h
@@ -141,11 +141,106 @@ public:
private:
explicit ShowSpaces(ExecutionPlan* plan, PlanNode* input)
- : SingleInputNode(plan, Kind::kShowSpaces, input) {}
+ : SingleInputNode(plan, Kind::kShowSpaces, input) {}
};
-class Config final : public SingleInputNode {
+class ShowConfigs final : public SingleInputNode {
public:
+ static ShowConfigs* make(ExecutionPlan* plan,
+ PlanNode* input,
+ meta::cpp2::ConfigModule module) {
+ return new ShowConfigs(plan, input, module);
+ }
+
+ std::unique_ptr<cpp2::PlanNodeDescription> explain() const override;
+
+ meta::cpp2::ConfigModule getModule() const {
+ return module_;
+ }
+
+private:
+ ShowConfigs(ExecutionPlan* plan,
+ PlanNode* input,
+ meta::cpp2::ConfigModule module)
+ : SingleInputNode(plan, Kind::kShowConfigs, input)
+ , module_(module) {}
+
+private:
+ meta::cpp2::ConfigModule module_;
+};
+
+class SetConfig final : public SingleInputNode {
+public:
+ static SetConfig* make(ExecutionPlan* plan,
+ PlanNode* input,
+ meta::cpp2::ConfigModule module,
+ std::string name,
+ Value value) {
+ return new SetConfig(plan, input, module, std::move(name), std::move(value));
+ }
+
+ std::unique_ptr<cpp2::PlanNodeDescription> explain() const override;
+
+ meta::cpp2::ConfigModule getModule() const {
+ return module_;
+ }
+
+ const std::string& getName() const {
+ return name_;
+ }
+
+ const Value& getValue() const {
+ return value_;
+ }
+
+private:
+ SetConfig(ExecutionPlan* plan,
+ PlanNode* input,
+ meta::cpp2::ConfigModule module,
+ std::string name,
+ Value value)
+ : SingleInputNode(plan, Kind::kSetConfig, input)
+ , module_(module)
+ , name_(std::move(name))
+ , value_(std::move(value)) {}
+
+private:
+ meta::cpp2::ConfigModule module_;
+ std::string name_;
+ Value value_;
+};
+
+class GetConfig final : public SingleInputNode {
+public:
+ static GetConfig* make(ExecutionPlan* plan,
+ PlanNode* input,
+ meta::cpp2::ConfigModule module,
+ std::string name) {
+ return new GetConfig(plan, input, module, std::move(name));
+ }
+
+ std::unique_ptr<cpp2::PlanNodeDescription> explain() const override;
+
+ meta::cpp2::ConfigModule getModule() const {
+ return module_;
+ }
+
+ const std::string& getName() const {
+ return name_;
+ }
+
+private:
+ explicit GetConfig(ExecutionPlan* plan,
+ PlanNode* input,
+ meta::cpp2::ConfigModule module,
+ std::string name)
+ : SingleInputNode(plan, Kind::kGetConfig, input)
+ , module_(module)
+ , name_(std::move(name)) {}
+
+private:
+ meta::cpp2::ConfigModule module_;
+ std::string name_;
};
class ShowCreateSpace final : public SingleInputNode {
@@ -336,3 +431,4 @@ private:
} // namespace graph
} // namespace nebula
#endif // PLANNER_ADMIN_H_
+
diff --git a/src/planner/PlanNode.cpp b/src/planner/PlanNode.cpp
index b16e2000aba4f1ff39a1af42796f7367226928c3..e354fa5d0c7e891b12c54b5c960c8efa97a11389 100644
--- a/src/planner/PlanNode.cpp
+++ b/src/planner/PlanNode.cpp
@@ -125,6 +125,12 @@ const char* PlanNode::toString(PlanNode::Kind kind) {
return "ShowCharset";
case Kind::kShowCollation:
return "ShowCollation";
+ case Kind::kShowConfigs:
+ return "ShowConfigs";
+ case Kind::kSetConfig:
+ return "SetConfig";
+ case Kind::kGetConfig:
+ return "GetConfig";
// no default so the compiler will warning when lack
}
LOG(FATAL) << "Impossible kind plan node " << static_cast<int>(kind);
diff --git a/src/planner/PlanNode.h b/src/planner/PlanNode.h
index bd9cc35c9475af761497a21bbae8fc8f4bf80e42..1baa6935ca1e616a2442917e6bfd8b54b004ea83 100644
--- a/src/planner/PlanNode.h
+++ b/src/planner/PlanNode.h
@@ -79,6 +79,9 @@ public:
kShowParts,
kShowCharset,
kShowCollation,
+ kShowConfigs,
+ kSetConfig,
+ kGetConfig,
};
PlanNode(ExecutionPlan* plan, Kind kind);
diff --git a/src/planner/test/CMakeLists.txt b/src/planner/test/CMakeLists.txt
index 3c639639a3a6060d679f779c9786bed3422c1a87..455c036caeafdaae3fff7b1f4d45689321be0878 100644
--- a/src/planner/test/CMakeLists.txt
+++ b/src/planner/test/CMakeLists.txt
@@ -9,6 +9,7 @@ nebula_add_test(
ExecutionPlanTest.cpp
OBJECTS
$<TARGET_OBJECTS:common_time_function_obj>
+ $<TARGET_OBJECTS:common_conf_obj>
$<TARGET_OBJECTS:common_expression_obj>
$<TARGET_OBJECTS:common_http_client_obj>
$<TARGET_OBJECTS:common_network_obj>
diff --git a/src/service/PermissionCheck.cpp b/src/service/PermissionCheck.cpp
index 11500ef3c5b09ce2f918e10a85b77ce34dcd5610..4f0476628a4051d28bd3953c4ea7f3e75fc87dfb 100644
--- a/src/service/PermissionCheck.cpp
+++ b/src/service/PermissionCheck.cpp
@@ -57,8 +57,10 @@ bool PermissionCheck::permissionCheck(Session *session,
case Sentence::Kind::kDropSnapshot :
case Sentence::Kind::kBalance :
case Sentence::Kind::kAdminJob :
+ case Sentence::Kind::kShowConfigs :
+ case Sentence::Kind::kSetConfig :
+ case Sentence::Kind::kGetConfig :
case Sentence::Kind::kIngest :
- case Sentence::Kind::kConfig :
case Sentence::Kind::kDownload : {
return PermissionManager::canWriteSpace(session);
}
diff --git a/src/validator/AdminValidator.cpp b/src/validator/AdminValidator.cpp
index 6ccb1f9475a475bad602f59266f592c4cdf4a86d..7e4e4a0d8a1174ed55037145318e214c502da1f8 100644
--- a/src/validator/AdminValidator.cpp
+++ b/src/validator/AdminValidator.cpp
@@ -256,5 +256,108 @@ Status ShowCollationValidator::toPlan() {
tail_ = root_;
return Status::OK();
}
+
+Status ShowConfigsValidator::validateImpl() {
+ return Status::OK();
+}
+
+Status ShowConfigsValidator::toPlan() {
+ auto sentence = static_cast<ShowConfigsSentence*>(sentence_);
+ meta::cpp2::ConfigModule module;
+ auto item = sentence->configItem();
+ if (item != nullptr) {
+ module = item->getModule();
+ } else {
+ module = meta::cpp2::ConfigModule::ALL;
+ }
+ auto* plan = qctx_->plan();
+ auto *doNode = ShowConfigs::make(plan, nullptr, module);
+ root_ = doNode;
+ tail_ = root_;
+ return Status::OK();
+}
+
+Status SetConfigValidator::validateImpl() {
+ auto sentence = static_cast<SetConfigSentence*>(sentence_);
+ auto item = sentence->configItem();
+ if (item == nullptr) {
+ return Status::Error("Empty config item");
+ }
+ if (item->getName() != nullptr) {
+ name_ = *item->getName();
+ }
+ name_ = *item->getName();
+ module_ = item->getModule();
+ auto updateItems = item->getUpdateItems();
+ QueryExpressionContext ctx(nullptr, nullptr);
+ if (updateItems == nullptr) {
+ module_ = item->getModule();
+ if (item->getName() != nullptr) {
+ name_ = *item->getName();
+ }
+
+ if (item->getValue() != nullptr) {
+ value_ = Expression::eval(item->getValue(), ctx);
+ }
+ } else {
+ Map configs;
+ for (auto &updateItem : updateItems->items()) {
+ std::string name;
+ Value value;
+ if (updateItem->getFieldName() == nullptr || updateItem->value() == nullptr) {
+ return Status::Error("Empty item");
+ }
+ name = *updateItem->getFieldName();
+
+ value = Expression::eval(const_cast<Expression*>(updateItem->value()), ctx);
+
+ if (value.isNull() || (!value.isNumeric() && !value.isStr() && !value.isBool())) {
+ return Status::Error("Wrong value: %s", name.c_str());
+ }
+ configs.kvs.emplace(std::move(name), std::move(value));
+ }
+ value_.setMap(std::move(configs));
+ }
+
+ return Status::OK();
+}
+
+Status SetConfigValidator::toPlan() {
+ auto* plan = qctx_->plan();
+ auto *doNode = SetConfig::make(plan,
+ nullptr,
+ module_,
+ std::move(name_),
+ std::move(value_));
+ root_ = doNode;
+ tail_ = root_;
+ return Status::OK();
+}
+
+Status GetConfigValidator::validateImpl() {
+ auto sentence = static_cast<GetConfigSentence*>(sentence_);
+ auto item = sentence->configItem();
+ if (item == nullptr) {
+ return Status::Error("Empty config item");
+ }
+
+ module_ = item->getModule();
+ if (item->getName() != nullptr) {
+ name_ = *item->getName();
+ }
+ name_ = *item->getName();
+ return Status::OK();
+}
+
+Status GetConfigValidator::toPlan() {
+ auto* plan = qctx_->plan();
+ auto *doNode = GetConfig::make(plan,
+ nullptr,
+ module_,
+ std::move(name_));
+ root_ = doNode;
+ tail_ = root_;
+ return Status::OK();
+}
} // namespace graph
} // namespace nebula
diff --git a/src/validator/AdminValidator.h b/src/validator/AdminValidator.h
index 1a29a95982d69a9847bc071212995019f3ad197f..f1b20f647141eaded0aa3fa7973b294c16444158 100644
--- a/src/validator/AdminValidator.h
+++ b/src/validator/AdminValidator.h
@@ -173,6 +173,54 @@ private:
Status toPlan() override;
};
+
+class ShowConfigsValidator final : public Validator {
+public:
+ ShowConfigsValidator(Sentence* sentence, QueryContext* context)
+ : Validator(sentence, context) {
+ setNoSpaceRequired();
+ }
+
+private:
+ Status validateImpl() override;
+
+ Status toPlan() override;
+};
+
+class SetConfigValidator final : public Validator {
+public:
+ SetConfigValidator(Sentence* sentence, QueryContext* context)
+ : Validator(sentence, context) {
+ setNoSpaceRequired();
+ }
+
+private:
+ Status validateImpl() override;
+
+ Status toPlan() override;
+
+private:
+ meta::cpp2::ConfigModule module_;
+ std::string name_;
+ Value value_;
+};
+
+class GetConfigValidator final : public Validator {
+public:
+ GetConfigValidator(Sentence* sentence, QueryContext* context)
+ : Validator(sentence, context) {
+ setNoSpaceRequired();
+ }
+
+private:
+ Status validateImpl() override;
+
+ Status toPlan() override;
+
+private:
+ meta::cpp2::ConfigModule module_;
+ std::string name_;
+};
} // namespace graph
} // namespace nebula
#endif // VALIDATOR_ADMINVALIDATOR_H_
diff --git a/src/validator/ReportError.h b/src/validator/ReportError.h
index fba7a439561a919dab457e79b7b506b07be2a5ea..6d8d91e3206a909c8d8634e45191b985a346ae82 100644
--- a/src/validator/ReportError.h
+++ b/src/validator/ReportError.h
@@ -14,7 +14,9 @@ namespace graph {
class ReportError final : public Validator {
public:
ReportError(Sentence* sentence, QueryContext* context)
- : Validator(sentence, context) {}
+ : Validator(sentence, context) {
+ setNoSpaceRequired();
+ }
private:
Status validateImpl() override {
diff --git a/src/validator/Validator.cpp b/src/validator/Validator.cpp
index 428507b0386073113bedbad625735c96a1989301..195285a812d09a16a72abf49caa770fea49c4282 100644
--- a/src/validator/Validator.cpp
+++ b/src/validator/Validator.cpp
@@ -132,6 +132,12 @@ std::unique_ptr<Validator> Validator::makeValidator(Sentence* sentence, QueryCon
return std::make_unique<ShowCharsetValidator>(sentence, context);
case Sentence::Kind::kShowCollation:
return std::make_unique<ShowCollationValidator>(sentence, context);
+ case Sentence::Kind::kGetConfig:
+ return std::make_unique<GetConfigValidator>(sentence, context);
+ case Sentence::Kind::kSetConfig:
+ return std::make_unique<SetConfigValidator>(sentence, context);
+ case Sentence::Kind::kShowConfigs:
+ return std::make_unique<ShowConfigsValidator>(sentence, context);
case Sentence::Kind::kUnknown:
case Sentence::Kind::kMatch:
case Sentence::Kind::kCreateTagIndex:
@@ -160,7 +166,6 @@ std::unique_ptr<Validator> Validator::makeValidator(Sentence* sentence, QueryCon
case Sentence::Kind::kDownload:
case Sentence::Kind::kIngest:
case Sentence::Kind::kBalance:
- case Sentence::Kind::kConfig:
case Sentence::Kind::kFindPath:
case Sentence::Kind::kReturn: {
// nothing
@@ -215,7 +220,10 @@ Status Validator::appendPlan(PlanNode* node, PlanNode* appended) {
case PlanNode::Kind::kUpdateEdge:
case PlanNode::Kind::kShowParts:
case PlanNode::Kind::kShowCharset:
- case PlanNode::Kind::kShowCollation: {
+ case PlanNode::Kind::kShowCollation:
+ case PlanNode::Kind::kShowConfigs:
+ case PlanNode::Kind::kSetConfig:
+ case PlanNode::Kind::kGetConfig: {
static_cast<SingleDependencyNode*>(node)->dependsOn(appended);
break;
}
diff --git a/tests/admin/test_configs.py b/tests/admin/test_configs.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0db1132c5b683990856e2278e62db630634dbb7
--- /dev/null
+++ b/tests/admin/test_configs.py
@@ -0,0 +1,122 @@
+# --coding:utf-8--
+#
+# Copyright (c) 2020 vesoft inc. All rights reserved.
+#
+# This source code is licensed under Apache 2.0 License,
+# attached with Common Clause Condition 1.0, found in the LICENSES directory.
+
+import time
+import re
+
+from tests.common.nebula_test_suite import NebulaTestSuite
+from nebula2.common import ttypes
+
+class TestConfigs(NebulaTestSuite):
+
+ @classmethod
+ def prepare(self):
+ pass
+
+ @classmethod
+ def cleanup(self):
+ pass
+
+ def test_configs(self):
+ # set/get without declaration
+ resp = self.client.execute('UPDATE CONFIGS storage:notRegistered=123;')
+ self.check_resp_failed(resp)
+
+ # update immutable config will fail, read-only
+ resp = self.client.execute_query('UPDATE CONFIGS storage:num_io_threads=10')
+ self.check_resp_failed(resp)
+
+ # set and get config after declaration
+ v = 3
+ resp = self.client.execute('UPDATE CONFIGS meta:v={}'.format(3))
+ self.check_resp_failed(resp)
+ resp = self.client.execute('UPDATE CONFIGS graph:v={}'.format(3))
+ self.check_resp_succeeded(resp)
+ resp = self.client.execute('UPDATE CONFIGS storage:v={}'.format(3))
+ self.check_resp_succeeded(resp)
+
+ # get
+ resp = self.client.execute('GET CONFIGS meta:v')
+ self.check_resp_failed(resp)
+
+ resp = self.client.execute_query('GET CONFIGS graph:v')
+ self.check_resp_succeeded(resp)
+ expected_result = [['GRAPH', 'v', 'int', 'MUTABLE', 3]]
+ self.check_result(resp, expected_result)
+
+ resp = self.client.execute_query('GET CONFIGS storage:v')
+ self.check_resp_succeeded(resp)
+ expected_result = [['STORAGE', 'v', 'int', 'MUTABLE', 3]]
+ self.check_result(resp, expected_result)
+
+ # show configs
+ resp = self.client.execute_query('SHOW CONFIGS meta')
+ self.check_resp_succeeded(resp)
+
+ resp = self.client.execute_query('SHOW CONFIGS graph')
+ self.check_resp_succeeded(resp)
+ expected_result = [['GRAPH', 'v', 'int', 'MUTABLE', v],
+ ['GRAPH', 'minloglevel', 'int', 'MUTABLE', 0],
+ ['GRAPH', 'slow_op_threshhold_ms', 'int', 'MUTABLE', 50],
+ ['GRAPH', 'heartbeat_interval_secs', 'int', 'MUTABLE', 1],
+ ['GRAPH', 'meta_client_retry_times', 'int', 'MUTABLE', 3]]
+ self.check_out_of_order_result(resp, expected_result)
+
+ resp = self.client.execute_query('SHOW CONFIGS storage')
+ self.check_resp_succeeded(resp)
+ expected_result = [['STORAGE', 'v', 'int', 'MUTABLE', 3],
+ ['STORAGE', 'wal_ttl', 'int', 'MUTABLE', 14400],
+ ['STORAGE', 'minloglevel', 'int', 'MUTABLE', 0],
+ ['STORAGE', 'enable_reservoir_sampling', 'bool', 'MUTABLE', False],
+ ['STORAGE', 'custom_filter_interval_secs', 'int', 'MUTABLE', 86400],
+ ['STORAGE', 'slow_op_threshhold_ms', 'int', 'MUTABLE', 50],
+ ['STORAGE', 'heartbeat_interval_secs', 'int', 'MUTABLE', 1],
+ ['STORAGE', 'meta_client_retry_times', 'int', 'MUTABLE', 3],
+ ['STORAGE', 'rocksdb_db_options', 'map', 'MUTABLE', {}],
+ ['STORAGE', 'max_edge_returned_per_vertex', 'int', 'MUTABLE', 2147483647],
+ ['STORAGE', 'rocksdb_column_family_options', 'map', 'MUTABLE',
+ {"write_buffer_size":"67108864","max_bytes_for_level_base":"268435456","max_write_buffer_number":"4"}],
+ ['STORAGE', 'rocksdb_block_based_table_options', 'map', 'MUTABLE', {"block_size":"8192"}]]
+ self.check_out_of_order_result(resp, expected_result)
+
+ # set and get a config of all module
+ resp = self.client.execute('UPDATE CONFIGS minloglevel={}'.format(2))
+ self.check_resp_succeeded(resp)
+
+ # check result
+ resp = self.client.execute_query('GET CONFIGS minloglevel')
+ self.check_resp_succeeded(resp)
+ expected_result = [['GRAPH', 'minloglevel', 'int', 'MUTABLE', 2],
+ ['STORAGE', 'minloglevel', 'int', 'MUTABLE', 2]]
+ self.check_out_of_order_result(resp, expected_result)
+
+ # update storage
+ resp = self.client.execute('UPDATE CONFIGS storage:minloglevel={}'.format(3))
+ self.check_resp_succeeded(resp)
+
+ # get result
+ resp = self.client.execute_query('GET CONFIGS minloglevel')
+ self.check_resp_succeeded(resp)
+ expected_result = [['GRAPH', 'minloglevel', 'int', 'MUTABLE', 2],
+ ['STORAGE', 'minloglevel', 'int', 'MUTABLE', 3]]
+ self.check_result(resp, expected_result)
+
+ # update rocksdb
+ resp = self.client.execute('''
+ UPDATE CONFIGS storage:rocksdb_column_family_options={
+ max_bytes_for_level_base=1024,
+ write_buffer_size=1024,
+ max_write_buffer_number=4}
+ ''')
+ self.check_resp_succeeded(resp)
+
+ # get result
+ resp = self.client.execute_query('GET CONFIGS storage:rocksdb_column_family_options')
+ self.check_resp_succeeded(resp)
+ value = {"max_bytes_for_level_base": 1024, "write_buffer_size": 1024, "max_write_buffer_number": 4}
+ expected_result = [['STORAGE', 'rocksdb_column_family_options', 'map', 'MUTABLE', value]]
+ self.check_result(resp, expected_result)
diff --git a/tests/common/nebula_service.py b/tests/common/nebula_service.py
index 0fd1511663871ae4981348f33e5b16826bd9087c..32e99eea0df0474d8ec0331d9f8146e78c40149a 100644
--- a/tests/common/nebula_service.py
+++ b/tests/common/nebula_service.py
@@ -48,6 +48,11 @@ class NebulaService(object):
shutil.copy(storage_conf_path + '/nebula-metad.conf.default',
self.work_dir + '/conf/nebula-metad.conf')
+ # gflags.json
+ resources_dir = self.work_dir + '/share/resources/'
+ os.makedirs(resources_dir)
+ shutil.copy(self.build_dir + '/../resources/gflags.json', resources_dir)
+
def _format_nebula_command(self, name, meta_port, ports, debug_log = True):
param_format = "--meta_server_addrs={} --port={} --ws_http_port={} --ws_h2_port={} --heartbeat_interval_secs=1"
param = param_format.format("127.0.0.1:" + str(meta_port), ports[0],
diff --git a/tests/common/nebula_test_suite.py b/tests/common/nebula_test_suite.py
index c8a6b3421a5b264fdf9ec28ffd4b4e6f55777724..4463240d52db3062f5708f6a2ebf1de0eeb70564 100644
--- a/tests/common/nebula_test_suite.py
+++ b/tests/common/nebula_test_suite.py
@@ -219,26 +219,61 @@ class NebulaTestSuite(object):
else:
return False, msg
+ @classmethod
+ def date_to_string(self, date):
+ return '{}/{}/{}'.format(date.year, date.month, date.day)
+
+ @classmethod
+ def date_time_to_string(self, date_time):
+ zone = '+'
+ if date_time.timezone < 0:
+ zone = '-'
+ return '{}/{}/{} {}:{}:{}.{} {}{}.{}'.format(date_time.year,
+ date_time.month,
+ date_time.day,
+ date_time.hour,
+ date_time.minute,
+ date_time.sec,
+ date_time.microsec,
+ zone,
+ date_time.timezone / 3600,
+ date_time.timezone % 3600)
+ @classmethod
+ def map_to_string(self, map):
+ kvStrs = []
+ if map.kvs is not None:
+ for key in map.kvs:
+ kvStrs.append('"{}":"{}"'.format(key.decode('utf-8'), self.value_to_string(map.kvs[key])))
+ return '{' + ','.join(kvStrs) + '}'
+ return ''
+
+ @classmethod
+ def value_to_string(self, value):
+ if value.getType() == CommonTtypes.Value.__EMPTY__:
+ return '__EMPTY__'
+ elif value.getType() == CommonTtypes.Value.NVAL:
+ return '__NULL__'
+ elif value.getType() == CommonTtypes.Value.BVAL:
+ return str(value.get_bVal())
+ elif value.getType() == CommonTtypes.Value.IVAL:
+ return str(value.get_iVal())
+ elif value.getType() == CommonTtypes.Value.FVAL:
+ return str(value.get_fVal())
+ elif value.getType() == CommonTtypes.Value.SVAL:
+ return value.get_sVal().decode('utf-8')
+ elif value.getType() == CommonTtypes.Value.DVAL:
+ return self.date_time_to_string(value.get_dVal())
+ elif value.getType() == CommonTtypes.Value.TVAL:
+ return self.date_time_to_string(value.get_tVal())
+ elif value.getType() == CommonTtypes.Value.MVAL:
+ return self.map_to_string(value.get_mVal())
+ return 'Unsupported type'
+
@classmethod
def row_to_string(self, row):
value_list = []
for col in row.values:
- if col.getType() == CommonTtypes.Value.__EMPTY__:
- value_list.append('__EMPTY__')
- elif col.getType() == CommonTtypes.Value.NVAL:
- value_list.append('__NULL__')
- elif col.getType() == CommonTtypes.Value.BVAL:
- value_list.append(col.get_bVal())
- elif col.getType() == CommonTtypes.Value.IVAL:
- value_list.append(col.get_iVal())
- elif col.getType() == CommonTtypes.Value.FVAL:
- value_list.append(col.get_fVal())
- elif col.getType() == CommonTtypes.Value.SVAL:
- value_list.append(col.get_sVal().decode('utf-8'))
- elif col.getType() == CommonTtypes.Type.DVAL:
- value_list.append(col.get_dVal().decode('utf-8'))
- elif col.getType() == CommonTtypes.Type.DATETIME:
- value_list.append(col.get_datetime())
+ value_list.append(self.value_to_string(col))
return str(value_list)
@classmethod
@@ -304,6 +339,30 @@ class NebulaTestSuite(object):
ok = (expect[i] == result)
assert ok, "different column name, expect: {} vs. result: {}".format(expect[i], result)
+ @classmethod
+ def to_value(self, col):
+ value = CommonTtypes.Value()
+ if isinstance(col, bool):
+ value.set_bVal(col)
+ elif isinstance(col, int):
+ value.set_iVal(col)
+ elif isinstance(col, float):
+ value.set_fVal(col)
+ elif isinstance(col, str):
+ value.set_sVal(col.encode('utf-8'))
+ elif isinstance(col, dict):
+ map_val = CommonTtypes.Map()
+ map_val.kvs = dict()
+ for key in col:
+ ok, temp = self.to_value(col[key])
+ if not ok:
+ return ok, temp
+ map_val.kvs[key.encode('utf-8')] = temp
+ value.set_mVal(map_val)
+ else:
+ return False, 'Wrong val type'
+ return True, value
+
@classmethod
def convert_expect(self, expect):
result = []
@@ -316,15 +375,9 @@ class NebulaTestSuite(object):
if isinstance(col, CommonTtypes.Value):
new_row.values.append(col)
else:
- value = CommonTtypes.Value()
- if isinstance(col, bool):
- value.set_bVal(col)
- elif isinstance(col, int):
- value.set_iVal(col)
- elif isinstance(col, float):
- value.set_fVal(col)
- elif isinstance(col, str):
- value.set_sVal(col.encode('utf-8'))
+ ok, value = self.to_value(col)
+ if not ok:
+ return ok, value
new_row.values.append(value)
result.append(new_row)
return True, result, ''
diff --git a/tests/nebula-test-run.py b/tests/nebula-test-run.py
index a8e83a05f3efa94740e9739a5e65b7ad4f680475..3fa5770a3f6331f6d5d865a3676d4c72d8517b35 100755
--- a/tests/nebula-test-run.py
+++ b/tests/nebula-test-run.py
@@ -61,7 +61,6 @@ class TestExecutor(object):
#self.total_executed += len(plugin.tests_executed)
return error_code
-
if __name__ == "__main__":
# If the user is just asking for --help, just print the help test and then exit.
executor = TestExecutor()
diff --git a/tests/query/stateless/test_admin.py b/tests/query/stateless/test_admin.py
index 28834b56bed5ee6eab55a2f47514a3b2d3ae494b..f6d9c2d3fe6c085a65e94656067497132727598b 100644
--- a/tests/query/stateless/test_admin.py
+++ b/tests/query/stateless/test_admin.py
@@ -40,10 +40,10 @@ class TestAdmin(NebulaTestSuite):
# Backup
resp = self.client.execute_query('GET CONFIGS graph:minloglevel')
self.check_resp_succeeded(resp)
- graph_minloglevel = resp.rows[0].columns[4].get_str()
+ graph_minloglevel = resp.data.rows[0].values[4].get_iVal()
resp = self.client.execute_query('GET CONFIGS storage:minloglevel')
self.check_resp_succeeded(resp)
- storage_minloglevel = resp.rows[0].columns[4].get_str()
+ storage_minloglevel = resp.data.rows[0].values[4].get_iVal()
# Set
minloglevel = 3
@@ -57,14 +57,14 @@ class TestAdmin(NebulaTestSuite):
# get
resp = self.client.execute('GET CONFIGS meta:minloglevel')
self.check_resp_failed(resp)
- result = [['GRAPH', 'minloglevel', 'INT64', 'MUTABLE', str(minloglevel)]]
+ result = [['GRAPH', 'minloglevel', 'int', 'MUTABLE', minloglevel]]
resp = self.client.execute_query('GET CONFIGS graph:minloglevel')
self.check_resp_succeeded(resp)
- self.check_result(resp.rows, result)
- result = [['STORAGE', 'minloglevel', 'INT64', 'MUTABLE', str(minloglevel)]]
+ self.check_result(resp, result)
+ result = [['STORAGE', 'minloglevel', 'int', 'MUTABLE', minloglevel]]
resp = self.client.execute_query('GET CONFIGS storage:minloglevel')
self.check_resp_succeeded(resp)
- self.check_result(resp.rows, result)
+ self.check_result(resp, result)
# rollback
resp = self.client.execute('UPDATE CONFIGS graph:minloglevel={}'.format(int(graph_minloglevel)))