catalog: Implement Sync Update Executor
Change-Id: I88a0c6935d7b8094dfb587e83270a607e753ea31
refs: #2611
diff --git a/catalog/src/query/query-adapter.hpp b/catalog/src/query/query-adapter.hpp
index 2adb161..ccfefb6 100644
--- a/catalog/src/query/query-adapter.hpp
+++ b/catalog/src/query/query-adapter.hpp
@@ -198,6 +198,10 @@
json2AutocompletionSql(std::stringstream& sqlQuery,
Json::Value& jsonValue);
+ bool
+ json2CompleteSearchSql(std::stringstream& sqlQuery,
+ Json::Value& jsonValue);
+
protected:
typedef std::unordered_map<ndn::Name, const ndn::RegisteredPrefixId*> RegisteredPrefixList;
// Handle to the Catalog's database
@@ -439,9 +443,9 @@
nack->setFinalBlockId(ndn::Name::Component::fromSegment(segmentNo));
signData(*nack);
-
+#ifndef NDEBUG
std::cout << "make NACK : " << ndn::Name(dataPrefix).appendSegment(segmentNo) << std::endl;
-
+#endif
m_mutex.lock();
m_cache.insert(*nack);
m_mutex.unlock();
@@ -563,7 +567,86 @@
// 2. generate the sql string (append what appears in the typed string, like activity='xxx'),
// return true
bool more = false;
- sqlQuery << "SELECT " << m_nameFields[count] << " FROM cmip5";
+ sqlQuery << "SELECT DISTINCT " << m_nameFields[count] << " FROM cmip5";
+ for (std::map<std::string, std::string>::iterator it = typedComponents.begin();
+ it != typedComponents.end(); ++it) {
+ if (more)
+ sqlQuery << " AND";
+ else
+ sqlQuery << " WHERE";
+
+ sqlQuery << " " << it->first << "='" << it->second << "'";
+
+ more = true;
+ }
+ sqlQuery << ";";
+ return true;
+}
+
+template <typename DatabaseHandler>
+bool
+QueryAdapter<DatabaseHandler>::json2CompleteSearchSql(std::stringstream& sqlQuery,
+ Json::Value& jsonValue)
+{
+#ifndef NDEBUG
+ std::cout << "jsonValue in json2CompleteSearchSql: " << jsonValue.toStyledString() << std::endl;
+#endif
+ if (jsonValue.type() != Json::objectValue) {
+ std::cout << jsonValue.toStyledString() << "is not json object" << std::endl;
+ return false;
+ }
+
+ std::string typedString;
+ // get the string in the jsonValue
+ for (Json::Value::iterator iter = jsonValue.begin(); iter != jsonValue.end(); ++iter)
+ {
+ Json::Value key = iter.key();
+ Json::Value value = (*iter);
+
+ if (key == Json::nullValue || value == Json::nullValue) {
+ std::cout << "null key or value in JsonValue: " << jsonValue.toStyledString() << std::endl;
+ return false;
+ }
+
+ // cannot convert to string
+ if (!key.isConvertibleTo(Json::stringValue) || !value.isConvertibleTo(Json::stringValue)) {
+ std::cout << "malformed JsonQuery string : " << jsonValue.toStyledString() << std::endl;
+ return false;
+ }
+
+ if (key.asString().compare("??") == 0) {
+ typedString.assign(value.asString());
+ // since the front end triggers the autocompletion when users typed '/',
+ // there must be a '/' at the end, and the first char must be '/'
+ if (typedString.at(typedString.length() - 1) != '/' || typedString.find("/") != 0)
+ return false;
+ break;
+ }
+ }
+
+ // 1. get the expected column number by parsing the typedString, so we can get the filed name
+ size_t pos = 0;
+ size_t start = 1; // start from the 1st char which is not '/'
+ size_t count = 0; // also the name to query for
+ std::string token;
+ std::string delimiter = "/";
+ std::map<std::string, std::string> typedComponents;
+ while ((pos = typedString.find(delimiter, start)) != std::string::npos) {
+ token = typedString.substr(start, pos - start);
+ if (count >= m_nameFields.size() - 1) {
+ return false;
+ }
+
+ // add column name and value (token) into map
+ typedComponents.insert(std::pair<std::string, std::string>(m_nameFields[count], token));
+ count ++;
+ start = pos + 1;
+ }
+
+ // 2. generate the sql string (append what appears in the typed string, like activity='xxx'),
+ // return true
+ bool more = false;
+ sqlQuery << "SELECT name FROM cmip5";
for (std::map<std::string, std::string>::iterator it = typedComponents.begin();
it != typedComponents.end(); ++it) {
if (more)
@@ -668,6 +751,12 @@
return;
}
}
+ else if (parsedFromString.get("??", tmp) != tmp) {
+ if (!json2CompleteSearchSql(sqlQuery, parsedFromString)) {
+ sendNack(segmentPrefix);
+ return;
+ }
+ }
else {
if (!json2Sql(sqlQuery, parsedFromString)) {
sendNack(segmentPrefix);
@@ -695,11 +784,16 @@
const std::string& sqlString,
bool autocomplete)
{
+#ifndef NDEBUG
std::cout << "prepareSegments() executes sql : " << sqlString << std::endl;
-
+#endif
+ std::string errMsg;
+ bool success;
// 4) Run the Query
std::shared_ptr<MYSQL_RES> results
- = atmos::util::MySQLPerformQuery(m_databaseHandler, sqlString);
+ = atmos::util::MySQLPerformQuery(m_databaseHandler, sqlString, util::QUERY, success, errMsg);
+ if (!success)
+ std::cout << errMsg << std::endl;
if (!results) {
std::cout << "null MYSQL_RES for query : " << sqlString << std::endl;
@@ -717,27 +811,29 @@
<< " rows" << std::endl;
MYSQL_ROW row;
- size_t usedBytes = 0;
uint64_t segmentNo = 0;
- Json::Value array;
+ Json::Value tmp;
+ Json::Value resultJson;
+ Json::FastWriter fastWriter;
while ((row = mysql_fetch_row(results.get())))
{
- size_t size = strlen(row[0]) + 1;
- if (usedBytes + size > PAYLOAD_LIMIT) {
+ tmp.append(row[0]);
+ const std::string tmpString = fastWriter.write(tmp);
+ if (tmpString.length() > PAYLOAD_LIMIT) {
std::shared_ptr<ndn::Data> data
- = makeReplyData(segmentPrefix, array, segmentNo, false, autocomplete, resultCount);
+ = makeReplyData(segmentPrefix, resultJson, segmentNo, false, autocomplete, resultCount);
m_mutex.lock();
m_cache.insert(*data);
m_mutex.unlock();
- array.clear();
- usedBytes = 0;
- segmentNo++;
+ tmp.clear();
+ resultJson.clear();
+ segmentNo ++;
}
- array.append(row[0]);
- usedBytes += size;
+ resultJson.append(row[0]);
}
+
std::shared_ptr<ndn::Data> data
- = makeReplyData(segmentPrefix, array, segmentNo, true, autocomplete, resultCount);
+ = makeReplyData(segmentPrefix, resultJson, segmentNo, true, autocomplete, resultCount);
m_mutex.lock();
m_cache.insert(*data);
m_mutex.unlock();