| /** | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| #include "Common.h" | |
| #include <boost/date_time/gregorian/gregorian.hpp> | |
| int32_t parseDateExpressionToInt(const boost::gregorian::date& date) { | |
| if (date.is_not_a_date()) { | |
| throw IoTDBException("Date expression is null or empty."); | |
| } | |
| const int year = date.year(); | |
| if (year < 1000 || year > 9999) { | |
| throw DateTimeParseException( | |
| "Year must be between 1000 and 9999.", | |
| boost::gregorian::to_iso_extended_string(date), | |
| 0 | |
| ); | |
| } | |
| const int64_t result = static_cast<int64_t>(year) * 10000 + | |
| date.month() * 100 + | |
| date.day(); | |
| if (result > INT32_MAX || result < INT32_MIN) { | |
| throw DateTimeParseException( | |
| "Date value overflow. ", | |
| boost::gregorian::to_iso_extended_string(date), | |
| 0 | |
| ); | |
| } | |
| return static_cast<int32_t>(result); | |
| } | |
| boost::gregorian::date parseIntToDate(int32_t dateInt) { | |
| if (dateInt == EMPTY_DATE_INT) { | |
| return boost::gregorian::date(boost::date_time::not_a_date_time); | |
| } | |
| int year = dateInt / 10000; | |
| int month = (dateInt % 10000) / 100; | |
| int day = dateInt % 100; | |
| return boost::gregorian::date(year, month, day); | |
| } | |
| std::string getTimePrecision(int32_t timeFactor) { | |
| if (timeFactor >= 1000000) return "us"; | |
| if (timeFactor >= 1000) return "ms"; | |
| return "s"; | |
| } | |
| std::string formatDatetime(const std::string& format, const std::string& precision, | |
| int64_t timestamp, const std::string& zoneId) { | |
| // Simplified implementation - in real code you'd use proper timezone handling | |
| std::time_t time = static_cast<std::time_t>(timestamp); | |
| std::tm* tm = std::localtime(&time); | |
| char buffer[80]; | |
| strftime(buffer, sizeof(buffer), format.c_str(), tm); | |
| return std::string(buffer); | |
| } | |
| std::tm convertToTimestamp(int64_t value, int32_t timeFactor) { | |
| std::time_t time = static_cast<std::time_t>(value / timeFactor); | |
| return *std::localtime(&time); | |
| } | |
| TSDataType::TSDataType getDataTypeByStr(const std::string& typeStr) { | |
| if (typeStr == "BOOLEAN") return TSDataType::BOOLEAN; | |
| if (typeStr == "INT32") return TSDataType::INT32; | |
| if (typeStr == "INT64") return TSDataType::INT64; | |
| if (typeStr == "FLOAT") return TSDataType::FLOAT; | |
| if (typeStr == "DOUBLE") return TSDataType::DOUBLE; | |
| if (typeStr == "TEXT") return TSDataType::TEXT; | |
| if (typeStr == "TIMESTAMP") return TSDataType::TIMESTAMP; | |
| if (typeStr == "DATE") return TSDataType::DATE; | |
| if (typeStr == "BLOB") return TSDataType::BLOB; | |
| if (typeStr == "STRING") return TSDataType::STRING; | |
| return TSDataType::UNKNOWN; | |
| } | |
| std::tm int32ToDate(int32_t value) { | |
| // Convert days since epoch (1970-01-01) to tm struct | |
| std::time_t time = static_cast<std::time_t>(value) * 86400; // seconds per day | |
| return *std::localtime(&time); | |
| } | |
| void RpcUtils::verifySuccess(const TSStatus& status) { | |
| if (status.code == TSStatusCode::MULTIPLE_ERROR) { | |
| verifySuccess(status.subStatus); | |
| return; | |
| } | |
| if (status.code != TSStatusCode::SUCCESS_STATUS | |
| && status.code != TSStatusCode::REDIRECTION_RECOMMEND) { | |
| throw ExecutionException(to_string(status.code) + ": " + status.message, status); | |
| } | |
| } | |
| void RpcUtils::verifySuccessWithRedirection(const TSStatus& status) { | |
| verifySuccess(status); | |
| if (status.__isset.redirectNode) { | |
| throw RedirectException(to_string(status.code) + ": " + status.message, status.redirectNode); | |
| } | |
| if (status.__isset.subStatus) { | |
| auto statusSubStatus = status.subStatus; | |
| vector<TEndPoint> endPointList(statusSubStatus.size()); | |
| int count = 0; | |
| for (TSStatus subStatus : statusSubStatus) { | |
| if (subStatus.__isset.redirectNode) { | |
| endPointList[count++] = subStatus.redirectNode; | |
| } | |
| else { | |
| TEndPoint endPoint; | |
| endPointList[count++] = endPoint; | |
| } | |
| } | |
| if (!endPointList.empty()) { | |
| throw RedirectException(to_string(status.code) + ": " + status.message, endPointList); | |
| } | |
| } | |
| } | |
| void RpcUtils::verifySuccessWithRedirectionForMultiDevices(const TSStatus& status, vector<string> devices) { | |
| verifySuccess(status); | |
| if (status.code == TSStatusCode::MULTIPLE_ERROR | |
| || status.code == TSStatusCode::REDIRECTION_RECOMMEND) { | |
| map<string, TEndPoint> deviceEndPointMap; | |
| vector<TSStatus> statusSubStatus; | |
| for (int i = 0; i < statusSubStatus.size(); i++) { | |
| TSStatus subStatus = statusSubStatus[i]; | |
| if (subStatus.__isset.redirectNode) { | |
| deviceEndPointMap.insert(make_pair(devices[i], subStatus.redirectNode)); | |
| } | |
| } | |
| throw RedirectException(to_string(status.code) + ": " + status.message, deviceEndPointMap); | |
| } | |
| if (status.__isset.redirectNode) { | |
| throw RedirectException(to_string(status.code) + ": " + status.message, status.redirectNode); | |
| } | |
| if (status.__isset.subStatus) { | |
| auto statusSubStatus = status.subStatus; | |
| vector<TEndPoint> endPointList(statusSubStatus.size()); | |
| int count = 0; | |
| for (TSStatus subStatus : statusSubStatus) { | |
| if (subStatus.__isset.redirectNode) { | |
| endPointList[count++] = subStatus.redirectNode; | |
| } | |
| else { | |
| TEndPoint endPoint; | |
| endPointList[count++] = endPoint; | |
| } | |
| } | |
| if (!endPointList.empty()) { | |
| throw RedirectException(to_string(status.code) + ": " + status.message, endPointList); | |
| } | |
| } | |
| } | |
| void RpcUtils::verifySuccess(const vector<TSStatus>& statuses) { | |
| for (const TSStatus& status : statuses) { | |
| if (status.code != TSStatusCode::SUCCESS_STATUS) { | |
| throw BatchExecutionException(status.message, statuses); | |
| } | |
| } | |
| } | |
| TSStatus RpcUtils::getStatus(TSStatusCode::TSStatusCode tsStatusCode) { | |
| TSStatus status; | |
| status.__set_code(tsStatusCode); | |
| return status; | |
| } | |
| TSStatus RpcUtils::getStatus(int code, const string& message) { | |
| TSStatus status; | |
| status.__set_code(code); | |
| status.__set_message(message); | |
| return status; | |
| } | |
| shared_ptr<TSExecuteStatementResp> RpcUtils::getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode) { | |
| TSStatus status = getStatus(tsStatusCode); | |
| return getTSExecuteStatementResp(status); | |
| } | |
| shared_ptr<TSExecuteStatementResp> | |
| RpcUtils::getTSExecuteStatementResp(TSStatusCode::TSStatusCode tsStatusCode, const string& message) { | |
| TSStatus status = getStatus(tsStatusCode, message); | |
| return getTSExecuteStatementResp(status); | |
| } | |
| shared_ptr<TSExecuteStatementResp> RpcUtils::getTSExecuteStatementResp(const TSStatus& status) { | |
| shared_ptr<TSExecuteStatementResp> resp(new TSExecuteStatementResp()); | |
| TSStatus tsStatus(status); | |
| resp->__set_status(status); | |
| return resp; | |
| } | |
| shared_ptr<TSFetchResultsResp> RpcUtils::getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode) { | |
| TSStatus status = getStatus(tsStatusCode); | |
| return getTSFetchResultsResp(status); | |
| } | |
| shared_ptr<TSFetchResultsResp> | |
| RpcUtils::getTSFetchResultsResp(TSStatusCode::TSStatusCode tsStatusCode, const string& appendMessage) { | |
| TSStatus status = getStatus(tsStatusCode, appendMessage); | |
| return getTSFetchResultsResp(status); | |
| } | |
| shared_ptr<TSFetchResultsResp> RpcUtils::getTSFetchResultsResp(const TSStatus& status) { | |
| shared_ptr<TSFetchResultsResp> resp(new TSFetchResultsResp()); | |
| TSStatus tsStatus(status); | |
| resp->__set_status(tsStatus); | |
| return resp; | |
| } | |
| MyStringBuffer::MyStringBuffer() : pos(0) { | |
| checkBigEndian(); | |
| } | |
| MyStringBuffer::MyStringBuffer(const std::string& str) : str(str), pos(0) { | |
| checkBigEndian(); | |
| } | |
| void MyStringBuffer::reserve(size_t n) { | |
| str.reserve(n); | |
| } | |
| void MyStringBuffer::clear() { | |
| str.clear(); | |
| pos = 0; | |
| } | |
| bool MyStringBuffer::hasRemaining() { | |
| return pos < str.size(); | |
| } | |
| int MyStringBuffer::getInt() { | |
| return *(int*)getOrderedByte(4); | |
| } | |
| boost::gregorian::date MyStringBuffer::getDate() { | |
| return parseIntToDate(getInt()); | |
| } | |
| int64_t MyStringBuffer::getInt64() { | |
| #ifdef ARCH32 | |
| const char *buf_addr = getOrderedByte(8); | |
| if (reinterpret_cast<uint32_t>(buf_addr) % 4 == 0) { | |
| return *(int64_t *)buf_addr; | |
| } else { | |
| char tmp_buf[8]; | |
| memcpy(tmp_buf, buf_addr, 8); | |
| return *(int64_t*)tmp_buf; | |
| } | |
| #else | |
| return *(int64_t*)getOrderedByte(8); | |
| #endif | |
| } | |
| float MyStringBuffer::getFloat() { | |
| return *(float*)getOrderedByte(4); | |
| } | |
| double MyStringBuffer::getDouble() { | |
| #ifdef ARCH32 | |
| const char *buf_addr = getOrderedByte(8); | |
| if (reinterpret_cast<uint32_t>(buf_addr) % 4 == 0) { | |
| return *(double*)buf_addr; | |
| } else { | |
| char tmp_buf[8]; | |
| memcpy(tmp_buf, buf_addr, 8); | |
| return *(double*)tmp_buf; | |
| } | |
| #else | |
| return *(double*)getOrderedByte(8); | |
| #endif | |
| } | |
| char MyStringBuffer::getChar() { | |
| return str[pos++]; | |
| } | |
| bool MyStringBuffer::getBool() { | |
| return getChar() == 1; | |
| } | |
| std::string MyStringBuffer::getString() { | |
| size_t len = getInt(); | |
| size_t tmpPos = pos; | |
| pos += len; | |
| return str.substr(tmpPos, len); | |
| } | |
| void MyStringBuffer::putInt(int ins) { | |
| putOrderedByte((char*)&ins, 4); | |
| } | |
| void MyStringBuffer::putDate(boost::gregorian::date date) { | |
| putInt(parseDateExpressionToInt(date)); | |
| } | |
| void MyStringBuffer::putInt64(int64_t ins) { | |
| putOrderedByte((char*)&ins, 8); | |
| } | |
| void MyStringBuffer::putFloat(float ins) { | |
| putOrderedByte((char*)&ins, 4); | |
| } | |
| void MyStringBuffer::putDouble(double ins) { | |
| putOrderedByte((char*)&ins, 8); | |
| } | |
| void MyStringBuffer::putChar(char ins) { | |
| str += ins; | |
| } | |
| void MyStringBuffer::putBool(bool ins) { | |
| char tmp = ins ? 1 : 0; | |
| str += tmp; | |
| } | |
| void MyStringBuffer::putString(const std::string& ins) { | |
| putInt((int)(ins.size())); | |
| str += ins; | |
| } | |
| void MyStringBuffer::concat(const std::string& ins) { | |
| str.append(ins); | |
| } | |
| void MyStringBuffer::checkBigEndian() { | |
| static int chk = 0x0201; //used to distinguish CPU's type (BigEndian or LittleEndian) | |
| isBigEndian = (0x01 != *(char*)(&chk)); | |
| } | |
| const char* MyStringBuffer::getOrderedByte(size_t len) { | |
| const char* p = nullptr; | |
| if (isBigEndian) { | |
| p = str.c_str() + pos; | |
| } | |
| else { | |
| const char* tmp = str.c_str(); | |
| for (size_t i = pos; i < pos + len; i++) { | |
| numericBuf[pos + len - 1 - i] = tmp[i]; | |
| } | |
| p = numericBuf; | |
| } | |
| pos += len; | |
| return p; | |
| } | |
| void MyStringBuffer::putOrderedByte(char* buf, int len) { | |
| if (isBigEndian) { | |
| str.assign(buf, len); | |
| } | |
| else { | |
| for (int i = len - 1; i > -1; i--) { | |
| str += buf[i]; | |
| } | |
| } | |
| } | |
| BitMap::BitMap(size_t size) { | |
| resize(size); | |
| } | |
| void BitMap::resize(size_t size) { | |
| this->size = size; | |
| this->bits.resize((size >> 3) + 1); // equal to "size/8 + 1" | |
| reset(); | |
| } | |
| bool BitMap::mark(size_t position) { | |
| if (position >= size) | |
| return false; | |
| bits[position >> 3] |= (char)1 << (position % 8); | |
| return true; | |
| } | |
| bool BitMap::unmark(size_t position) { | |
| if (position >= size) | |
| return false; | |
| bits[position >> 3] &= ~((char)1 << (position % 8)); | |
| return true; | |
| } | |
| void BitMap::markAll() { | |
| std::fill(bits.begin(), bits.end(), (char)0XFF); | |
| } | |
| void BitMap::reset() { | |
| std::fill(bits.begin(), bits.end(), (char)0); | |
| } | |
| bool BitMap::isMarked(size_t position) const { | |
| if (position >= size) | |
| return false; | |
| return (bits[position >> 3] & ((char)1 << (position % 8))) != 0; | |
| } | |
| bool BitMap::isAllUnmarked() const { | |
| size_t j; | |
| for (j = 0; j < size >> 3; j++) { | |
| if (bits[j] != (char)0) { | |
| return false; | |
| } | |
| } | |
| for (j = 0; j < size % 8; j++) { | |
| if ((bits[size >> 3] & ((char)1 << j)) != 0) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool BitMap::isAllMarked() const { | |
| size_t j; | |
| for (j = 0; j < size >> 3; j++) { | |
| if (bits[j] != (char)0XFF) { | |
| return false; | |
| } | |
| } | |
| for (j = 0; j < size % 8; j++) { | |
| if ((bits[size >> 3] & ((char)1 << j)) == 0) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| const std::vector<char>& BitMap::getByteArray() const { | |
| return this->bits; | |
| } | |
| size_t BitMap::getSize() const { | |
| return this->size; | |
| } | |
| const std::string UrlUtils::PORT_SEPARATOR = ":"; | |
| const std::string UrlUtils::ABB_COLON = "["; | |
| TEndPoint UrlUtils::parseTEndPointIpv4AndIpv6Url(const std::string& endPointUrl) { | |
| TEndPoint endPoint; | |
| // Return default TEndPoint if input is empty | |
| if (endPointUrl.empty()) { | |
| return endPoint; | |
| } | |
| size_t portSeparatorPos = endPointUrl.find_last_of(PORT_SEPARATOR); | |
| // If no port separator found, treat entire string as IP | |
| if (portSeparatorPos == std::string::npos) { | |
| endPoint.__set_ip(endPointUrl); | |
| return endPoint; | |
| } | |
| // Extract port part | |
| std::string portStr = endPointUrl.substr(portSeparatorPos + 1); | |
| // Extract IP part | |
| std::string ip = endPointUrl.substr(0, portSeparatorPos); | |
| // Handle IPv6 addresses with brackets | |
| if (ip.find(ABB_COLON) != std::string::npos) { | |
| // Remove surrounding square brackets for IPv6 | |
| if (ip.size() >= 2 && ip.front() == '[' && ip.back() == ']') { | |
| ip = ip.substr(1, ip.size() - 2); | |
| } | |
| } | |
| try { | |
| int port = std::stoi(portStr); | |
| endPoint.__set_ip(ip); | |
| endPoint.__set_port(port); | |
| } catch (const std::exception& e) { | |
| endPoint.__set_ip(endPointUrl); | |
| } | |
| return endPoint; | |
| } |