From fea5141a8e2dc9bc62889a7d814109877e68ac80 Mon Sep 17 00:00:00 2001 From: mochizk Date: Fri, 29 Mar 2019 11:27:34 +0900 Subject: [PATCH 1/6] Add utility function --- src/Util.cpp | 31 +++++++++++++++++++++++++++++++ src/Util.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/Util.cpp create mode 100644 src/Util.h diff --git a/src/Util.cpp b/src/Util.cpp new file mode 100644 index 0000000..8adacba --- /dev/null +++ b/src/Util.cpp @@ -0,0 +1,31 @@ +/* + Copyright (c) 2017 TOSHIBA Digital Solutions Corporation. + + Licensed 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 "Util.h" + +namespace griddb { + + /** + * @brief Allocate new memory and setup string data from source string data for the new memory + * @param **to A pointer variable that refers to new string data + * @param *from A pointer stores source string data + */ + void Util::strdup(const GSChar** const to, const GSChar* from) { + GSChar* temp = new char[strlen(from) + 1](); + strcpy(temp, from); + *to = temp; + } +} diff --git a/src/Util.h b/src/Util.h new file mode 100644 index 0000000..5217469 --- /dev/null +++ b/src/Util.h @@ -0,0 +1,34 @@ +/* + Copyright (c) 2017 TOSHIBA Digital Solutions Corporation. + + Licensed 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. +*/ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include +#include "GSException.h" + +using namespace std; + +namespace griddb { + +class Util { + public: + static void strdup(const GSChar** const to, const GSChar* from); +}; + +} + +#endif \ No newline at end of file From 4ffa90525d5c867f2aa3f58de86e254d6ba340e8 Mon Sep 17 00:00:00 2001 From: mochizk Date: Fri, 29 Mar 2019 11:28:04 +0900 Subject: [PATCH 2/6] Move Field class implementation from header file to cpp file --- src/Field.cpp | 106 ++++++++++++++++++++++++++++++++++++++++ src/Field.h | 133 +++----------------------------------------------- 2 files changed, 112 insertions(+), 127 deletions(-) create mode 100644 src/Field.cpp diff --git a/src/Field.cpp b/src/Field.cpp new file mode 100644 index 0000000..365e416 --- /dev/null +++ b/src/Field.cpp @@ -0,0 +1,106 @@ +/* + Copyright (c) 2017 TOSHIBA Digital Solutions Corporation. + + Licensed 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 "Field.h" + +namespace griddb { + + /** + * @brief Constructor a new Field:: Field object + */ + Field::Field() : type(GS_TYPE_STRING) { + memset(&value, 0, sizeof(GSValue)); + }; + + Field::~Field() { + switch (type) { + case GS_TYPE_STRING: + if (value.asString) { + delete [] value.asString; + value.asString = NULL; + } + break; + case GS_TYPE_BLOB: + if (value.asBlob.data) { + delete [] value.asBlob.data; + value.asBlob.data = NULL; + } + break; + case GS_TYPE_INTEGER_ARRAY: + if (value.asArray.elements.asInteger) { + delete [] value.asArray.elements.asInteger; + value.asArray.elements.asInteger = NULL; + } + break; + case GS_TYPE_STRING_ARRAY: + if (value.asArray.elements.asString) { + for (int j = 0; j < value.asArray.length; j++) { + if (value.asArray.elements.asString[j]) { + delete [] value.asArray.elements.asString[j]; + } + } + delete [] value.asArray.elements.asString; + value.asArray.elements.asString = NULL; + } + break; + case GS_TYPE_BOOL_ARRAY: + if (value.asArray.elements.asBool) { + delete [] value.asArray.elements.asBool; + value.asArray.elements.asBool = NULL; + } + break; + case GS_TYPE_BYTE_ARRAY: + if (value.asArray.elements.asByte) { + delete [] value.asArray.elements.asByte; + value.asArray.elements.asByte = NULL; + } + break; + case GS_TYPE_SHORT_ARRAY: + if (value.asArray.elements.asShort) { + delete [] value.asArray.elements.asShort; + value.asArray.elements.asShort = NULL; + } + break; + case GS_TYPE_LONG_ARRAY: + if (value.asArray.elements.asLong) { + delete [] value.asArray.elements.asLong; + value.asArray.elements.asLong = NULL; + } + break; + case GS_TYPE_FLOAT_ARRAY: + if (value.asArray.elements.asFloat) { + delete [] value.asArray.elements.asFloat; + value.asArray.elements.asFloat = NULL; + } + break; + case GS_TYPE_DOUBLE_ARRAY: + if (value.asArray.elements.asDouble) { + delete [] value.asArray.elements.asDouble; + value.asArray.elements.asDouble = NULL; + } + break; + case GS_TYPE_TIMESTAMP_ARRAY: + if (value.asArray.elements.asTimestamp) { + delete [] value.asArray.elements.asTimestamp; + value.asArray.elements.asTimestamp = NULL; + } + break; + default: + //not need to free allocation + break; + } + } +} diff --git a/src/Field.h b/src/Field.h index b921e0b..15e3f36 100644 --- a/src/Field.h +++ b/src/Field.h @@ -26,133 +26,12 @@ using namespace std; namespace griddb { -struct Field { - GSType type; - GSValue value; - Field() : type(GS_TYPE_STRING) { - memset(&value, 0, sizeof(GSValue)); - }; - - ~Field() { - switch (type) { - case GS_TYPE_STRING: - if (value.asString) { - free(const_cast(value.asString)); - } - break; - case GS_TYPE_BLOB: - if (value.asBlob.data) { - free(const_cast(value.asBlob.data)); - } - break; -#if GS_COMPATIBILITY_VALUE_1_1_106 - case GS_TYPE_INTEGER_ARRAY: - if (value.asIntegerArray.elements) { - free(const_cast (value.asIntegerArray.elements)); - } - break; - case GS_TYPE_STRING_ARRAY: - if (value.asStringArray.elements) { - for (int j = 0; j < value.asStringArray.size; j++) { - if (value.asStringArray.elements[j]) { - free(const_cast (value.asStringArray.elements[j])); - } - } - free(const_cast (value.asStringArray.elements)); - } - break; - case GS_TYPE_BOOL_ARRAY: - if (value.asBoolArray.elements) { - free(const_cast (value.asBoolArray.elements)); - } - break; - case GS_TYPE_BYTE_ARRAY: - if (value.asByteArray.elements) { - free(const_cast (value.asByteArray.elements)); - } - break; - case GS_TYPE_SHORT_ARRAY: - if (value.asShortArray.elements) { - free(const_cast (value.asShortArray.elements)); - } - break; - case GS_TYPE_LONG_ARRAY: - if (value.asLongArray.elements) { - free(const_cast (value.asLongArray.elements)); - } - break; - case GS_TYPE_FLOAT_ARRAY: - if (value.asFloatArray.elements) { - free(const_cast (value.asFloatArray.elements)); - } - break; - case GS_TYPE_DOUBLE_ARRAY: - if (value.asDoubleArray.elements) { - free(const_cast (value.asDoubleArray.elements)); - } - break; - case GS_TYPE_TIMESTAMP_ARRAY: - if (value.asTimestampArray.elements) { - free(const_cast (value.asTimestampArray.elements)); - } - break; -#else - case GS_TYPE_INTEGER_ARRAY: - if (value.asArray.elements.asInteger) { - free(const_cast (value.asArray.elements.asInteger)); - } - break; - case GS_TYPE_STRING_ARRAY: - if (value.asArray.elements.asString) { - for (int j = 0; j < value.asArray.length; j++) { - if (value.asArray.elements.asString[j]) { - free(const_cast (value.asArray.elements.asString[j])); - } - } - free(const_cast (value.asArray.elements.asString)); - } - break; - case GS_TYPE_BOOL_ARRAY: - if (value.asArray.elements.asBool) { - free(const_cast (value.asArray.elements.asBool)); - } - break; - case GS_TYPE_BYTE_ARRAY: - if (value.asArray.elements.asByte) { - free(const_cast (value.asArray.elements.asByte)); - } - break; - case GS_TYPE_SHORT_ARRAY: - if (value.asArray.elements.asShort) { - free(const_cast (value.asArray.elements.asShort)); - } - break; - case GS_TYPE_LONG_ARRAY: - if (value.asArray.elements.asLong) { - free(const_cast (value.asArray.elements.asLong)); - } - break; - case GS_TYPE_FLOAT_ARRAY: - if (value.asArray.elements.asFloat) { - free(const_cast (value.asArray.elements.asFloat)); - } - break; - case GS_TYPE_DOUBLE_ARRAY: - if (value.asArray.elements.asDouble) { - free(const_cast (value.asArray.elements.asDouble)); - } - break; - case GS_TYPE_TIMESTAMP_ARRAY: - if (value.asArray.elements.asTimestamp) { - free(const_cast (value.asArray.elements.asTimestamp)); - } - break; -#endif - default: - //not need to free allocation - break; - } - } +class Field { + public: + GSType type; + GSValue value; + Field(); + ~Field(); }; } From af26e3b76921dc8db88654b56d3f6b0d732fbfb9 Mon Sep 17 00:00:00 2001 From: mochizk Date: Fri, 29 Mar 2019 11:31:41 +0900 Subject: [PATCH 3/6] Store error info of C client in exception constructor --- src/GSException.h | 173 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 52 deletions(-) diff --git a/src/GSException.h b/src/GSException.h index f388ccc..e06d457 100644 --- a/src/GSException.h +++ b/src/GSException.h @@ -25,6 +25,7 @@ using namespace std; #define DEFAULT_ERROR_CODE -1 +#define DEFAULT_ERROR_STACK_SIZE 1 namespace griddb { @@ -38,65 +39,54 @@ class GSException : public exception { string mMessage; void *mResource; + bool hasInnerError; + size_t mInnerErrStackSize; + GSResult* mInnerErrCodeStack; + string* mInnerMessagesStack; + string* mInnerErrorLocationStack; + public: - GSException(int32_t code) : exception(), mCode(code), mResource(NULL) { - mMessage = "Error with number " + to_string((long long int)mCode); - if (mCode != DEFAULT_ERROR_CODE) { - //Case exception with error code. - mIsTimeout = gsIsTimeoutError(mCode); - } - else { - mIsTimeout = false; - } - } GSException(const char* message) : exception(), mCode(DEFAULT_ERROR_CODE), mMessage(message), mResource(NULL) { - if (mCode != DEFAULT_ERROR_CODE) { - //Case exception with error code. - mIsTimeout = gsIsTimeoutError(mCode); - } - else { - mIsTimeout = false; - } + hasInnerError = false; + mInnerErrStackSize = 0; + mInnerErrCodeStack = NULL; + mInnerMessagesStack = NULL; + mInnerErrorLocationStack = NULL; + mIsTimeout = false; } GSException(void *resource, const char* message) : exception(), mCode(DEFAULT_ERROR_CODE), mMessage(message), mResource(resource) { - if (mCode != DEFAULT_ERROR_CODE) { - //Case exception with error code. - mIsTimeout = gsIsTimeoutError(mCode); - } - else { - mIsTimeout = false; - } + hasInnerError = false; + mInnerErrStackSize = 0; + mInnerErrCodeStack = NULL; + mInnerMessagesStack = NULL; + mInnerErrorLocationStack = NULL; + mIsTimeout = false; } GSException(void *resource, int32_t code) : exception(), mCode(code), mResource(resource) { mMessage = "Error with number " + to_string((long long int)mCode); - if (mCode != DEFAULT_ERROR_CODE) { - //Case exception with error code. - mIsTimeout = gsIsTimeoutError(mCode); - } - else { - mIsTimeout = false; - } - } - GSException(int32_t code, const char* message) : exception(), - mCode(code), mMessage(message), mResource(NULL) { - if (mCode != DEFAULT_ERROR_CODE) { - //Case exception with error code. + if (mCode != DEFAULT_ERROR_CODE && mResource != NULL) { + //Case exception with error code from c layer mIsTimeout = gsIsTimeoutError(mCode); - } - else { - mIsTimeout = false; - } - } - GSException(void *resource, int32_t code, const char* message) : exception(), - mCode(code), mMessage(message), mResource(resource) { - if (mCode != DEFAULT_ERROR_CODE) { - //Case exception with error code. - mIsTimeout = gsIsTimeoutError(mCode); - } - else { + // Store error stack + hasInnerError = true; + mInnerErrStackSize = get_error_stack_size_from_lower_layer(); + mInnerErrCodeStack = new GSResult[mInnerErrStackSize](); + mInnerMessagesStack = new string[mInnerErrStackSize](); + mInnerErrorLocationStack = new string[mInnerErrStackSize](); + for (int i = 0; i < mInnerErrStackSize; i++) { + mInnerErrCodeStack[i] = get_error_code_from_lower_layer(i); + mInnerMessagesStack[i] = get_message_from_lower_layer(i); + mInnerErrorLocationStack[i] = get_location_from_lower_layer(i); + } + } else { + hasInnerError = false; + mInnerErrStackSize = 0; + mInnerErrCodeStack = NULL; + mInnerMessagesStack = NULL; + mInnerErrorLocationStack = NULL; mIsTimeout = false; } } @@ -105,8 +95,42 @@ class GSException : public exception { mIsTimeout = exception->mIsTimeout; mMessage = exception->mMessage; mResource = exception->mResource; + hasInnerError = exception->hasInnerError; + if (hasInnerError == true) { + mInnerErrStackSize = exception->mInnerErrStackSize; + mInnerErrCodeStack = new GSResult[mInnerErrStackSize](); + mInnerMessagesStack = new string[mInnerErrStackSize](); + mInnerErrorLocationStack = new string[mInnerErrStackSize](); + for (int i = 0; i < mInnerErrStackSize; i++) { + mInnerErrCodeStack[i] = exception->mInnerErrCodeStack[i]; + mInnerMessagesStack[i] = exception->mInnerMessagesStack[i]; + mInnerErrorLocationStack[i] = exception->mInnerErrorLocationStack[i]; + } + } else { + mInnerErrStackSize = 0; + mInnerErrCodeStack = NULL; + mInnerMessagesStack = NULL; + mInnerErrorLocationStack = NULL; + } + } + ~GSException() throw() { + close(); + } + + void close() { + if (mInnerErrCodeStack != NULL) { + delete[] mInnerErrCodeStack; + mInnerErrCodeStack = NULL; + } + if (mInnerMessagesStack != NULL) { + delete[] mInnerMessagesStack; + mInnerMessagesStack = NULL; + } + if (mInnerErrorLocationStack != NULL) { + delete[] mInnerErrorLocationStack; + mInnerErrorLocationStack = NULL; + } } - ~GSException() throw() {} int32_t get_code() { return mCode; } @@ -123,18 +147,63 @@ class GSException : public exception { * Get error stack size. Convert from C-API: gsGetErrorStackSize. */ size_t get_error_stack_size() { - return gsGetErrorStackSize(mResource); + if (hasInnerError == false) { + return DEFAULT_ERROR_STACK_SIZE; + } + return mInnerErrStackSize; } /** * Get error code. Convert from C-API: gsGetErrorCode. */ GSResult get_error_code(size_t stack_index) { - return gsGetErrorCode(mResource, stack_index); + if (hasInnerError == false) { + if (stack_index == 0) return mCode; + return 0; + } else { + if (stack_index >= mInnerErrStackSize) return 0; + return mInnerErrCodeStack[stack_index]; + } } /** * Get error message. Convert from C-API: gsFormatErrorMessage. */ string get_message(size_t stack_index, size_t buf_size = 1024) { + if (hasInnerError == false) { + if (stack_index == 0) return mMessage; + return ""; + } else { + if (stack_index >= mInnerErrStackSize) return ""; + return mInnerMessagesStack[stack_index]; + } + } + /** + * Get error location. Convert from C-API: gsFormatErrorLocation. + */ + string get_location(size_t stack_index, size_t buf_size = 1024) { + if (hasInnerError == false) { + return ""; + } else { + if (stack_index >= mInnerErrStackSize) return ""; + return mInnerErrorLocationStack[stack_index]; + } + } + private: + /** + * Get error stack size. Convert from C-API: gsGetErrorStackSize. + */ + size_t get_error_stack_size_from_lower_layer() { + return gsGetErrorStackSize(mResource); + } + /** + * Get error code. Convert from C-API: gsGetErrorCode. + */ + GSResult get_error_code_from_lower_layer(size_t stack_index) { + return gsGetErrorCode(mResource, stack_index); + } + /** + * Get error message. Convert from C-API: gsFormatErrorMessage. + */ + string get_message_from_lower_layer(size_t stack_index, size_t buf_size = 1024) { char* strBuf = new char[buf_size]; size_t stringSize = gsFormatErrorMessage(mResource, stack_index, strBuf, buf_size); string ret(strBuf, stringSize); @@ -144,7 +213,7 @@ class GSException : public exception { /** * Get error location. Convert from C-API: gsFormatErrorLocation. */ - string get_location(size_t stack_index, size_t buf_size = 1024) { + string get_location_from_lower_layer(size_t stack_index, size_t buf_size = 1024) { char* strBuf = new char[buf_size]; size_t stringSize = gsFormatErrorLocation(mResource, stack_index, strBuf, buf_size); string ret(strBuf, stringSize); From 7a0cb00069c137bd953ee68ed2ab2fca21779d83 Mon Sep 17 00:00:00 2001 From: mochizk Date: Fri, 29 Mar 2019 11:34:08 +0900 Subject: [PATCH 4/6] Refactor and fix bugs of cpp files --- src/AggregationResult.cpp | 12 +- src/AggregationResult.h | 3 +- src/Container.cpp | 227 +++++++++++++++++++----------- src/Container.h | 6 +- src/ContainerInfo.cpp | 265 ++++++++++++++++++++++++----------- src/ContainerInfo.h | 3 + src/EnumValue.h | 8 +- src/PartitionController.cpp | 40 ++++-- src/PartitionController.h | 2 +- src/Query.cpp | 78 +++++++---- src/Query.h | 2 + src/QueryAnalysisEntry.cpp | 128 +++++++++++------ src/QueryAnalysisEntry.h | 2 + src/RowKeyPredicate.cpp | 149 ++++++++++++++------ src/RowKeyPredicate.h | 2 + src/RowSet.cpp | 130 ++++++++++++----- src/RowSet.h | 2 + src/Store.cpp | 184 ++++++++++++++++++------ src/Store.h | 1 + src/StoreFactory.cpp | 85 +++++++---- src/StoreFactory.h | 2 +- src/TimeSeriesProperties.cpp | 51 +++++-- 22 files changed, 964 insertions(+), 418 deletions(-) diff --git a/src/AggregationResult.cpp b/src/AggregationResult.cpp index d34c1c6..ad8b2c0 100644 --- a/src/AggregationResult.cpp +++ b/src/AggregationResult.cpp @@ -18,6 +18,10 @@ namespace griddb { + /** + * @brief Constructor a new Aggregation Result:: Aggregation Result object + * @param aggResult Stores the result of an aggregation operation + */ AggregationResult::AggregationResult(GSAggregationResult* aggResult) : mAggResult(aggResult), timestamp_output_with_float(false) { } @@ -27,7 +31,7 @@ namespace griddb { } /** - * Release AggregationResult resource + * @brief Release AggregationResult resource */ void AggregationResult::close() { if (mAggResult != NULL) { @@ -37,9 +41,12 @@ namespace griddb { } /** - * Obtains the result of aggregating numeric-type values. + * @brief Obtains the result of aggregating numeric-type values. + * @param type Column type + * @param *agValue aggregation result */ void AggregationResult::get(GSType type, griddb::Field *agValue) { + assert(agValue != NULL); void *value; agValue->type = type; switch (type) { @@ -62,4 +69,5 @@ namespace griddb { "Value cannot be retrieved from Aggregation result"); } } + } /* namespace griddb */ diff --git a/src/AggregationResult.h b/src/AggregationResult.h index c0bcaec..3db594f 100644 --- a/src/AggregationResult.h +++ b/src/AggregationResult.h @@ -17,6 +17,8 @@ #ifndef _AGGREGATIONRESULT_H_ #define _AGGREGATIONRESULT_H_ +#include + #include "GSException.h" #include "Field.h" #include "gridstore.h" @@ -35,7 +37,6 @@ class AggregationResult { bool timestamp_output_with_float; ~AggregationResult(); void close(); - void get(GSType type, griddb::Field *agValue); AggregationResult(GSAggregationResult* aggResult); diff --git a/src/Container.cpp b/src/Container.cpp index 864f86f..8bdc1c0 100644 --- a/src/Container.cpp +++ b/src/Container.cpp @@ -1,4 +1,4 @@ -/* + /* Copyright (c) 2017 TOSHIBA Digital Solutions Corporation. Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,155 +16,192 @@ #include "Container.h" +#include + namespace griddb { Container::Container(GSContainer *container, GSContainerInfo* containerInfo) : mContainer(container), mContainerInfo(NULL), mRow(NULL), mTypeList(NULL), timestamp_output_with_float(false) { + assert(container != NULL); + assert(containerInfo != NULL); GSResult ret = gsCreateRowByContainer(mContainer, &mRow); - if (ret != GS_RESULT_OK) { - throw GSException(ret, "can not create row from Container"); + if (!GS_SUCCEEDED(ret)) { + throw GSException(mContainer, ret); } + GSColumnInfo* columnInfoList; //create local mContainerInfo: there is issue from C-API about using share memory that // make GSContainerInfo* pointer error in case : create gsRow, get GSContainerInfo from gsRow, set field of gs Row - mContainerInfo = (GSContainerInfo*) malloc(sizeof(GSContainerInfo)); - (*mContainerInfo) = (*containerInfo); // this is for set for normal data (int, float, double..) - GSColumnInfo* columnInfoList = (GSColumnInfo *) malloc(sizeof (GSColumnInfo) * containerInfo->columnCount); - for (int i = 0; i < containerInfo->columnCount; i++) { - columnInfoList[i].type = containerInfo->columnInfoList[i].type; - if (containerInfo->columnInfoList[i].name) { - columnInfoList[i].name = strdup(containerInfo->columnInfoList[i].name); - } else { - columnInfoList[i].name = NULL; + try { + mContainerInfo = new GSContainerInfo(); + (*mContainerInfo) = (*containerInfo); // this is for set for normal data (int, float, double..) + mContainerInfo->name = NULL; + if (containerInfo->name) { + Util::strdup(&(mContainerInfo->name), containerInfo->name); } -#if GS_COMPATIBILITY_SUPPORT_1_5 - columnInfoList[i].indexTypeFlags = containerInfo->columnInfoList[i].indexTypeFlags; -#if GS_COMPATIBILITY_SUPPORT_3_5 - columnInfoList[i].options = containerInfo->columnInfoList[i].options; -#endif -#endif - } - mContainerInfo->name = NULL; - if (containerInfo->name) { - mContainerInfo->name = strdup(containerInfo->name); + + columnInfoList = new GSColumnInfo[containerInfo->columnCount](); + mContainerInfo->columnInfoList = columnInfoList; + + for (int i = 0; i < containerInfo->columnCount; i++) { + columnInfoList[i].type = containerInfo->columnInfoList[i].type; + if (containerInfo->columnInfoList[i].name) { + Util::strdup(&(columnInfoList[i].name), containerInfo->columnInfoList[i].name); + } else { + columnInfoList[i].name = NULL; + } + + columnInfoList[i].indexTypeFlags = containerInfo->columnInfoList[i].indexTypeFlags; + columnInfoList[i].options = containerInfo->columnInfoList[i].options; + } + + mTypeList = new GSType[mContainerInfo->columnCount](); + } catch (bad_alloc& ba) { + //Memory allocation error + freeMemoryContainer(); + throw GSException(mContainer, "Memory allocation error"); } - mContainerInfo->columnInfoList = columnInfoList; + mContainerInfo->timeSeriesProperties = NULL; mContainerInfo->triggerInfoList = NULL; mContainerInfo->dataAffinity = NULL; - mTypeList = (GSType*) malloc(sizeof(GSType) * mContainerInfo->columnCount); - for (int i = 0; i < mContainerInfo->columnCount; i++){ - mTypeList[i] = mContainerInfo->columnInfoList[i].type; + + if (mTypeList && mContainerInfo->columnInfoList) { + for (int i = 0; i < mContainerInfo->columnCount; i++){ + mTypeList[i] = mContainerInfo->columnInfoList[i].type; + } } } Container::~Container() { - gsCloseRow(&mRow); + // allRelated = FALSE, since all row object is managed by Row class close(GS_FALSE); + } + void Container::freeMemoryContainer() { if (mContainerInfo) { for (int i = 0; i < mContainerInfo->columnCount; i++) { - free((void*)mContainerInfo->columnInfoList[i].name); + if (mContainerInfo->columnInfoList && mContainerInfo->columnInfoList[i].name) { + delete[] mContainerInfo->columnInfoList[i].name; + } } - free((void*) mContainerInfo->columnInfoList); - free((void*) mContainerInfo->name); - free((void*) mContainerInfo); + if (mContainerInfo->columnInfoList) { + delete[] mContainerInfo->columnInfoList; + } + if (mContainerInfo->name) { + delete[] mContainerInfo->name; + } + delete mContainerInfo; + mContainerInfo = NULL; + } + if (mTypeList) { + delete[] mTypeList; + mTypeList = NULL; } - free((void*) mTypeList); } /** - * Close container. + * @brief Release Container resource + * @param allRelated Indicates whether all unclosed resources in the lower resources related to the specified GSContainer will be closed or not */ void Container::close(GSBool allRelated) { + if (mRow != NULL) { + gsCloseRow(&mRow); + mRow = NULL; + } + //Release container and all related resources if (mContainer != NULL) { gsCloseContainer(&mContainer, allRelated); mContainer = NULL; } + freeMemoryContainer(); } /** - * Removes the specified type of index among indexes on the specified Column. + * @brief Removes the specified type of index among indexes on the specified Column + * @param *column_name Column name + * @param index_type Flag value which shows index classification + * @param *name Index name */ void Container::drop_index(const char* column_name, GSIndexTypeFlags index_type, const char *name) { GSResult ret = GS_RESULT_OK; -#if GS_COMPATIBILITY_SUPPORT_3_5 + if (name) { GSIndexInfo indexInfo = GS_INDEX_INFO_INITIALIZER; indexInfo.name = name; indexInfo.type = index_type; indexInfo.columnName = column_name; ret = gsDropIndexDetail(mContainer, &indexInfo); - } - else { + } else { ret = gsDropIndex(mContainer, column_name, index_type); } -#else - ret = gsDropIndex(mContainer, column_name, index_type); -#endif - if (ret != GS_RESULT_OK) { + + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } } - /* - * Creates a specified type of index on the specified Column. + /** + * @brief Creates a specified type of index on the specified Column + * @param *column_name Column name + * @param index_type Flag value which shows index classification + * @param *name Index name */ void Container::create_index(const char *column_name, GSIndexTypeFlags index_type, const char *name) { GSResult ret = GS_RESULT_OK; -#if GS_COMPATIBILITY_SUPPORT_3_5 + if (name){ GSIndexInfo indexInfo = GS_INDEX_INFO_INITIALIZER; indexInfo.name = name; indexInfo.type = index_type; indexInfo.columnName = column_name; ret = gsCreateIndexDetail(mContainer, &indexInfo); - } - else { + } else { ret = gsCreateIndex(mContainer, column_name, index_type); } -#else - ret = gsCreateIndex(mContainer, column_name, index_type); -#endif - if (ret != GS_RESULT_OK) { + + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } } /** - * Writes the results of earlier updates to a non-volatile storage medium, such as SSD, so as to prevent the data from being lost even if all cluster nodes stop suddenly. + * @brief Writes the results of earlier updates to a non-volatile storage medium, such as SSD, so as to prevent the data from being lost even if all cluster nodes stop suddenly. */ void Container::flush() { GSResult ret = gsFlush(mContainer); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } } /** - * Put row to database. + * @brief Put row to database. + * @param *row A Row object representing the content of a Row to be put to database + * @return Return bool value to indicate row exist or not */ - bool Container::put(GSRow *rowContainer) { + bool Container::put(GSRow *row) { GSBool bExists; GSResult ret = gsPutRow(mContainer, NULL, mRow, &bExists); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } return bExists; } /** - * Get current container type + * @brief Get current container type + * @return Return container type */ GSContainerType Container::get_type() { GSContainerType containerType; GSResult ret = gsGetContainerType(mContainer, &containerType); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } @@ -172,56 +209,69 @@ namespace griddb { } /** - * Rolls back the result of the current transaction and starts a new transaction in the manual commit mode. + * @brief Rolls back the result of the current transaction and starts a new transaction in the manual commit mode. */ void Container::abort() { GSResult ret = gsAbort(mContainer); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } } /** - * Create query from input string. + * @brief Create query from input string. + * @param *query TQL statement + * @return Return a Query object */ Query* Container::query(const char* query) { GSQuery *pQuery; GSResult ret = gsQuery(mContainer, query, &pQuery); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } - return new Query(pQuery, mContainerInfo, mRow); + try { + Query* queryObj = new Query(pQuery, mContainerInfo, mRow); + return queryObj; + } catch(bad_alloc& ba) { + gsCloseQuery(&pQuery); + throw GSException(mContainer, "Memory allocation error"); + } } /** - * Set auto commit to true or false. + * @brief Set auto commit to true or false. + * @param enabled Indicates whether container enables auto commit mode or not */ void Container::set_auto_commit(bool enabled){ GSBool gsEnabled; gsEnabled = (enabled == true ? GS_TRUE:GS_FALSE); GSResult ret = gsSetAutoCommit(mContainer, gsEnabled); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } } /** - * Commit changes to database when autocommit is set to false. + * @brief Commit changes to database when autocommit is set to false. */ void Container::commit() { GSResult ret = gsCommit(mContainer); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } } /** - * Returns the content of a Row. + * @brief Returns the content of a Row. + * @param *keyFields The variable to store the target Row key + * @param *rowdata The Row object to store the contents of target Row to be obtained + * @return Return bool value to indicate row exist or not */ GSBool Container::get(Field* keyFields, GSRow *rowdata) { + assert(keyFields != NULL); GSBool exists; GSResult ret; void *key = NULL; @@ -234,7 +284,7 @@ namespace griddb { break; case GS_TYPE_INTEGER: if (mContainerInfo->columnInfoList[0].type != GS_TYPE_INTEGER) { - throw GSException("wrong type of rowKey"); + throw GSException("wrong type of rowKey integer"); } key = &keyFields->value.asInteger; break; @@ -246,7 +296,7 @@ namespace griddb { break; case GS_TYPE_TIMESTAMP: if (mContainerInfo->columnInfoList[0].type != GS_TYPE_TIMESTAMP) { - throw GSException("wrong type of rowKey"); + throw GSException("wrong type of rowKey timestamp"); } key = &keyFields->value.asTimestamp; break; @@ -255,24 +305,26 @@ namespace griddb { } ret = gsGetRow(mContainer, key, mRow, &exists); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } return exists; } - /* - * Deletes a Row corresponding to Row key + /** + * @brief Deletes a Row corresponding to Row key + * @param *keyFields The variable to store the target Row key + * @return Return bool value to indicate row exist or not */ bool Container::remove(Field* keyFields) { + assert(keyFields != NULL); GSBool exists = GS_FALSE; GSResult ret; -#if GS_COMPATIBILITY_SUPPORT_3_5 + if (keyFields->type == GS_TYPE_NULL) { ret = gsDeleteRow(mContainer, NULL, &exists); } else { -#endif switch (keyFields->type) { case GS_TYPE_STRING: if (mContainerInfo->columnInfoList[0].type != GS_TYPE_STRING) { @@ -282,7 +334,7 @@ namespace griddb { break; case GS_TYPE_INTEGER: if (mContainerInfo->columnInfoList[0].type != GS_TYPE_INTEGER) { - throw GSException("wrong type of rowKey"); + throw GSException("wrong type of rowKey integer"); } ret = gsDeleteRow(mContainer, &keyFields->value.asInteger, &exists); break; @@ -294,18 +346,16 @@ namespace griddb { break; case GS_TYPE_TIMESTAMP: if (mContainerInfo->columnInfoList[0].type != GS_TYPE_TIMESTAMP) { - throw GSException("wrong type of rowKey"); + throw GSException("wrong type of rowKey timestamp"); } ret = gsDeleteRow(mContainer, &keyFields->value.asTimestamp, &exists); break; default: throw GSException("wrong type of rowKey field"); } -#if GS_COMPATIBILITY_SUPPORT_3_5 } -#endif - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } @@ -313,7 +363,9 @@ namespace griddb { } /** - * Multiput data + * @brief Put multi row data to database + * @param **listRowdata The array of row to be put to data base + * @param rowCount The number of row to be put to database */ void Container::multi_put(GSRow** listRowdata, int rowCount) { GSResult ret; @@ -321,31 +373,38 @@ namespace griddb { //data for each container ret = gsPutMultipleRows(mContainer, (const void * const *) listRowdata, rowCount, &bExists); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mContainer, ret); } } /** - * Support Store::multi_put + * @brief Get GSContainer of Container object to support Store::multi_put + * @return Return a pointer which store GSContainer of container */ GSContainer* Container::getGSContainerPtr(){ return mContainer; } /** - * Support put row + * @brief Get GSType of Container object to support put row + * @return Return a pointer which store type the list of column of row in container */ GSType* Container::getGSTypeList(){ return mTypeList; } + /** + * @brief Get GSRow of Container object to support put row + * @return Return a pointer which store GSRow of container + */ GSRow* Container::getGSRowPtr(){ return mRow; } /** - * Support put row + * @brief Get number of column of row in container + * @return Return number of column of row in container */ int Container::getColumnCount(){ return mContainerInfo->columnCount; diff --git a/src/Container.h b/src/Container.h index 783fab0..74f7f47 100644 --- a/src/Container.h +++ b/src/Container.h @@ -17,9 +17,12 @@ #ifndef _CONTAINER_H_ #define _CONTAINER_H_ +#include + #include "Field.h" #include "Query.h" #include "GSException.h" +#include "Util.h" using namespace std; @@ -42,7 +45,7 @@ class Container { GSContainerType get_type(); void create_index(const char* column_name, GSIndexTypeFlags index_type = GS_INDEX_FLAG_DEFAULT, const char* name=NULL); void drop_index(const char* column_name, GSIndexTypeFlags index_type = GS_INDEX_FLAG_DEFAULT, const char* name=NULL); - bool put(GSRow *rowContainer); + bool put(GSRow *row); Query* query(const char *query); void abort(); void flush(); @@ -58,6 +61,7 @@ class Container { private: Container(GSContainer *container, GSContainerInfo* containerInfo); + void freeMemoryContainer(); }; } /* namespace griddb */ diff --git a/src/ContainerInfo.cpp b/src/ContainerInfo.cpp index cb1fcb0..7fd2ba4 100644 --- a/src/ContainerInfo.cpp +++ b/src/ContainerInfo.cpp @@ -18,36 +18,73 @@ namespace griddb { + /** + * @brief Constructor a new ContainerInfo::ContainerInfo object + * @param *containerInfo Stores the information about a specific Container + */ ContainerInfo::ContainerInfo(GSContainerInfo *containerInfo) { + assert(containerInfo != NULL); init(containerInfo->name, containerInfo->type, containerInfo->columnInfoList, containerInfo->columnCount, containerInfo->rowKeyAssigned, NULL); //Assign values from argument to mContainer GSTimeSeriesProperties* gsProps = NULL; + GSTriggerInfo* triggerInfoList = NULL; + + try { + if (containerInfo->timeSeriesProperties) { + gsProps = new GSTimeSeriesProperties(); + } + + if (containerInfo->triggerInfoList) { + triggerInfoList = new GSTriggerInfo(); + } + + if (containerInfo->dataAffinity) { + Util::strdup(&mContainerInfo.dataAffinity, containerInfo->dataAffinity); + } else { + mContainerInfo.dataAffinity = NULL; + } + } catch (bad_alloc& ba) { + //case allocation memory error + if (gsProps) { + delete gsProps; + } + if (triggerInfoList) { + delete triggerInfoList; + } + if (mContainerInfo.dataAffinity) { + delete[] mContainerInfo.dataAffinity; + } + throw GSException("Memory allocation error"); + } + if (containerInfo->timeSeriesProperties) { - gsProps = (GSTimeSeriesProperties*) malloc(sizeof(GSTimeSeriesProperties)); memcpy(gsProps, containerInfo->timeSeriesProperties, sizeof(GSTimeSeriesProperties)); } mContainerInfo.timeSeriesProperties = gsProps; - GSTriggerInfo* triggerInfoList = NULL; + if (containerInfo->triggerInfoList) { - triggerInfoList = (GSTriggerInfo*) malloc(sizeof(GSTriggerInfo)); memcpy(triggerInfoList, containerInfo->triggerInfoList, sizeof(GSTriggerInfo)); } + mContainerInfo.triggerInfoList = triggerInfoList; -#if GS_COMPATIBILITY_SUPPORT_2_1 - if (containerInfo->dataAffinity) { - mContainerInfo.dataAffinity = strdup(containerInfo->dataAffinity); - } else { - mContainerInfo.dataAffinity = NULL; - } -#endif + mContainerInfo.columnOrderIgnorable = containerInfo->columnOrderIgnorable; mContainerInfo.triggerInfoCount = containerInfo->triggerInfoCount; mColumnInfoList.columnInfo = NULL; mColumnInfoList.size = 0; } + /** + * @brief Constructor a new ContainerInfo::ContainerInfo object + * @param *name The name of Container + * @param *props Stores the information about the schema of a Column + * @param propsCount Number of columns + * @param type The type of Container + * @param row_key The boolean value indicating whether the Row key Column is assigned + * @param *expiration Stores the information about option of TimeSeries configuration + */ ContainerInfo::ContainerInfo(const GSChar* name, const GSColumnInfo* props, int propsCount, GSContainerType type, bool row_key, ExpirationInfo* expiration) { init(name, type, props, propsCount, row_key, expiration); @@ -63,30 +100,51 @@ namespace griddb { GSChar* containerName = NULL; GSTimeSeriesProperties* timeProps = NULL; - if (propsCount > 0 && props != NULL) { - columnInfoList = (GSColumnInfo *) malloc(propsCount*sizeof(GSColumnInfo)); - //Copy memory of GSColumnInfo list - memcpy(columnInfoList, props, propsCount*sizeof(GSColumnInfo)); - //Copy memory of columns name - for (int i = 0; i < propsCount; i++) { - if (props[i].name != NULL) { - columnInfoList[i].name = strdup(props[i].name); - } else { - columnInfoList[i].name = NULL; + try { + if (propsCount > 0 && props != NULL) { + columnInfoList = new GSColumnInfo[propsCount](); + //Copy memory of GSColumnInfo list + memcpy(columnInfoList, props, propsCount*sizeof(GSColumnInfo)); + //Copy memory of columns name + for (int i = 0; i < propsCount; i++) { + if (props[i].name != NULL) { + Util::strdup(&(columnInfoList[i].name), props[i].name); + } else { + columnInfoList[i].name = NULL; + } } } + + if (expiration != NULL) { + timeProps = new GSTimeSeriesProperties(); + } + + //Container name memory is copied via strdup function + if (name != NULL) { + Util::strdup((const GSChar**)&containerName, name); + } + } catch (bad_alloc& ba) { + if (columnInfoList) { + for (int i = 0; i < propsCount; i++) { + if (columnInfoList[i].name) { + delete[] columnInfoList[i].name; + } + } + delete[] columnInfoList; + } + if (containerName) { + delete[] containerName; + } + if (timeProps) { + delete timeProps; + } + throw GSException("Memory allocation error"); } if (expiration != NULL) { - timeProps = (GSTimeSeriesProperties*) malloc(sizeof(GSTimeSeriesProperties)); memcpy(timeProps, expiration->gs_ts(), sizeof(GSTimeSeriesProperties)); } - //Container name memory is copied via strdup function - if (name != NULL) { - containerName = strdup(name); - } - mContainerInfo = {containerName, type, (size_t)propsCount, columnInfoList, rowKeyAssigned}; if (timeProps != NULL) { mContainerInfo.timeSeriesProperties = timeProps; @@ -99,7 +157,7 @@ namespace griddb { ContainerInfo::~ContainerInfo() { //Free memory for the copy of container name if (mContainerInfo.name) { - free((void*) mContainerInfo.name); + delete[] mContainerInfo.name; } //Free memory for the copy of ColumnInfo list @@ -107,122 +165,160 @@ namespace griddb { //Free memory of columns name for(int i = 0; i < mContainerInfo.columnCount; i++) { if(mContainerInfo.columnInfoList[i].name) { - free((void *) mContainerInfo.columnInfoList[i].name); + delete[] mContainerInfo.columnInfoList[i].name; } } - free((void *) mContainerInfo.columnInfoList); + delete[] mContainerInfo.columnInfoList; } //Free memory of TimeSeriesProperties if existed if (mContainerInfo.timeSeriesProperties) { - free((void *) mContainerInfo.timeSeriesProperties); + delete mContainerInfo.timeSeriesProperties; } //Free memory of dataAffinity if existed -#if GS_COMPATIBILITY_SUPPORT_2_1 if (mContainerInfo.dataAffinity) { - free((void *) mContainerInfo.dataAffinity); + delete[] mContainerInfo.dataAffinity; } -#endif + //Free memory of triggerInfoList if existed if(mContainerInfo.triggerInfoList) { - free((void *) mContainerInfo.triggerInfoList); + delete mContainerInfo.triggerInfoList; } if (mExpInfo != NULL) { delete mExpInfo; } } - /* - * Set attribute: mContainerInfo.name + + /** + * @brief Set name of Container which is stored in ContainerInfo + * @param *containerName Stores the name of Container */ void ContainerInfo::set_name(GSChar* containerName) { if (mContainerInfo.name) { - free((void*) mContainerInfo.name); + delete[] mContainerInfo.name; } if (containerName == NULL) { mContainerInfo.name = NULL; } else { - mContainerInfo.name = strdup(containerName); + try { + Util::strdup(&(mContainerInfo.name), containerName); + } catch (bad_alloc& ba) { + throw GSException("Memory allocation error"); + } } } - /* - * Set attribute: mContainerInfo.type + + /** + * @brief Set type of Container which is stored in ContainerInfo + * @param containerType The type of Container */ void ContainerInfo::set_type(GSContainerType containerType) { mContainerInfo.type = containerType; } - /* - * Set attribute: mContainerInfo.rowKeyAssigned + + /** + * @brief Set rowKeyAssigned for ContainerInfo + * @param rowKeyAssigned The boolean value indicating whether the Row key Column is assigned */ void ContainerInfo::set_row_key_assigned(bool rowKeyAssigned) { mContainerInfo.rowKeyAssigned = rowKeyAssigned; } - /* - * Get attribute: mContainerInfo.name + + /** + * @brief Get name of Container which is stored in ContainerInfo + * @return The name of Container */ const GSChar* ContainerInfo::get_name() { return mContainerInfo.name; } - /* - * Get attribute: mContainerInfo.type + + /** + * @brief Get type of Container which is stored in ContainerInfo + * @return The type of Container */ GSContainerType ContainerInfo::get_type() { return mContainerInfo.type; } - /* - * Get attribute: mContainerInfo.columnInfoList + + /** + * @brief Get columnInfo which is stored in ContainerInfo + * @param column The number of column + * @return The information of column which is stored in ContainerInfo */ GSColumnInfo ContainerInfo::get_column_info(size_t column) { + if (column >= mContainerInfo.columnCount) { + throw GSException("Index out of bound error"); + } return mContainerInfo.columnInfoList[column]; } - /* - * Get attribute: mContainerInfo.rowKeyAssigned + + /** + * @brief Get rowKeyAssigned value of ContainerInfo + * @return The boolean value indicating whether the Row key Column is assigned */ bool ContainerInfo::get_row_key_assigned() { return mContainerInfo.rowKeyAssigned; } /** - * Return GSContainerInfo variable + * @brief Get all information of Container + * @return A pointer which store all information of Container */ GSContainerInfo* ContainerInfo::gs_info() { return &mContainerInfo; } /** - * Set attribute :column_info_list + * @brief Set information of column stored in ContainerInfo + * @param columnInfoList A struct which store information of column */ void ContainerInfo::set_column_info_list(ColumnInfoList columnInfoList) { //Free current stored ColumnInfo list if (mContainerInfo.columnInfoList) { //Free memory of columns name for(int i = 0; i < mContainerInfo.columnCount; i++) { - free((void *) mContainerInfo.columnInfoList[i].name); + delete[] mContainerInfo.columnInfoList[i].name; } - free((void*) mContainerInfo.columnInfoList); + delete[] mContainerInfo.columnInfoList; } - //Copy memory of new ColumnInfo list - GSColumnInfo* tmpColumnInfoList = NULL; - if (columnInfoList.size > 0 && columnInfoList.columnInfo != NULL) { - tmpColumnInfoList = (GSColumnInfo *) malloc(columnInfoList.size*sizeof(GSColumnInfo)); - //Copy memory of GSColumnInfo list - memcpy(tmpColumnInfoList, columnInfoList.columnInfo, columnInfoList.size*sizeof(GSColumnInfo)); - //Copy memory of columns name - for (int i = 0; i < columnInfoList.size; i++) { - if (columnInfoList.columnInfo[i].name) { - tmpColumnInfoList[i].name = strdup(columnInfoList.columnInfo[i].name); - } else { - tmpColumnInfoList[i].name = NULL; + mContainerInfo.columnCount = columnInfoList.size; + mContainerInfo.columnInfoList = NULL; + + if (columnInfoList.size == 0 || columnInfoList.columnInfo == NULL) { + return; + } + + GSColumnInfo* tmpColumnInfoList; + try { + tmpColumnInfoList = new GSColumnInfo[columnInfoList.size](); + } catch (bad_alloc& ba) { + throw GSException("Memory allocation error"); + } + + //Copy memory of GSColumnInfo list + memcpy(tmpColumnInfoList, columnInfoList.columnInfo, columnInfoList.size*sizeof(GSColumnInfo)); + //Copy memory of columns name + for (int i = 0; i < columnInfoList.size; i++) { + if (columnInfoList.columnInfo[i].name) { + try { + Util::strdup(&(tmpColumnInfoList[i].name), columnInfoList.columnInfo[i].name); + } catch (bad_alloc& ba) { + delete[] tmpColumnInfoList; + tmpColumnInfoList = NULL; + throw GSException("Memory allocation error"); } + } else { + tmpColumnInfoList[i].name = NULL; } } mContainerInfo.columnInfoList = tmpColumnInfoList; - mContainerInfo.columnCount = columnInfoList.size; } /** - * Get attribute :column_info_list + * @brief Get information of column stored in ContainerInfo + * @return A struct which store information of column */ ColumnInfoList ContainerInfo::get_column_info_list() { mColumnInfoList.columnInfo = (GSColumnInfo*) mContainerInfo.columnInfoList; @@ -230,25 +326,32 @@ namespace griddb { return mColumnInfoList; } - /* - * Set attribute: expiration + /** + * @brief Set expirationInfo for timeseries container which is stored in ContainerInfo + * @param *expirationInfo A ExpirationInfo object which store the information about optional configuration settings used for newly creating or updating a TimeSeries */ void ContainerInfo::set_expiration_info(ExpirationInfo* expirationInfo) { -#if GS_COMPATIBILITY_SUPPORT_1_5 if (mContainerInfo.timeSeriesProperties != NULL) { - free((void*) mContainerInfo.timeSeriesProperties); + delete mContainerInfo.timeSeriesProperties; + mContainerInfo.timeSeriesProperties = NULL; } if (expirationInfo) { - GSTimeSeriesProperties* ts = (GSTimeSeriesProperties*) malloc(sizeof(GSTimeSeriesProperties)); + GSTimeSeriesProperties* ts; + try { + ts = new GSTimeSeriesProperties(); + } catch (bad_alloc& ba) { + throw GSException("Memory allocation error"); + } + memcpy(ts, expirationInfo->gs_ts(), sizeof(GSTimeSeriesProperties)); mContainerInfo.timeSeriesProperties = ts; } -#endif } - /* - * Get attribute: expiration + /** + * @brief Get expirationInfo for timeseries container which is stored in ContainerInfo + * @return A ExpirationInfo object which store the information about optional configuration settings used for newly creating or updating a TimeSeries */ ExpirationInfo* ContainerInfo::get_expiration_info() { if (mContainerInfo.timeSeriesProperties != NULL){ @@ -257,9 +360,13 @@ namespace griddb { mExpInfo->set_time_unit(mContainerInfo.timeSeriesProperties->rowExpirationTimeUnit); mExpInfo->set_division_count(mContainerInfo.timeSeriesProperties->expirationDivisionCount); } else { - mExpInfo = new ExpirationInfo(mContainerInfo.timeSeriesProperties->rowExpirationTime, - mContainerInfo.timeSeriesProperties->rowExpirationTimeUnit, - mContainerInfo.timeSeriesProperties->expirationDivisionCount); + try { + mExpInfo = new ExpirationInfo(mContainerInfo.timeSeriesProperties->rowExpirationTime, + mContainerInfo.timeSeriesProperties->rowExpirationTimeUnit, + mContainerInfo.timeSeriesProperties->expirationDivisionCount); + } catch (bad_alloc& ba) { + throw GSException("Memory allocation error"); + } } } else { mExpInfo = NULL; diff --git a/src/ContainerInfo.h b/src/ContainerInfo.h index af4bd57..045a249 100644 --- a/src/ContainerInfo.h +++ b/src/ContainerInfo.h @@ -20,9 +20,12 @@ #include #include #include +#include + #include "TimeSeriesProperties.h" #include "ExpirationInfo.h" #include "GSException.h" +#include "Util.h" //Support column_info_list attribute struct ColumnInfoList { diff --git a/src/EnumValue.h b/src/EnumValue.h index 237ca00..dfbffbd 100644 --- a/src/EnumValue.h +++ b/src/EnumValue.h @@ -45,7 +45,6 @@ class RowSetType { class FetchOption { public: static const int LIMIT = 0; -#if GS_COMPATIBILITY_SUPPORT_1_5 #if GS_INTERNAL_DEFINITION_VISIBLE #if !GS_COMPATIBILITY_DEPRECATE_FETCH_OPTION_SIZE @@ -56,8 +55,6 @@ class FetchOption { #if GS_COMPATIBILITY_SUPPORT_4_0 static const int PARTIAL_EXECUTION = (LIMIT + 2); #endif - -#endif }; // Represents the time unit(s) used in TimeSeries data operation. class TimeUnit { @@ -93,10 +90,9 @@ class Type { static const int FLOAT_ARRAY = 17; static const int DOUBLE_ARRAY = 18; static const int TIMESTAMP_ARRAY = 19; -#if GS_COMPATIBILITY_SUPPORT_3_5 - // Can't use NULL because it is keyword of C language + + // Can't use NULL because it is keyword of C language static const int NULL_TYPE = -1; -#endif }; // Sum of bits of value of the flag indicating the option setting for Column. class TypeOption { diff --git a/src/PartitionController.cpp b/src/PartitionController.cpp index 7cf9a44..639b0fc 100644 --- a/src/PartitionController.cpp +++ b/src/PartitionController.cpp @@ -18,49 +18,69 @@ namespace griddb { + /** + * @brief Constructor a new PartitionController::PartitionController object + * @param *controller A pointer for acquiring and processing the partition status + */ PartitionController::PartitionController(GSPartitionController *controller) : mController(controller) { } + /** - * Destructor. Convert from C-API:gsClosePartitionController + * @brief Destructor to free resources for a PartitionController object */ PartitionController::~PartitionController() { close(); } + + /** + * @brief Release PartitionController resource + */ void PartitionController::close() { if (mController != NULL) { gsClosePartitionController(&mController); mController = NULL; } } + /** - * Get partition count. Convert from C-Api: gsGetPartitionCount + * @brief Get partition count + * @return The number of partitions in the target GridDB cluster */ int32_t PartitionController::get_partition_count() { int32_t value; GSResult ret = gsGetPartitionCount(mController, &value); // Check ret, if error, throw exception - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mController, ret); } return value; } + /** - * Get container partition count. Convert from C-Api: gsGetPartitionContainerCount + * @brief Get container partition count + * @param partition_index The partition index, from 0 to the number of partitions minus one + * @return The number of Container */ int64_t PartitionController::get_container_count(int32_t partition_index) { int64_t value; GSResult ret = gsGetPartitionContainerCount(mController, partition_index, &value); // Check ret, if error, throw exception - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mController, ret); } return value; } + /** - * Get list partition container names case there is limit. Convert from C-Api: gsGetPartitionContainerNames + * @brief Get a list of the Container names belonging to a specified partition. + * @param partition_index The partition index, from 0 to the number of partitions minus one + * @param start The start position of the acquisition range. A value must be greater than or equal to 0 + * @param ***stringList The pointer to a pointer variable to store the array list of Container name + * @param *size The pointer to a variable to store the number of array elements of the Container name list + * @param limit The upper limit of the number of cases acquired */ void PartitionController::get_container_names(int32_t partition_index, int64_t start, const GSChar * const ** stringList, size_t *size, int64_t limit) { @@ -72,20 +92,22 @@ namespace griddb { } GSResult ret = gsGetPartitionContainerNames(mController, partition_index, start, limitPtr, stringList, size); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mController, ret); } } /** - * Get get_partition index of container. Convert from C-Api: gsGetPartitionIndexOfContainer + * @brief Get the partition index corresponding to the specified Container name. + * @param *container_name Container name + * @return The partition index */ int32_t PartitionController::get_partition_index_of_container(const GSChar* container_name) { int32_t value; GSResult ret = gsGetPartitionIndexOfContainer(mController, container_name, &value); // Check ret, if error, throw exception - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mController, ret); } return value; diff --git a/src/PartitionController.h b/src/PartitionController.h index 6945e3a..cead4d5 100644 --- a/src/PartitionController.h +++ b/src/PartitionController.h @@ -34,7 +34,7 @@ class PartitionController { int32_t get_partition_count(); int64_t get_container_count(int32_t partition_index); void get_container_names(int32_t partition_index, int64_t start, - const GSChar * const ** stringList, size_t *size, int64_t limit = -1); + const GSChar * const ** stringList , size_t *size , int64_t limit = -1); int32_t get_partition_index_of_container(const GSChar *container_name); private: diff --git a/src/Query.cpp b/src/Query.cpp index 10bae12..da07678 100644 --- a/src/Query.cpp +++ b/src/Query.cpp @@ -18,14 +18,22 @@ namespace griddb { + /** + * @brief Constructor a new Query::Query object + * @param *query A pointer holding the information about a query related to a specific GSContainer + * @param *containerInfo A pointer holding the information about a specific GSContainer + * @param *gsRow A pointer holding the information about a row related to a specific GSContainer + */ Query::Query(GSQuery *query, GSContainerInfo *containerInfo, GSRow *gsRow) : mQuery(query), mContainerInfo(containerInfo), mRow(gsRow) { } + Query::~Query() { close(); } + /** - * Release all resources created by this Query object. + * @brief Release Query resource */ void Query::close() { if (mQuery) { @@ -33,65 +41,79 @@ namespace griddb { mQuery = NULL; } } + /** - * Fetch data from query result. + * @brief Fetch data from query result. + * @param for_update Indicates whether it requests a lock for update or not + * @return The pointer to a pointer variable to store GSRowSet instance */ RowSet* Query::fetch(bool for_update) { - GSRowSet *rowSet; + GSRowSet *gsRowSet; // Call method from C-Api. GSBool gsForUpdate = (for_update == true ? GS_TRUE:GS_FALSE); - GSResult ret = gsFetch(mQuery, gsForUpdate, &rowSet); + GSResult ret = gsFetch(mQuery, gsForUpdate, &gsRowSet); // Check ret, if error, throw exception - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mQuery, ret); } - return new RowSet(rowSet, mContainerInfo, mRow); + try { + RowSet* rowset = new RowSet(gsRowSet, mContainerInfo, mRow); + return rowset; + } catch (bad_alloc& ba) { + gsCloseRowSet(&gsRowSet); + throw GSException(mQuery, "Memory allocation error"); + } } + /** - * Get row set. Convert from C-Api: gsGetRowSet + * @brief Get row set. + * @return The pointer to a pointer variable to store GSRowSet instance */ RowSet* Query::get_row_set() { - GSRowSet *rowSet; - GSResult ret = gsGetRowSet(mQuery, &rowSet); + GSRowSet *gsRowSet; + GSResult ret = gsGetRowSet(mQuery, &gsRowSet); // Check ret, if error, throw exception - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mQuery, ret); } - return new RowSet(rowSet, mContainerInfo, mRow); + try { + RowSet* rowset = new RowSet(gsRowSet, mContainerInfo, mRow); + return rowset; + } catch (bad_alloc& ba) { + gsCloseRowSet(&gsRowSet); + throw GSException(mQuery, "Memory allocation error"); + } } /** - * Get raw pointer of GSQuery + * @brief Get raw pointer of GSQuery + * @return A pointer store raw pointer of GSQuery */ GSQuery* Query::gs_ptr() { return mQuery; } + /** - * Set fetch limit option + * @brief Set fetch limit option for a result acquisition. + * @param limit The maximum number of Rows to be fetched. + * @param partial The option value for GSFetchOption */ void Query::set_fetch_options(int limit, bool partial){ - GSFetchOption fetchOption; GSResult ret; - if (limit >= 0) { - fetchOption = GS_FETCH_LIMIT; - ret = gsSetFetchOption(mQuery, fetchOption, &limit, GS_TYPE_INTEGER); - if (ret != GS_RESULT_OK) { - throw GSException(mQuery, ret); - } + ret = gsSetFetchOption(mQuery, GS_FETCH_LIMIT, &limit, GS_TYPE_INTEGER); + if (!GS_SUCCEEDED(ret)) { + throw GSException(mQuery, ret); } - if (partial == true) { #if GS_COMPATIBILITY_SUPPORT_4_0 - fetchOption = GS_FETCH_PARTIAL_EXECUTION; - //Need to call gsSetFetchOption as many as the number of options - ret = gsSetFetchOption(mQuery, fetchOption, &partial, GS_TYPE_BOOL); - if (ret != GS_RESULT_OK) { - throw GSException(mQuery, ret); - } -#endif + //Need to call gsSetFetchOption as many as the number of options + ret = gsSetFetchOption(mQuery, GS_FETCH_PARTIAL_EXECUTION, &partial, GS_TYPE_BOOL); + if (!GS_SUCCEEDED(ret)) { + throw GSException(mQuery, ret); } +#endif } } diff --git a/src/Query.h b/src/Query.h index e7d180d..3500886 100644 --- a/src/Query.h +++ b/src/Query.h @@ -18,6 +18,7 @@ #define _QUERY_H_ #include + #include "gridstore.h" #include "RowSet.h" #include "GSException.h" @@ -28,6 +29,7 @@ namespace griddb { /** * Convert from GSQuery */ + class Query { friend class Container; private: diff --git a/src/QueryAnalysisEntry.cpp b/src/QueryAnalysisEntry.cpp index a3e377c..daffdf0 100644 --- a/src/QueryAnalysisEntry.cpp +++ b/src/QueryAnalysisEntry.cpp @@ -16,87 +16,129 @@ #include "QueryAnalysisEntry.h" +#include + namespace griddb { + /** + * @brief Constructor a new QueryAnalysisEntry::QueryAnalysisEntry object + * @param *queryAnalysis Represents one of information entries composing a query plan and the results of analyzing a query operation. + */ QueryAnalysisEntry::QueryAnalysisEntry(GSQueryAnalysisEntry* queryAnalysis) : mQueryAnalysis(NULL) { - if (queryAnalysis) { + if (!queryAnalysis) { + return; + } + + try { if (!mQueryAnalysis) { - mQueryAnalysis = (GSQueryAnalysisEntry*) malloc(sizeof(GSQueryAnalysisEntry)); + mQueryAnalysis = new GSQueryAnalysisEntry(); } - //Copy value which queryAnalysis point to - mQueryAnalysis->id = queryAnalysis->id; - mQueryAnalysis->depth = queryAnalysis->depth; + + mQueryAnalysis->statement = NULL; + mQueryAnalysis->type = NULL; + mQueryAnalysis->value = NULL; + mQueryAnalysis->valueType = NULL; + if (queryAnalysis->statement) { - mQueryAnalysis->statement = strdup(queryAnalysis->statement); - } else { - mQueryAnalysis->statement = NULL; + Util::strdup(&(mQueryAnalysis->statement), queryAnalysis->statement); } + if (queryAnalysis->type) { - mQueryAnalysis->type = strdup(queryAnalysis->type); - } else { - mQueryAnalysis->type = NULL; + Util::strdup(&(mQueryAnalysis->type), queryAnalysis->type); } + if (queryAnalysis->value) { - mQueryAnalysis->value = strdup(queryAnalysis->value); - } else { - mQueryAnalysis->value = NULL; + Util::strdup(&(mQueryAnalysis->value), queryAnalysis->value); } + if (queryAnalysis->valueType) { - mQueryAnalysis->valueType = strdup(queryAnalysis->valueType); - } else { - mQueryAnalysis->valueType = NULL; + Util::strdup(&(mQueryAnalysis->valueType), queryAnalysis->valueType); } + } catch (bad_alloc& ba) { + this->freeMemory(); + throw GSException(mQueryAnalysis, "Memory allocation error"); } + + //Copy value which queryAnalysis point to + mQueryAnalysis->id = queryAnalysis->id; + mQueryAnalysis->depth = queryAnalysis->depth; } QueryAnalysisEntry::~QueryAnalysisEntry() { this->close(); } + /** + * @brief Release QueryAnalysisEntry resource + */ void QueryAnalysisEntry::close() { + this->freeMemory(); + if (mQueryAnalysis) { + mQueryAnalysis = NULL; + } + } + + void QueryAnalysisEntry::freeMemory() { if (mQueryAnalysis) { if (mQueryAnalysis->statement) { - free((void*) mQueryAnalysis->statement); + delete[] mQueryAnalysis->statement; } if (mQueryAnalysis->type) { - free((void*) mQueryAnalysis->type); + delete[] mQueryAnalysis->type; } if (mQueryAnalysis->value) { - free((void*) mQueryAnalysis->value); + delete[] mQueryAnalysis->value; } if (mQueryAnalysis->valueType) { - free((void*) mQueryAnalysis->valueType); + delete[] mQueryAnalysis->valueType; } - free((void *) mQueryAnalysis); - mQueryAnalysis = NULL; + delete mQueryAnalysis; } } /** - * get QueryAnalysisEntry data + * @brief get QueryAnalysisEntry data + * @param *queryAnalysis Represents one of information entries composing a query plan and the results of analyzing a query operation. */ void QueryAnalysisEntry::get(GSQueryAnalysisEntry* queryAnalysis) { + assert(queryAnalysis != NULL); queryAnalysis->id = mQueryAnalysis->id; queryAnalysis->depth = mQueryAnalysis->depth; - if (mQueryAnalysis->statement) { - queryAnalysis->statement = strdup(mQueryAnalysis->statement); - } else { - queryAnalysis->statement = NULL; - } - if (mQueryAnalysis->type) { - queryAnalysis->type = strdup(mQueryAnalysis->type); - } else { - queryAnalysis->type = NULL; - } - if (mQueryAnalysis->value) { - queryAnalysis->value = strdup(mQueryAnalysis->value); - } else { - queryAnalysis->value = NULL; - } - if (mQueryAnalysis->valueType) { - queryAnalysis->valueType = strdup(mQueryAnalysis->valueType); - } else { - queryAnalysis->valueType = NULL; + queryAnalysis->statement = NULL; + queryAnalysis->type = NULL; + queryAnalysis->value = NULL; + queryAnalysis->valueType = NULL; + + try { + if (mQueryAnalysis->statement) { + Util::strdup(&(queryAnalysis->statement), mQueryAnalysis->statement); + } + + if (mQueryAnalysis->type) { + Util::strdup(&(queryAnalysis->type), mQueryAnalysis->type); + } + + if (mQueryAnalysis->value) { + Util::strdup(&(queryAnalysis->value), mQueryAnalysis->value); + } + + if (mQueryAnalysis->valueType) { + Util::strdup(&(queryAnalysis->valueType), mQueryAnalysis->valueType); + } + } catch (bad_alloc& ba) { + if (queryAnalysis->statement) { + delete[] queryAnalysis->statement; + } + if (queryAnalysis->type) { + delete[] queryAnalysis->type; + } + if (queryAnalysis->value) { + delete[] queryAnalysis->value; + } + if (queryAnalysis->valueType) { + delete[] queryAnalysis->valueType; + } + throw GSException(mQueryAnalysis, "Memory allocation error"); } } } diff --git a/src/QueryAnalysisEntry.h b/src/QueryAnalysisEntry.h index 6925307..107839b 100644 --- a/src/QueryAnalysisEntry.h +++ b/src/QueryAnalysisEntry.h @@ -22,6 +22,7 @@ #include "gridstore.h" #include "GSException.h" +#include "Util.h" using namespace std; @@ -30,6 +31,7 @@ namespace griddb { class QueryAnalysisEntry { private: GSQueryAnalysisEntry* mQueryAnalysis; + void freeMemory(); public: QueryAnalysisEntry(GSQueryAnalysisEntry* queryAnalysis); diff --git a/src/RowKeyPredicate.cpp b/src/RowKeyPredicate.cpp index 5aa1120..2370426 100644 --- a/src/RowKeyPredicate.cpp +++ b/src/RowKeyPredicate.cpp @@ -18,17 +18,24 @@ namespace griddb { + /** + * @brief Constructor a new RowSet::RowSet object + * @param *predicate Represents the condition that a row key satisfies. + * @param type The type of Row key used as a matching condition + */ RowKeyPredicate::RowKeyPredicate(GSRowKeyPredicate *predicate, GSType type): mPredicate(predicate), mType(type), timestamp_output_with_float(false){ } + /** - * Destructor. Call close methods to release resource + * @brief Destructor to free resource of RowKeyPredicate object */ RowKeyPredicate::~RowKeyPredicate() { close(); } + /** - * Convert from C-API: gsCloseRowKeyPredicate + * @brief Release RowKeyPredicate resource */ void RowKeyPredicate::close() { if (mPredicate != NULL) { @@ -38,29 +45,39 @@ namespace griddb { } /** - * Get key type. Convert from C-API: gsGetPredicateKeyType + * @brief Get key type + * @return The type of Row key used as a matching condition */ GSType RowKeyPredicate::get_key_type() { return mType; } - /* - * Returns the value of Row key at the start and end position of the range condition + + /** + * @brief Get the value of Row key at the start and end position of the range condition + * @param *startField The pointer to a variable to store the value of the Row key at the starting position + * @param *finishField The pointer to a variable to store the value of the Row key at the end position */ void RowKeyPredicate::get_range(Field* startField, Field* finishField) { + assert(startField != NULL); + assert(finishField != NULL); startField->type = -1; // for all versions which do not support GS_TYPE_NULL finishField->type = -1; // for all versions which do not support GS_TYPE_NULL GSType key_type = get_key_type(); const GSValue *startKey = NULL; const GSValue *endKey = NULL; GSResult ret = gsGetPredicateStartKeyGeneral(mPredicate, &startKey); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } if (startKey != NULL) { startField->type = key_type; if (startField->type == GS_TYPE_STRING) { if (startKey->asString) { - startField->value.asString = strdup(startKey->asString); + try { + Util::strdup(&(startField->value.asString), startKey->asString); + } catch (bad_alloc& ba) { + throw GSException(mPredicate, "Memory allocation error"); + } } else { startField->value.asString = NULL; } @@ -69,9 +86,9 @@ namespace griddb { } } ret = gsGetPredicateFinishKeyGeneral(mPredicate, &endKey); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { if (startField->type == GS_TYPE_STRING && startField->value.asString) { - free((void*) startField->value.asString); + delete[] startField->value.asString; } throw GSException(mPredicate, ret); } @@ -79,7 +96,14 @@ namespace griddb { finishField->type = key_type; if (finishField->type == GS_TYPE_STRING) { if (endKey->asString) { - finishField->value.asString = strdup(endKey->asString); + try { + Util::strdup(&(finishField->value.asString), endKey->asString); + } catch (bad_alloc& ba) { + if (startField->type == GS_TYPE_STRING && startField->value.asString) { + delete[] startField->value.asString; + } + throw GSException(mPredicate, "Memory allocation error"); + } } else { finishField->value.asString = NULL; } @@ -88,53 +112,58 @@ namespace griddb { } } } - /* - * Sets the value of Row key as the start and end position of the range conditions + + /** + * @brief Sets the value of Row key as the start and end position of the range conditions + * @param *startKey The pointer to a variable to store the value of the Row key at the starting position + * @param *finishKey The pointer to a variable to store the value of the Row key at the end position */ void RowKeyPredicate::set_range(Field* startKey, Field* finishKey) { + assert(startKey != NULL); + assert(finishKey != NULL); GSType key_type = get_key_type(); GSResult ret; switch (key_type) { case GS_TYPE_LONG: ret = gsSetPredicateStartKeyByLong(mPredicate, (int64_t*)&startKey->value.asLong); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } ret = gsSetPredicateFinishKeyByLong(mPredicate, (int64_t *) &finishKey->value.asLong); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } break; case GS_TYPE_INTEGER: ret = gsSetPredicateStartKeyByInteger(mPredicate, (const int32_t *) &startKey->value.asInteger); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } ret = gsSetPredicateFinishKeyByInteger(mPredicate, (const int32_t *)&finishKey->value.asInteger); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } break; case GS_TYPE_STRING: ret = gsSetPredicateStartKeyByString(mPredicate, startKey->value.asString); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } ret = gsSetPredicateFinishKeyByString(mPredicate, finishKey->value.asString); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } break; case GS_TYPE_TIMESTAMP: ret = gsSetPredicateStartKeyByTimestamp(mPredicate, (const GSTimestamp *) &(startKey->value.asTimestamp)); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } ret = gsSetPredicateFinishKeyByTimestamp(mPredicate, (const GSTimestamp *) &(finishKey->value.asTimestamp)); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } break; @@ -143,38 +172,44 @@ namespace griddb { break; } } - /* - * Adds the value of Row key as one of the elements in the individual condition + + /** + * @brief Adds the value of Row key as one of the elements in the individual condition + * @param *keys The value of Row key to be added as one of the elements in the individual condition + * @param keyCount Number of distinct key */ void RowKeyPredicate::set_distinct_keys(const Field *keys, size_t keyCount) { + assert(keys != NULL); GSType key_type = get_key_type(); GSResult ret; for (size_t i = 0; i < keyCount; i++) { const Field* key = keys + i; + assert(key != NULL); switch (key_type) { case GS_TYPE_LONG: ret = gsAddPredicateKeyByLong(mPredicate, key->value.asLong); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } break; case GS_TYPE_INTEGER: ret = gsAddPredicateKeyByInteger(mPredicate, key->value.asInteger); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } break; case GS_TYPE_STRING: ret = gsAddPredicateKeyByString(mPredicate, key->value.asString); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } + break; case GS_TYPE_TIMESTAMP: ret = gsAddPredicateKeyByTimestamp(mPredicate, key->value.asTimestamp); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mPredicate, ret); } break; @@ -184,39 +219,63 @@ namespace griddb { } } } - /* - * Returns a set of the values of the Row keys that configure the individual condition. + + /** + * @brief Get a set of the values of the Row keys that configure the individual condition. + * @param **keys A pointer refers to list of Row key value + * @param *keyCount A pointer stores number of distinct key */ void RowKeyPredicate::get_distinct_keys(Field **keys, size_t* keyCount) { + assert(keys != NULL); + assert(keyCount != NULL); + size_t size; GSType key_type = get_key_type(); GSValue * keyList; GSResult ret = gsGetPredicateDistinctKeysGeneral(mPredicate, (const GSValue **)&keyList, &size); + if (!GS_SUCCEEDED(ret)) { + throw GSException(mPredicate, ret); + } *keyCount = size; - Field* keyFields = new Field[size]; - for(int i = 0; i < size; i++) { - keyFields[i].type = key_type; - switch(key_type) { - case GS_TYPE_STRING: - if (keyList[i].asString) { - keyFields[i].value.asString = strdup(keyList[i].asString); - } else { - keyFields[i].value.asString = NULL; + Field* keyFields; + try { + keyFields = new Field[size](); //will be free in typemap out + for (int i = 0; i < size; i++) { + keyFields[i].type = key_type; + switch(key_type) { + case GS_TYPE_STRING: + if (keyList[i].asString) { + Util::strdup(&(keyFields[i].value.asString), keyList[i].asString); + } else { + keyFields[i].value.asString = NULL; + } + break; + default: + keyFields[i].value = keyList[i]; + break; } - break; - default: - keyFields[i].value = keyList[i]; - break; } - } + *keys = keyFields; + } catch (bad_alloc& ba) { + if (keyFields) { + for (int i = 0; i < size; i++) { + if (keyFields[i].type == GS_TYPE_STRING && keyFields[i].value.asString) { + delete[] keyFields[i].value.asString; + } + } + delete[] keyFields; + } - *keys = keyFields; - if (ret != GS_RESULT_OK) { - throw GSException(mPredicate, ret); + throw GSException(mPredicate, "Memory allocation error"); } + } + /** + * @brief Get GSRowKeyPredicate data in RowKeyPredicate object + * @return A pointer stores GSRowKeyPredicate data in RowKeyPredicate object + */ GSRowKeyPredicate* RowKeyPredicate::gs_ptr() { return mPredicate; } diff --git a/src/RowKeyPredicate.h b/src/RowKeyPredicate.h index 59876a6..0134a17 100644 --- a/src/RowKeyPredicate.h +++ b/src/RowKeyPredicate.h @@ -19,11 +19,13 @@ #include #include +#include #include #include "gridstore.h" #include "Field.h" #include "GSException.h" +#include "Util.h" using namespace std; diff --git a/src/RowSet.cpp b/src/RowSet.cpp index 6d28e9c..b0ce22e 100644 --- a/src/RowSet.cpp +++ b/src/RowSet.cpp @@ -18,6 +18,12 @@ namespace griddb { + /** + * @brief Constructor a new RowSet::RowSet object + * @param *rowSet A pointer manages a set of Rows obtained by a query + * @param *containerInfo A pointer holding the information about a specific GSContainer + * @param *gsRow A pointer holding the information about a row related to a specific GSContainer + */ RowSet::RowSet(GSRowSet *rowSet, GSContainerInfo *containerInfo, GSRow *gsRow) : mRowSet(rowSet), mContainerInfo(containerInfo), mRow(gsRow), timestamp_output_with_float(false), typeList(NULL) { @@ -27,8 +33,10 @@ namespace griddb { throw GSException(mRowSet, "mRowSet is NULL"); } } + /** - * Check if RowSet has next row data. Convert from gsHasNextRow. + * @brief Check if RowSet has next row data. + * @return Returns whether a Row set has at least one Row ahead of the current cursor position */ bool RowSet::has_next() { GSRowSetType type; @@ -38,55 +46,67 @@ namespace griddb { case (GS_ROW_SET_AGGREGATION_RESULT): case (GS_ROW_SET_QUERY_ANALYSIS): return (bool) gsHasNextRow(mRowSet); - break; default: return false; - break; } } + RowSet::~RowSet() { close(); if (typeList) { - free(typeList); + delete[] typeList; } } + /** - * Close rowset. + * @brief Release RowSet resource */ void RowSet::close() { if (mRowSet != NULL) { gsCloseRowSet(&mRowSet); mRowSet = NULL; } - } + /** - * Update current row from RowSet + * @brief Update current row from RowSet + * @param *row A Row object representing the content of a Row to be put to database */ void RowSet::update(GSRow* row) { GSResult ret = gsUpdateCurrentRow(mRowSet, mRow); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mRowSet, ret); } } + /** - * Get next row data. Convert from gsGetNextRow. + * @brief Get next row data. + * @param *hasNextRow Indicate whether there is any row in RowSet or not */ void RowSet::next_row(bool* hasNextRow) { *hasNextRow = this->has_next(); if (*hasNextRow) { GSResult ret = gsGetNextRow(mRowSet, mRow); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mRowSet, ret); } } } + /** - * Get next row + * @brief Get next row or queryAnalysis or aggResult corresponding query command + * @param *type The type of content that can be extracted from GSRowSet. + * @param *hasNextRow Indicate whether there is any row in RowSet or not + * @param **queryAnalysis Represents one of information entries composing a query plan and the results of analyzing a query operation. + * @param **aggResult Stores the result of an aggregation operation. */ void RowSet::next(GSRowSetType* type, bool* hasNextRow, QueryAnalysisEntry** queryAnalysis, AggregationResult** aggResult){ + assert(type != NULL); + assert(hasNextRow != NULL); + assert(queryAnalysis != NULL); + assert(aggResult != NULL); *type = this->type(); switch(*type) { case (GS_ROW_SET_CONTAINER_ROWS): @@ -104,81 +124,122 @@ namespace griddb { throw GSException(mRowSet, "type for rowset is not correct"); } } + /** - * Return size of this rowset + * @brief Get size of this rowset + * @return Size of this rowset */ int32_t RowSet::size() { return gsGetRowSetSize(mRowSet); } /** - * Delete current row data. Convert from C-API: gsDeleteCurrentRow. + * @brief Delete current row data. */ void RowSet::remove() { GSResult ret = gsDeleteCurrentRow(mRowSet); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mRowSet, ret); } } /** - * Moves to the next Row in a Row set and returns the aggregation result at the moved position. + * @brief Moves to the next Row in a Row set and returns the aggregation result at the moved position. + * @return A pointer Stores the result of an aggregation operation. */ AggregationResult* RowSet::get_next_aggregation() { GSAggregationResult* pAggResult; GSResult ret = gsGetNextAggregation(mRowSet, &pAggResult); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mRowSet, ret); } - return new AggregationResult(pAggResult); + try { + AggregationResult* aggResult = new AggregationResult(pAggResult); + return aggResult; + } catch (bad_alloc& ba) { + gsCloseAggregationResult(&pAggResult); + throw GSException(mRowSet, "Memory allocation error"); + } } /** - * Get current row type. Convert from C-API: gsGetRowSetType. + * @brief Get current row type. + * @return The type of content that can be extracted from GSRowSet. */ GSRowSetType RowSet::type(){ return mType; } /** - * Get next query analysis + * @brief Get next query analysis + * @return Represents one of information entries composing a query plan and the results of analyzing a query operation. */ QueryAnalysisEntry* RowSet::get_next_query_analysis(){ - GSQueryAnalysisEntry queryAnalysis = GS_QUERY_ANALYSIS_ENTRY_INITIALIZER; + GSQueryAnalysisEntry gsQueryAnalysis = GS_QUERY_ANALYSIS_ENTRY_INITIALIZER; GSResult ret; - ret = gsGetNextQueryAnalysis(mRowSet, &queryAnalysis); - if (ret != GS_RESULT_OK) { + ret = gsGetNextQueryAnalysis(mRowSet, &gsQueryAnalysis); + if (!GS_SUCCEEDED(ret)) { throw GSException(mRowSet, ret); } - return new QueryAnalysisEntry(&queryAnalysis); + + try { + QueryAnalysisEntry* queryAnalysis = new QueryAnalysisEntry(&gsQueryAnalysis); + return queryAnalysis; + } catch (bad_alloc& ba) { + throw GSException(mRowSet, "Memory allocation error"); + } } /** - * Get column name from RowSet. Use in python only. + * @brief Get column name from RowSet. Use in python only. + * @param ***listName List name of column + * @param *num Number of column */ void RowSet::get_column_names(char*** listName, int* num){ - if (mContainerInfo){ - //Memory will be free from typemap - (*listName) = (char **) malloc(mContainerInfo->columnCount * sizeof(char*)); + assert(listName != NULL); + assert(num != NULL); + if (!mContainerInfo){ + return; + } + + //Memory will be free from typemap + try { + (*listName) = new char*[mContainerInfo->columnCount](); *num = mContainerInfo->columnCount; for (int i = 0; i < mContainerInfo->columnCount; i++){ if (mContainerInfo->columnInfoList[i].name) { - (*listName)[i] = strdup(mContainerInfo->columnInfoList[i].name); + Util::strdup((const GSChar**)(&((*listName)[i])), mContainerInfo->columnInfoList[i].name); } else { (*listName)[i] = NULL; } } + } catch (bad_alloc& ba) { + for (int i = 0; i < mContainerInfo->columnCount; i++){ + if ((*listName)[i]) { + delete[] (*listName)[i]; + } + } + if ((*listName)) { + delete[] (*listName); + } + throw GSException(mRowSet, "Memory allocation error"); } } /** - * Support put row + * @brief Get list type of column in row + * @return A list type of column in row */ GSType* RowSet::getGSTypeList(){ - if (typeList == NULL){ - typeList = (GSType*) malloc(sizeof(GSType) * mContainerInfo->columnCount); + if (typeList == NULL) { + try { + typeList = new GSType[mContainerInfo->columnCount](); + } catch (bad_alloc& ba) { + throw GSException(mRowSet, "Memory allocation error"); + } + for (int i = 0; i < mContainerInfo->columnCount; i++){ typeList[i] = mContainerInfo->columnInfoList[i].type; } @@ -187,12 +248,17 @@ namespace griddb { } /** - * Support put row + * @brief Get number of column in row + * @return Number of column in row */ int RowSet::getColumnCount(){ return mContainerInfo->columnCount; } + /** + * @brief Get row data in RowSet object + * @return A pointer stores row data in RowSet object + */ GSRow* RowSet::getGSRowPtr(){ return mRow; } diff --git a/src/RowSet.h b/src/RowSet.h index 84d8286..9dad3d8 100644 --- a/src/RowSet.h +++ b/src/RowSet.h @@ -21,12 +21,14 @@ #include #include #include +#include #include "gridstore.h" #include "Field.h" #include "AggregationResult.h" #include "QueryAnalysisEntry.h" #include "GSException.h" +#include "Util.h" using namespace std; diff --git a/src/Store.cpp b/src/Store.cpp index e342184..b6660ba 100644 --- a/src/Store.cpp +++ b/src/Store.cpp @@ -18,14 +18,20 @@ namespace griddb { + /** + * @brief Constructor a new Store::Store object + * @param *store A pointer which provides functions to manipulate the entire data managed in one GridDB system. + */ Store::Store(GSGridStore *store) : mStore(store), timestamp_output_with_float(false) { } + Store::~Store() { // allRelated = FALSE, since all container object is managed by Container class close(GS_FALSE); } + /** - * Release all resources created by this gridstore object + * @brief Release Store resource */ void Store::close(GSBool allRelated) { // close store @@ -34,55 +40,80 @@ namespace griddb { mStore = NULL; } } + /** - * Delete container with specified name + * @brief Delete container with specified name + * @param *name Container name */ void Store::drop_container(const char* name) { GSResult ret = gsDropContainer(mStore, name); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } } + /** - * Return information object of a specific container + * @brief Get information object of a specific container + * @param *name Container name + * @return Return a pointer which stores all information of container */ ContainerInfo* Store::get_container_info(const char* name) { - GSContainerInfo containerInfo = GS_CONTAINER_INFO_INITIALIZER; + GSContainerInfo gsContainerInfo = GS_CONTAINER_INFO_INITIALIZER; GSChar bExists; - GSResult ret = gsGetContainerInfo(mStore, name, &containerInfo, &bExists); - if (ret != GS_RESULT_OK) { + GSResult ret = gsGetContainerInfo(mStore, name, &gsContainerInfo, &bExists); + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } if (bExists == false) { return NULL; } - return new ContainerInfo(&containerInfo); + + try { + ContainerInfo* containerInfo = new ContainerInfo(&gsContainerInfo); + return containerInfo; + } catch (bad_alloc& ba) { + throw GSException(mStore, "Memory allocation error"); + } } + /** - * Put container. Convert from method gsPutContainerGeneral() + * @brief Creates or update a Container with the specified GSContainerInfo. + * @param *info A pointer which stores all information of container + * @param modifiable Indicates whether the column layout of the existing Container can be modified or not + * @return The pointer to a pointer variable to store Container instance */ Container* Store::put_container(ContainerInfo* info, bool modifiable) { + if (info == NULL) { + throw GSException(mStore, "Invalid input for \"Store::put_container\" method. Argument container info can not be null"); + } // Get Container information GSContainerInfo* gsInfo = info->gs_info(); GSContainer* pContainer = NULL; // Create new gsContainer GSResult ret = gsPutContainerGeneral(mStore, gsInfo->name, gsInfo, modifiable, &pContainer); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } - if (pContainer == NULL) { - return NULL; + + try { + Container* container = new Container(pContainer, gsInfo); + return container; + } catch (bad_alloc& ba) { + gsCloseContainer(&pContainer, GS_FALSE); + throw GSException(mStore, "Memory allocation error"); } - return new Container(pContainer, gsInfo); } + /** - * Get container object with corresponding name + * @brief Get container object with corresponding name + * @param *name Container name + * @return The pointer to a pointer variable to store Container instance */ Container* Store::get_container(const char* name) { GSContainer* pContainer; GSResult ret = gsGetContainerGeneral(mStore, name, &pContainer); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } if (pContainer == NULL) { @@ -92,81 +123,141 @@ namespace griddb { GSContainerInfo containerInfo = GS_CONTAINER_INFO_INITIALIZER; GSChar bExists; ret = gsGetContainerInfo(mStore, name, &containerInfo, &bExists); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { + gsCloseContainer(&pContainer, GS_FALSE); throw GSException(mStore, ret); } - return new Container(pContainer, &containerInfo); + try { + Container* container = new Container(pContainer, &containerInfo); + return container; + } catch (bad_alloc& ba) { + gsCloseContainer(&pContainer, GS_FALSE); + throw GSException(mStore, "Memory allocation error"); + } } + /** - * Query execution and fetch is carried out on a specified arbitrary number of Query, with the request unit enlarged as much as possible. + * @brief Query execution and fetch is carried out on a specified arbitrary number of Query, with the request unit enlarged as much as possible. + * @param **queryList A list of query + * @param queryCount Number of element in query list */ void Store::fetch_all(GSQuery* const* queryList, size_t queryCount) { GSResult ret = gsFetchAll(mStore, queryList, queryCount); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } } + /** - * Get Partition controller. Convert from C-API: gsGetPartitionController + * @brief Get Partition controller. + * @return The pointer to a pointer variable to store PartitionController instance */ PartitionController* Store::partition_info() { - GSPartitionController* partitionController; + GSPartitionController* partitionController; + GSResult ret = gsGetPartitionController(mStore, &partitionController); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } - return new PartitionController(partitionController); + try { + PartitionController* partition = new PartitionController(partitionController); + return partition; + } catch (bad_alloc& ba) { + gsClosePartitionController(&partitionController); + throw GSException(mStore, "Memory allocation error"); + } } + /** - * Create row key predicate. Convert from C-API: gsCreateRowKeyPredicate + * @brief Create row key predicate. + * @param type The type of Row key used as a matching condition + * @return The pointer to a pointer variable to store RowKeyPredicate instance */ RowKeyPredicate* Store::create_row_key_predicate(GSType type) { GSRowKeyPredicate* predicate; + GSResult ret = gsCreateRowKeyPredicate(mStore, type, &predicate); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } - return new RowKeyPredicate(predicate, type); + try { + RowKeyPredicate* rowKeyPredicate = new RowKeyPredicate(predicate, type); + return rowKeyPredicate; + } catch (bad_alloc& ba) { + gsCloseRowKeyPredicate(&predicate); + throw GSException(mStore, "Memory allocation error"); + } } + /** - * New creation or update operation is carried out on an arbitrary number of rows of multiple Containers, with the request unit enlarged as much as possible. + * @brief New creation or update operation is carried out on an arbitrary number of rows of multiple Containers, with the request unit enlarged as much as possible. + * @param ***listRow A pointer refers list of row data + * @param *listRowContainerCount A array store number of list row for each container + * @param **listContainerName list container name + * @param containerCount Number of container */ void Store::multi_put(GSRow*** listRow, const int *listRowContainerCount, const char ** listContainerName, size_t containerCount) { + assert(listRowContainerCount != NULL); + assert(listContainerName != NULL); GSResult ret; - GSContainerRowEntry * entryList = (GSContainerRowEntry*) malloc (containerCount * sizeof(GSContainerRowEntry)); + GSContainerRowEntry* entryList; + + try { + entryList = new GSContainerRowEntry[containerCount](); + } catch (bad_alloc& ba) { + throw GSException(mStore, "Memory allocation error"); + } for (int i= 0; i < containerCount; i++) { entryList[i].containerName = listContainerName[i]; entryList[i].rowCount = listRowContainerCount[i]; entryList[i].rowList = (void* const*) listRow[i]; } ret = gsPutMultipleContainerRows(mStore, entryList, containerCount); - free((void*) entryList); - if (ret != GS_RESULT_OK) { + delete[] entryList; + if (!GS_SUCCEEDED(ret)) { throw GSException(mStore, ret); } } + /** - * multi_get method. Using gsGetMultipleContainerRows C-API + * @brief get multi row from multi container + * @param **predicateList A pointer refers list of the specified condition entry by a container for representing the acquisition conditions for a plurality of containers. + * @param predicateCount Number of predicate list + * @param **entryList A pointer refers to a list of the Row contents entry by a container used when operating collectively a plurality of Rows of a plurality of containers. + * @param *containerCount Number of container + * @param **colNumList A pointer refers to an array stores number of column of each container + * @param ***typeList A pointer refers to an array stores type of column of each container + * @param **orderFromInput A pointer refers to an array stores order of each container for output */ void Store::multi_get(const GSRowKeyPredicateEntry* const * predicateList, size_t predicateCount, GSContainerRowEntry **entryList, size_t* containerCount, int **colNumList, GSType*** typeList, int **orderFromInput) { + assert(predicateList != NULL); + assert(predicateCount >= 0); + assert(colNumList != NULL); + assert(typeList != NULL); + assert(orderFromInput != NULL); + assert(containerCount != NULL); *colNumList = NULL; *typeList = NULL; *orderFromInput = NULL; *containerCount = 0; - // get number of column of rows in each container. - *colNumList = new int[predicateCount]; //will be free in argout - *orderFromInput = new int[predicateCount]; //will be free in argout - *typeList = new GSType*[predicateCount]; //will be free in argout - int length = (int)predicateCount; - memset(*colNumList, 0, predicateCount * sizeof(int)); - memset(*typeList, 0, predicateCount * sizeof(GSType*)); + int length = (int) predicateCount; + + try { + // get number of column of rows in each container. + *colNumList = new int[predicateCount](); //will be free in argout + *typeList = new GSType*[predicateCount](); //will be free in argout + *orderFromInput = new int[length](); //will be free in argout + } catch (bad_alloc& ba) { + this->freeMemoryMultiGet(colNumList, typeList, length, orderFromInput); + throw GSException(mStore, "Memory allocation error"); + } bool setNumList = this->setMultiContainerNumList(predicateList, length, &colNumList, &typeList); @@ -174,10 +265,11 @@ namespace griddb { this->freeMemoryMultiGet(colNumList, typeList, length, orderFromInput); throw GSException(mStore, "Set multi containers number list and type list error"); } + // Get data for entryList GSResult ret = gsGetMultipleContainerRows(mStore, predicateList, predicateCount, (const GSContainerRowEntry**) entryList, containerCount); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { this->freeMemoryMultiGet(colNumList, typeList, length, orderFromInput); throw GSException(mStore, ret); } @@ -205,7 +297,7 @@ namespace griddb { if (*typeList) { for (int i = 0; i < length; i++) { if ((*typeList)[i]) { - free((void*) (*typeList)[i]); + delete[] (*typeList)[i]; } } delete [] *typeList; @@ -233,8 +325,15 @@ namespace griddb { return false; } (**colNumList)[i] = tmpContainer->getColumnCount(); - (**typeList)[i] = (GSType*) malloc(sizeof(GSType) * (**colNumList)[i]); - //(**typeList)[i] will be freed in freeMemoryMultiGet() function or argout + + try { + //(**typeList)[i] will be freed in freeMemoryMultiGet() function or argout + (**typeList)[i] = new GSType[(**colNumList)[i]](); + } catch (bad_alloc& ba) { + delete tmpContainer; + return false; + } + for (int j = 0; j < (**colNumList)[i]; j++) { (**typeList)[i][j] = tmpContainer->getGSTypeList()[j]; } @@ -242,4 +341,5 @@ namespace griddb { } return true; } + } diff --git a/src/Store.h b/src/Store.h index 27c4e33..7de25c6 100644 --- a/src/Store.h +++ b/src/Store.h @@ -19,6 +19,7 @@ #include #include +#include #include "ContainerInfo.h" #include "Container.h" diff --git a/src/StoreFactory.cpp b/src/StoreFactory.cpp index 37a9503..617e99f 100644 --- a/src/StoreFactory.cpp +++ b/src/StoreFactory.cpp @@ -22,26 +22,40 @@ namespace griddb { StoreFactory::StoreFactory() : mFactory(NULL) { } + StoreFactory::~StoreFactory() { //allRelated = FALSE, since Gridstore object is managed by Store class close(GS_FALSE); } + /** - * Release all GridStore created by this factory and related resources - */ + * @brief Release StoreFactory resource + */ void StoreFactory::close(GSBool allRelated) { if (mFactory != NULL) { gsCloseFactory(&mFactory, allRelated); mFactory = NULL; } } + + /** + * @brief Get a default GSGridStoreFactory instance. + * @return The pointer to a pointer variable to store StoreFactory instance + */ StoreFactory* StoreFactory::get_instance() { GSGridStoreFactory* pFactory = gsGetDefaultFactory(); - StoreFactory* factory(new StoreFactory()); - factory->set_factory(pFactory); - return factory; + try { + StoreFactory* factory(new StoreFactory()); + factory->set_factory(pFactory); + + return factory; + } catch (bad_alloc& ba) { + gsCloseFactory(&pFactory, GS_FALSE); + throw GSException("Memory allocation error"); + } } + /* * set GSPropertyEntry */ @@ -49,29 +63,44 @@ namespace griddb { prop->name = name; prop->value = value; } + /* * Check whether in MULTICAST mode */ bool StoreFactory::check_multicast(const char* address) { if (address && address[0] != '\0') { - char *tmp = strdup(address); + char* tmp; + try { + Util::strdup((const GSChar**)&tmp, address); + } catch (bad_alloc& ba) { + throw GSException("Memory allocation error"); + } + char *octets = strtok((char*)tmp, "."); if (octets) { int firstOctet = atoi(octets); int first4Bits = firstOctet >> 4 & 0x0f; if (first4Bits == 0x0E) { - free((void *) tmp); + delete[] tmp; return true; } } - if (tmp) { - free((void *) tmp); - } + delete[] tmp; } return false; } - /* - * Returns a Store with the specified properties + + /** + * @brief Get a Store with the specified properties + * @param *host A destination host name + * @param port A destination port number + * @param *cluster_name A cluster name + * @param *database A database name to be connected + * @param *user A user name + * @param *password A password for user authentication + * @param *notification_member A list of address and port pairs in cluster + * @param *notification_provider A URL of address provider + * @return The pointer to a pointer variable to store Store instance */ Store* StoreFactory::get_store(const char* host, int32_t port, const char* cluster_name, const char* database, const char* user, const char* password, @@ -116,36 +145,32 @@ namespace griddb { index++; } - GSGridStore *store; - GSResult ret = gsGetGridStore(mFactory, local_props, index, &store); + GSGridStore *gsStore; + GSResult ret = gsGetGridStore(mFactory, local_props, index, &gsStore); // Check ret, if error, throw exception - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { throw GSException(mFactory, ret); } - return new Store(store); - } - - /** - * Changes the settings for this Factory. - * The changed settings will be reflected in GridStore object which is already created by the specified Factory and GridStore object which will be created later by the Factory. - */ - void StoreFactory::set_properties(const GSPropertyEntry* props, - int propsCount) { - GSResult ret = gsSetFactoryProperties(mFactory, props, propsCount); - // Check ret, if error, throw exception - if (ret != GS_RESULT_OK) { - throw GSException(mFactory, ret); + try { + //return new Store(store); + Store* store = new Store(gsStore); + return store; + } catch (bad_alloc& ba) { + gsCloseGridStore(&gsStore, GS_FALSE); + throw GSException(mFactory, "Memory allocation error"); } } - /* - * Return current client version + /** + * @brief Get current client version + * @return Client version name */ string StoreFactory::get_version() { return CLIENT_VERSION; } + /* * Set attribute: mFactory */ diff --git a/src/StoreFactory.h b/src/StoreFactory.h index f719dcd..f163034 100644 --- a/src/StoreFactory.h +++ b/src/StoreFactory.h @@ -24,6 +24,7 @@ #include "gridstore.h" #include "Store.h" #include "GSException.h" +#include "Util.h" using namespace std; @@ -44,7 +45,6 @@ class StoreFactory { Store* get_store(const char* host=NULL, int32_t port=0, const char* cluster_name=NULL, const char* database=NULL, const char* username=NULL, const char* password=NULL, const char* notification_member=NULL, const char* notification_provider=NULL); - void set_properties(const GSPropertyEntry* props, int propsCount); string get_version(); private: diff --git a/src/TimeSeriesProperties.cpp b/src/TimeSeriesProperties.cpp index ae932ac..0c05f50 100644 --- a/src/TimeSeriesProperties.cpp +++ b/src/TimeSeriesProperties.cpp @@ -18,49 +18,72 @@ namespace griddb { + /** + * @brief Constructor a new TimeSeriesProperties::TimeSeriesProperties object + * @param *timeSeriesProps Represents the information about optional configuration settings used for newly creating or updating a TimeSeries + */ TimeSeriesProperties::TimeSeriesProperties(const GSTimeSeriesProperties* timeSeriesProps) : mTsProps(*timeSeriesProps) { } + /** + * @brief Constructor a new TimeSeriesProperties::TimeSeriesProperties object + * @param elapsedTime The elapsed time period of a Row to be used as the basis of the validity period + * @param timeUnit The unit of elapsed time referenced for the expiration date of a Row + * @param ExpirationDivisionCount The division number for the validity period as the number of expired Row data units to be released + */ TimeSeriesProperties::TimeSeriesProperties(int32_t elapsedTime, GSTimeUnit timeUnit, int32_t ExpirationDivisionCount) : mTsProps{elapsedTime, timeUnit, -1, timeUnit, GS_COMPRESSION_NO, 0, NULL, ExpirationDivisionCount} { } + TimeSeriesProperties::~TimeSeriesProperties() { } - /* - * Set attribute: mTsProps.rowExpirationTime & mTsProps.rowExpirationTimeUnit + + /** + * @brief Set rowExpiration for TimeSeriesProperties. + * @param elapsedTime The elapsed time period of a Row to be used as the basis of the validity period + * @param timeUnit The unit of elapsed time referenced for the expiration date of a Row */ - void TimeSeriesProperties::set_row_expiration_time(int elapsedTime, - GSTimeUnit timeUnit) { + void TimeSeriesProperties::set_row_expiration_time(int elapsedTime, GSTimeUnit timeUnit) { mTsProps.rowExpirationTime = elapsedTime; mTsProps.rowExpirationTimeUnit = timeUnit; } - /* - * Set attribute: mTsProps.expirationDivisionCount + + /** + * @brief Set expirationDivisionCount for TimeSeriesProperties + * @param count The division number for the validity period as the number of expired Row data units to be released */ void TimeSeriesProperties::set_expiration_division_count(int count) { mTsProps.expirationDivisionCount = count; } - /* - * Get attribute: mTsProps.rowExpirationTime + + /** + * @brief Get rowExpirationTime from TimeSeriesProperties + * @return The elapsed time period of a Row to be used as the basis of the validity period */ int TimeSeriesProperties::get_row_expiration_time() { return mTsProps.rowExpirationTime; } - /* - * Get attribute: mTsProps.rowExpirationTimeUnit + + /** + * @brief Get rowExpirationTimeUnit from TimeSeriesProperties + * @return timeUnit The unit of elapsed time referenced for the expiration date of a Row */ GSTimeUnit TimeSeriesProperties::get_row_expiration_time_unit() { return mTsProps.rowExpirationTimeUnit; } - /* - * Get attribute: mTsProps.expirationDivisionCount + + /** + * @brief Get expirationDivisionCount from TimeSeriesProperties + * @return The division number for the validity period as the number of expired Row data units to be released */ int TimeSeriesProperties::get_expiration_division_count() { return mTsProps.expirationDivisionCount; } - /* - * Get attribute: mTsProps + + /** + * @brief Get attribute: mTsProps + * @return A pointer store GSTimeSeriesProperties of TimeSeriesProperties */ GSTimeSeriesProperties* TimeSeriesProperties::gs_ptr() { return &mTsProps; From 08fe971f997ac36d1a537cd43ff9463a62b4764d Mon Sep 17 00:00:00 2001 From: mochizk Date: Fri, 29 Mar 2019 11:36:06 +0900 Subject: [PATCH 5/6] Add comment and fix bugs of griddb_node.js --- griddb_node.js | 984 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 921 insertions(+), 63 deletions(-) diff --git a/griddb_node.js b/griddb_node.js index ba4d259..6b212b8 100644 --- a/griddb_node.js +++ b/griddb_node.js @@ -1,12 +1,40 @@ -var griddb = require('griddb_client'); +var griddb = require('./griddb_client'); var exports = module.exports; griddb['StoreFactory_'] = griddb.StoreFactory; +/** + *

+ * Manage a Store instance. + *
It manages the client settings shared by Store instances and used connections. + *
To access GridDB, you need to get a Store instance using this Factory. + *

+ * @type {object} + * @alias StoreFactory + */ class StoreFactory { constructor(factory) { this.factory = factory; } + + /** + *

+ * Returns a Store with the specified properties. + *
When obtaining Store, it just searches for the name of a master node (hereafter, a master) administering each Container as necessary, but authentication is not performed. When a client really needs to connect to a node corresponding to each Container , authentication is performed. + *
A new Store instance is created by each call of this method. Operations on different Store instances and related resources are thread safe. That is, if some two resources are each created based on Store instances or they are just Store instances, and if they are related to different Store instances respectively, any function related to one resource can be called, no matter when a function related to the other resource may be called from any thread. However, since thread safety is not guaranteed for Store itself, it is not allowed to call a method of a single Store instance from two or more threads at an arbitrary time. + *

+ * @type {Store} + * @param {object} options - Information to get store. + * @param {string} options.host=null - A destination host name. + * @param {number} options.port=null - A destination port number. + * @param {string} options.clusterName=null - A cluster name. + * @param {string} options.database=null - Name of the database to be connected. + * @param {string} options.username=null - A user name. + * @param {string} options.password=null - A password for user authentication. + * @param {string} options.notificationMember=null - A list of address and port pairs in cluster. + * @param {string} options.notificationProvider=null - A URL of address provider. + * @returns {Store} Store instance. + */ getStore(obj) { try { return new Store(this.factory.getStore(obj)); @@ -15,6 +43,15 @@ class StoreFactory { } } + /** + *

+ * Returns a StoreFactory instance. + *
It can be used only for RowSet obtained with locking enabled. + *

+ * @static + * @type {StoreFactory} + * @returns {StoreFactory} StoreFactory instance + */ static getInstance() { try { return new StoreFactory(griddb.StoreFactory_.getInstance()); @@ -22,39 +59,93 @@ class StoreFactory { throw(convertToGSException(err)); } } + + /** + *

+ * Returns the version of this client. + *

+ * @type {string} + * @returns {string} The version of this client + */ getVersion() { return this.factory.getVersion(); } }; +/** + *

+ * Provides functions to manipulate the entire data managed in one GridDB system. + *
A function to add, delete, or change the composition of Collection and TimeSeries Containers as well as to process the Rows constituting a Container is provided. + *
Regardless of container types, etc., multiple container names different only in uppercase and lowercase ASCII characters cannot be defined in a database. See the GridDB Technical Reference for the details. In the operations specifying a container name, uppercase and lowercase ASCII characters are identified as the same unless otherwise noted. + *
Thread safety of each method is not guaranteed. + *

+ * @type {object} + * @alias Store + * @property {PartitionController} partitionController - PartitionController instance corresponding to GridDB cluster. (Read-only attribute) + */ class Store { constructor(store) { this.store = store; this.pController = null; } + + /** + *

+ * Get PartitionController corresponding to GridDB cluster. + *
It can be used until the specified GSGridStore is closed. + *

+ * @type {PartitionController} + * @returns {PartitionController} PartitionController instance + */ get partitionController() { if (this.pController == null) { - this.pController = new PartitionController(this.store.partitionInfo); + this.pController = new PartitionController(this.store.partitionInfo, this); } return this.pController; } + /** + *

+ * Set output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {void} + * @param {boolean} value - enable timestamp ouput float + * @returns {void} + */ set timestampOutput(value) { this.store.timestampOutput = value; } + /** + *

+ * Get output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {boolean} + * @returns {boolean} PartitionController instance + */ get timestampOutput() { return this.store.timestampOutput; } - - // Async functions + + /** + *

+ * Newly creates or update a Container with the specified ContainerInfo. + *
It can be used only for RowSet obtained with locking enabled. + *

+ * @type {Promise} + * @param {ContainerInfo} info - Container information to be processed. + * @param {boolean} modifiable=false - Indicates whether the column layout of the existing Container can be modified or not. + * @returns {Promise} Container instance + */ putContainer(info, modifiable = false) { var this_ = this; return new Promise(function(resolve, reject) { setTimeout(function() { try{ var container = this_.store.putContainer(info, modifiable); - resolve(new Container(container)); + resolve(new Container(container, this_)); } catch(err) { reject(convertToGSException(err)); } @@ -62,13 +153,25 @@ class Store { }); } + /** + *

+ * Get a Container instance whose Rows can be processed using a Row. + *

+ * @type {Promise} + * @param {string} name - Container name to be processed + * @returns {Promise} Container instance. If the Container with the specified name does not exist, null is returned. + */ getContainer(name) { var this_ = this; return new Promise(function(resolve, reject) { setTimeout(function() { try { var container = this_.store.getContainer(name); - resolve(new Container(container)); + if (container === null) { + resolve(null); + } else { + resolve(new Container(container, this_)); + } } catch(err) { reject(convertToGSException(err)); } @@ -76,6 +179,16 @@ class Store { }); } + /** + *

+ * Delete a Container with the specified name. + *
If the specified Container is already deleted, nothing is changed. + *
When a transaction(s) is active in a target Container, it deletes the Container after waiting for the transaction completion. + *

+ * @type {Promise} + * @param {string} name - Container name to be processed. + * @return {Promise} + */ dropContainer(name) { var this_ = this; return new Promise(function(resolve, reject) { @@ -89,6 +202,16 @@ class Store { }); } + /** + *

+ * Get information related to a Container with the specified name. + *
A name stored in GridDB is set for the Container name to be included in a returned ContainerInfo . Therefore, compared to the specified Container name, the notation of the ASCII uppercase characters and lowercase characters may differ. + *
When a transaction(s) is active in a target Container, it deletes the Container after waiting for the transaction completion. + *

+ * @type {Promise} + * @param {string} name - Container name to be processed. + * @returns {Promise} ContainerInfo instance for storing information about the Container with the specified name. If the Container with the specified name does not exist, null is returned. + */ getContainerInfo(name) { var this_= this; return new Promise(function(resolve, reject) { @@ -102,6 +225,20 @@ class Store { }); } + /** + *

+ * Query execution and fetch is carried out on a specified arbitrary number of Query , with the request unit enlarged as much as possible. + *
For each Query included in a specified query column, perform a similar query execution and fetch as when Query.fetch() is performed individually and set the RowSet in the results. Use getRowSet() to extract the execution results of each Query . However, unlike the case when carried out individually, the target node is requested for the same storage destination, etc. with a unit that is as large as possible. Based on this, the larger the number of elements in the list, the higher is the possibility that the number of correspondences with the target node will be reduced. Query in a list are not executed in any particular order. + *
Only a Query that has not been closed, including corresponding Container acquired via the specified Store instance, can be included in a specified query column. Like a fetch() , the Row operations via RowSet finally generated and held by each Query will be unavailable. If the same instance is included multiple times in an array, the behavior will be the same as the case in which the respective instances differ. + *
Like other Container or Row operations, consistency between Containers is not guaranteed. Therefore, the processing results for a certain Container may be affected by other operation commands that have been completed prior to the start of the process. + *
The commit mode of each Container corresponding to the specified Query can be used in either the auto commit mode or manual commit mode. The transaction status is reflected in the execution results of the query. If the operation is completed normally, the corresponding transaction of each Container will not be aborted so long as the transaction timeout time has not been reached. + *
If an exception occurs in the midst of processing each Query , a new RowSet may be set for only some of the Query . In addition, uncommitted transactions of each Query corresponding to the designated Container may be aborted. + *
If the system tries to acquire a large number of Rows all at once, the upper limit of the communication buffer size managed by the GridDB node may be reached, possibly resulting in a failure. Refer to "System limiting values" in the Appendix of GridDB API Reference for the upper limit size. + *

+ * @type {Promise} + * @param {Query[]} queryList - A list of target Queries + * @returns {Promise} + */ fetchAll(queryList) { var this_ = this; if (queryList == null ||queryList.constructor !== Array || queryList.length == 0) { @@ -119,8 +256,13 @@ class Store { setTimeout(function() { var queryListRet = queryList; var queryListTmp = []; + for (var i = 0; i < queryListRet.length; i++) { - queryListTmp.push(queryListRet[i].query); + if (queryListRet[i] && queryListRet[i].hasOwnProperty('query')) { + queryListTmp.push(queryListRet[i].query); + } else { + reject("Invalid input of Store.fetchAll()"); + } } try { resolve(this_.store.fetchAll(queryListTmp)); @@ -132,6 +274,17 @@ class Store { } } + /** + *

+ * New creation or update operation is carried out on an arbitrary number of rows of a Container, with the request unit enlarged as much as possible. + *
For each Row object included in a specified entry column, a new creation or update operation is carried out just like the case when Container.put() is invoked individually. However, unlike the case when carried out individually, the target node is requested for the same storage destination, etc. with a unit that is as large as possible. Based on this, the larger the total number of Row objects specified and the larger the total number of target Containers, the higher is the possibility that the number of correspondences with the target node will be reduced. + *
A specified entry column is composed of an arbitrary number of entries that adopt the Container name as its key and the column of Row objects as its value. A subject Container may be a mixture of different Container types and column layouts. However, the Containers must already exist. Null can not be set as the Container name in the entry column. Also null can not be set as the array address to the column of Row objects if the number of elements in the column of Row objects is positive value. + *
An arbitrary number of Row with the same column layout as the subject Container can be included in each column of Row objects. In the current version, all the column order must also be the same. The Container cannot include null as an element of the column of Row objects. Depending on the Container type and setting, the same restrictions as Container.put() are established for the contents of Rows that can be operated. If there are multiple columns of Row objects having the same Row key targeting the same Container in the designated entry column, the contents of the rear-most Row object having a Row key with the same value will be reflected using the element order of entry column as a reference if it is between different lists, or the element order of the column of Row object as a reference if it is within the same column of Row object. The transaction cannot be maintained and the lock cannot continue to be retained. However, if the lock that affects the target Row is secured by an existing transaction, the system will continue to wait for all the locks to be released. Like other Container or Row operations, consistency between Containers is not guaranteed. Therefore, the processing results for a certain Container may be affected by other operation commands that have been completed prior to the start of the process. If an error occurs in the midst of processing a Container and its Rows, only the results for some of the Rows of some of the Containers may remain reflected. + *

+ * @type {Promise} + * @param {object.} containerEntry - dict-type data consisting of container name and the list of Row objects + * @returns {Promise} + */ multiPut(containerEntry) { var this_ = this; return new Promise(function(resolve, reject) { @@ -145,12 +298,50 @@ class Store { }); } + /** + *

+ * Returns an arbitrary number and range of Rows in any Container based on the specified conditions, with the request unit enlarged as much as possible. + *
Returns the Row contents in accordance with the conditions included in the specified entry column, similar to invoking Container.get() or Query.fetch() individually. However, unlike the case when carried out individually, the target node is requested for the same storage destination, etc. with a unit that is as large as possible. Based on this, the larger the total number of Rows conforming to the conditions and the larger the total number of target Containers, the higher is the possibility that the number of correspondences with the target node will be reduced. + *
A specified condition entry column is composed of an arbitrary number of condition entries that adopt the Container name as the key and the acquisition condition represented by RowKeyPredicate as the value. Multiple instances with the same RowKeyPredicate can also be included. In addition, a subject Container may be a mixture of different Container types and column layouts. However, there are some acquisition conditions that cannot be evaluated due to the composition of the Container. Refer to the definitions of the various setting functions for RowKeyPredicate for the specific restrictions. In addition, the specified Container name must be a real Container. It is prohibited to set null in the Container name or the acquisition condition. + *
An acquired entry column is composed of entries that adopt the Container name as its key and column of Row objects as its value. All entries included in a specified entry as acquisition conditions are included in an acquired entry column. If multiple entries pointing the same Container are included in a specified condition entry column, a single entry consolidating these is stored in the acquired entry column. If multiple Row objects are included in the same list, the stored order follows the Container type and the definition of the individual Container type derived from the corresponding Container . If there is no Row corresponding to the specified Container, the number of elements in corresponding column of Row object will be 0. + *
Like other Container or Row operations, consistency between Containers is not guaranteed. Therefore, the processing results for a certain Container may be affected by other operation commands that have been completed prior to the start of the process. + *
Like Container.get() or Query.fetch() , a transaction cannot be maintained and requests for updating locks cannot be made. + *
If the system tries to acquire a large number of Rows all at once, the upper limit of the communication buffer size managed by the GridDB node may be reached, possibly resulting in a failure. Refer to "System limiting values" in the Appendix of GridDB API Reference for the upper limit size. + *

+ * @type {object.} + * @param {object.} predicateEntry - The column of condition entry consisting of a combination of the target Container name and the acquisition condition. It consists of the array of RowKeyPredicate. + * @returns {object.} dict-type data consisting of container name and the list of Row. + */ multiGet(predicateEntry) { var this_ = this; + var inputPredEntry = {}; + if (!predicateEntry || typeof predicateEntry != 'object') { + return new Promise(function(resolve, reject) { + setTimeout(function() { + try { + return resolve(this_.store.multiGet(predicateEntry)); + } catch(err) { + reject(convertToGSException(err)); + } + }, 0); + }); + } + var error = false; + Object.keys(predicateEntry).forEach(key => { + var value = predicateEntry[key]; + if (value && typeof value == 'object' && value.hasOwnProperty('rowKeyPredicate')) { + inputPredEntry[key] = value.rowKeyPredicate; + } else { + error = true; + } + }); + if (error) { + return Promise.reject(new Error('Invalid input of multiGet')) + } return new Promise(function(resolve, reject) { setTimeout(function() { try { - return resolve(this_.store.multiGet(predicateEntry)); + return resolve(this_.store.multiGet(inputPredEntry)); } catch(err) { reject(convertToGSException(err)); } @@ -158,12 +349,56 @@ class Store { }); } - close(allRelated = false) { + /** + *

+ * Creates a matching condition with the specified Type as the type of Row key. + *
The target Container must have a Row key, and it must be the same type as the specified Type. + *
The type of Row key that can be set must be the same type that is allowed by the individual Container type derived from Container. + *

+ * @type {Promise} + * @param {Type} type - The type of Row key used as a matching condition. + * @returns {Promise} RowKeyPredicate instance + */ + createRowKeyPredicate(type) { + try { + return new RowKeyPredicate(this.store.createRowKeyPredicate(type)); + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Creates a matching condition with the specified Type as the type of Row key. + *
The target Container must have a Row key, and it must be the same type as the specified Type. + *
The type of Row key that can be set must be the same type that is allowed by the individual Container type derived from Container. + *

+ * @type {RowKeyPredicate} + * @param {Type} type - The type of Row key used as a matching condition. + * @returns {RowKeyPredicate} RowKeyPredicate instance + */ + createRowKeyPredicateSync(type) { + try { + return new RowKeyPredicate(this.store.createRowKeyPredicate(type)); + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Disconnects with GridDB and releases related resources as necessary. + *

+ * @type {Promise} + * @param {boolean} allRelated=false - In the current version, this parameter does not affect the result. + * @returns {Promise} + */ + close() { var this_ = this; return new Promise(function(resolve, reject) { setTimeout(function() { try { - resolve(this_.store.close(allRelated)); + resolve(this_.store.close(false)); } catch(err) { reject(convertToGSException(err)); } @@ -171,43 +406,167 @@ class Store { }); } - // Sync functions - createRowKeyPredicate(type) { - try { - return this.store.createRowKeyPredicate(type); - } catch(err) { - throw(convertToGSException(err)); - } - } - - closeSync(allRelated = false) { + /** + *

+ * Disconnects with GridDB and releases related resources as necessary. + *

+ * @type {void} + * @param {boolean} allRelated=false - In the current version, this parameter does not affect the result. + * @returns {void} + */ + closeSync() { try { - this.store.close(allRelated); + this.store.close(false); } catch(err) { throw(convertToGSException(err)); } } - }; +/** + *

CProvides management functions for sets of row having same type. + *
Each column in GridDB schema is defined by a ContainerInfo. Each container consists of one or more columns. + *
Mapping table between column type and value in a row object is following: + *

+ *

+ * + * + * + * + * + * + * + * + * + * + * + * + *
(Column) TypestringbooleannumberDateBuffer
STRINGmapped
BOOL mappedmapped
BYTE mapped
SHORT mapped
INTEGER mapped
LONG mapped
FLOAT mapped
DOUBLE mapped
TIMESTAMPmapped mappedmapped
BLOB mapped
+ *

+ *

+ *

+ * TIMESTAMP represents milliseconds since the UNIX epoch (January 1, 1970 00:00:00 UTC) with long type. + *
TIMESTAMP value suports msec. Range of time is from 1/1/1970 to 12/31/9999 (UTC). + * There may be more limitation depending on a GridDB cluster configuration. Cannot store a value out of the range. + *
There is an upper limit for the number of column and the length of column name. + * The value has limitations for rage and size. Please refer to appendix of GridDB API Reference for more detail. + * Cannot store a value exceeding these limitations. + *
A limitation about a row key type, presence of column corresponding to a row key, + * and availability of row value updates, may differ for each type derived from the container type. + *
NULL in GridDB rows can be retained unless the NOT NULL constraint is set. + * NOT NULL constraint can be set with columnInfoList object in ContainerInfo when put_container() is called. + *
About transaction, auto commit mode is active as a default. + * In the auto commit mode, each transaction is processed sequentially, and cannot be canceled. + * For manual commit mode, transactions before a commit is canceled if there is an error on a cluster node during the transaction via Container instances. + * Transaction isolation level supports only READ COMMITTED. Lock granularity may differ for each container type. + *
When a row is updated, added, deleted, and got a lock for updates, a transaction is generated internally. + * This transaction has a valid period. + * After some period defined by GridDB is passed from the timing of this transaction for Container instance, any same type of transactions will be not accepted. + *

+ * @type {object} + * @alias Container + * @property {ContainerType} type=0 - Container type + */ class Container { - constructor(container) { + constructor(container, store) { this.container = container; + //need reference to avoid gc + this.store = store; } + /** + *

+ * Get type of Container + *

+ * @type {ContainerType} + * @returns {ContainerType} Type of Container + */ get type() { return this.container.type; } + /** + *

+ * Set type for Container + *

+ * @type {void} + * @param {ContainerType} value - Type of Container + * @returns {void} + */ + set type(value) { + try { + this.container.type = value; + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Set output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {void} + * @param {boolean} value - enable timestamp ouput float + * @returns {void} + */ set timestampOutput(value) { this.container.timestampOutput = value; } + /** + *

+ * Get output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {boolean} + * @returns {boolean} PartitionController instance + */ get timestampOutput() { return this.container.timestampOutput; } - // Async functions + //query(strQuery) { + // var this_ = this; + // return new Promise(function(resolve, reject) { + // setTimeout(function() { + // try { + // var query = this_.container.query(strQuery); + // resolve(new Query(query)); + // } catch(err) { + // reject(convertToGSException(err)); + // } + // }, 0); + // }); + //} + + /** + *

+ * Creates a query to execute the specified TQL statement. + *

+ * @type {Query} + * @param {string} query - TQL statement. + * @returns {Query} Query instance + */ + query(strQuery) { + try { + return new Query(this.container.query(strQuery), this); + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Newly creates or update a Row. + *
If a Column exists which corresponds to the specified Row key, it determines whether to newly create or update a Row, based on the Row key and the state of the Container. If there is no corresponding Row in the Container, it determines to newly create a Row; otherwise, it updates a relevant Row. + *
If no Column exists which corresponds to the specified Row key, it always creates a new Row. + *
In the manual commit mode, the target Row is locked. + *

+ * @type {Promise} + * @param {object[]} row=null - A list object representing the content of a Row to be newly created or updated. + * @returns {Promise} True if a Row exists + */ put(arr) { var this_ = this; return new Promise(function(resolve, reject) { @@ -221,6 +580,15 @@ class Container { }); } + /** + *

+ * Returns the content of a Row corresponding to Row key. + *

+ * @type {Promise} + * @param {object} key - Row key to be processed + * @param {boolean} forUpdate - Indicates whether it requests a lock for update or not + * @returns {Promise} The list object representing the content of a Row to be obtained + */ get(key) { var this_ = this; return new Promise(function(resolve, reject) { @@ -235,6 +603,15 @@ class Container { }); } + /** + *

+ * Removes a Row corresponding to Row key. + *
In the manual commit mode, the target Row is locked. + *

+ * @type {Promise} + * @param {object} key - Row key to be processed + * @returns {Promise} A boolean-type value which can be used to identify whether the target Row exists or not. + */ remove(key) { var this_ = this; return new Promise(function(resolve, reject) { @@ -248,6 +625,22 @@ class Container { }); } + /** + *

+ * Creates a specified type of index on the specified Column. + *
Named index can be set with name parameter. + *
No index cannot be set on a TimeSeries Row key (TIMESTAMP type). + *
When a transaction is held, uncommitted updates will be rolled back. + *
If an index is already set on the specified Column, nothing is changed. + *
When a transaction(s) is active in a target Container, it creates an index after waiting for the transaction(s) to complete. + *

+ * @type {Promise} + * @param {object} indexInfo - Index information + * @param {string} indexInfo.columnName - Column name to be processed + * @param {IndexType} indexInfo.indexType=DEFAULT - Type of index + * @param {string} indexInfo.name=null - Name of index + * @returns {Promise} + */ createIndex(parameterObj) { var this_ = this; return new Promise(function(resolve, reject) { @@ -261,6 +654,19 @@ class Container { }); } + /** + *

+ * Removes the specified type of index among indexes on the specified Column. + *
Nothing is changed if the specified index is not found. + *
When a transaction(s) is active in a target Container, it removes the index after waiting for the transaction(s) to be completed. + *

+ * @type {Promise} + * @param {object} indexInfo - Index information + * @param {string} indexInfo.columnName - Column name to create index + * @param {IndexType} indexInfo.indexType=DEFAULT - Type of index + * @param {string} indexInfo.name=null - Name of index + * @returns {Promise} + */ dropIndex(parameterObj) { var this_ = this; return new Promise(function(resolve, reject) { @@ -274,6 +680,15 @@ class Container { }); } + /** + *

+ * Writes the results of earlier updates to a non-volatile storage medium, such as SSD, so as to prevent the data loss even if all cluster nodes stop suddenly. + *
It can be used for operations which require higher reliability than usual. However, frequent execution of this operation would potentially cause degradation in response time. + *
The details of behavior, such as the scope of cluster nodes which are the data export targets, will be changed depending on the configuration of GridDB. + *

+ * @type {Promise} + * @returns {Promise} + */ flush() { var this_ = this; return new Promise(function(resolve, reject) { @@ -287,6 +702,13 @@ class Container { }); } + /** + *

+ * Rolls back the result of the current transaction and starts a new transaction in the manual commit mode. + *

+ * @type {Promise} + * @returns {Promise} + */ abort() { var this_ = this; return new Promise(function(resolve, reject) { @@ -300,6 +722,13 @@ class Container { }); } + /** + *

+ * Commits the result of the current transaction and start a new transaction in the manual commit mode. + *

+ * @type {Promise} + * @returns {Promise} + */ commit() { var this_ = this; return new Promise(function(resolve, reject) { @@ -313,6 +742,32 @@ class Container { }); } + /** + *

+ * Change the setting of the commit mode. + *
In the auto commit mode, the transaction state cannot be controlled directly and change operations are committed sequentially. If the auto commit mode is disabled, i.e. in the manual commit mode, as long as the transaction has not timed out or commit() has been invoked directly, the same transaction will continue to be used in this Container and change operations will not be committed. + *
When the auto commit mode is switched from disabled to enabled, uncommitted updates are committed implicitly. Unless the commit mode is changed, the state of the transaction will not be changed. + *

+ * @type {void} + * @param {boolean} enabled - Indicates whether it enables auto commit mode or not. if True, auto commit mode is enabled. if False, manual commit mode is enabled. + */ + setAutoCommit(commitFlg) { + try { + this.container.setAutoCommit(commitFlg); + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Newly creates an arbitrary number of Rows together based on the specified Row objects group. + *
In the manual commit mode, the target Row is locked. + *

+ * @type {Promise} + * @param {object[][]} rowList - List object corresponding to contents of newly created Row collection + * @returns {Promise} + */ multiPut(rowList) { var this_ = this; return new Promise(function(resolve, reject) { @@ -326,6 +781,13 @@ class Container { }); } + /** + *

+ * Disconnects with GridDB and releases related resources as necessary. + *

+ * @type {Promise} + * @returns {Promise} + */ close() { var this_ = this; return new Promise(function(resolve, reject) { @@ -339,23 +801,13 @@ class Container { }); } - // Sync functions - query(strQuery) { - try { - return new Query(this.container.query(strQuery)); - } catch(err) { - throw(convertToGSException(err)); - } - } - - setAutoCommit(commitFlg) { - try { - this.container.setAutoCommit(commitFlg); - } catch(err) { - reject(convertToGSException(err)); - } - } - + /** + *

+ * Disconnects with GridDB and releases related resources as necessary. + *

+ * @type {void} + * @returns {void} + */ closeSync() { try { this.container.close(); @@ -365,18 +817,37 @@ class Container { } }; +/** + *

+ * Provides the functions of holding the information about a query related to a specific Container, specifying the options for fetching and retrieving the result. + *

+ * @alias Query + * @type {object} + */ class Query { - constructor(query) { + constructor(query, container) { this.query = query; + //Need reference to avoid gc + this.container = container; } - // Async functions + + /** + *

+ * It locks all target Rows if True is specified as forUpdate . If the target Rows are locked, update operations on the Rows by any other transactions are blocked while a relevant transaction is active. True can be specified only if the auto commit mode is disabled on a relevant Container. + *
When new set of Rows are obtained, any Row operation via RowSet as the last result of specified query is prohibited. + *
If the system tries to acquire a large number of Rows all at once, the upper limit of the communication buffer size managed by the GridDB node may be reached, possibly resulting in a failure. Refer to "System limiting values" in the Appendix of GridDB API Reference for the upper limit size. + *

+ * @type {Promise} + * @returns {Promise} RowSet instance + */ fetch() { var this_ = this; + var forUpdate = false; return new Promise(function(resolve, reject) { setTimeout(function() { try { - var rowSet = this_.query.fetch(false); - resolve(new RowSet(rowSet)); + var rowSet = this_.query.fetch(forUpdate); + resolve(new RowSet(rowSet, this_)); } catch(err) { reject(convertToGSException(err)); } @@ -384,6 +855,13 @@ class Query { }); } + /** + *

+ * Releases related resources properly. + *

+ * @type {Promise} + * @returns {Promise} + */ close() { var this_ = this; return new Promise(function(resolve, reject) { @@ -397,15 +875,31 @@ class Query { }); } - // Sync functions + /** + *

+ * Returns RowSet as the latest result. + *
Once RowSet is returned, it cannot be obtained until the new query is executed. + *

+ * @type {RowSet} + * @returns {RowSet} RowSet instance as the latest result + */ getRowSet() { try { - return new RowSet(this.query.getRowSet()); + return new RowSet(this.query.getRowSet(), this); } catch(err) { throw(convertToGSException(err)); } } + /** + *

+ * Sets an fetch options for a result acquisition. + *
Once RowSet is returned, it cannot be obtained until the new query is executed. + *

+ * @type {void} + * @param {object} options - The options for fetching the result of a query + * @param {number} options.limit=null - Used to set the maximum number of Rows to be fetched + */ setFetchOptions(option) { try { this.query.setFetchOptions(option); @@ -414,6 +908,13 @@ class Query { } } + /** + *

+ * Releases related resources properly. + *

+ * @type {void} + * @returns {void} + */ closeSync() { try { this.query.close(); @@ -423,28 +924,94 @@ class Query { } }; +/** + *

+ * Manages a set of Rows obtained by a query. + *
It has a function of per-Row and per-Row-field manipulation and holds a cursor state to specify a target Row. The cursor is initially located just before the head of a Row set. + *

+ * @type {object} + * @alias RowSet + * @property {RowSetType} type=CONTAINER_ROWS - The type of content that can be extracted from RowSet. (Read-only attribute) + * @property {number} size=null - The size of Row set. (Read-only attribute) + */ class RowSet { - constructor(rowSet) { + constructor(rowSet, query) { this.rowSet = rowSet; + //Need reference to avoid gc + this.query = query; } + /** + *

+ * Get size of row set + *
The number of Row when a Row set is created + *

+ * @type {number} + * @returns {number} The size of row set + */ get size() { return this.rowSet.size; } + set size(value) { + try { + this.rowSet.size = value; + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Get type of row set + *

+ * @type {RowSetType} + * @returns {RowSetType} The type of row set + */ get type() { return this.rowSet.type; } + set type(value) { + try { + this.rowSet.type = value; + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Set output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {void} + * @param {boolean} value - enable timestamp ouput float + * @returns {void} + */ set timestampOutput(value) { this.rowSet.timestampOutput = value; } + /** + *

+ * Get output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {boolean} + * @returns {boolean} PartitionController instance + */ get timestampOutput() { return this.rowSet.timestampOutput; } - // Async functions + /** + *

+ * Releases related resources as necessary. + *

+ * @type {Promise} + * @returns {Promise} + */ close() { var this_ = this; return new Promise(function(resolve, reject) { @@ -458,8 +1025,15 @@ class RowSet { }); } - // Sync functions + /** + *

+ * Moves the cursor to the next Row in a Row set and returns the Row object at the moved position. + *

+ * @type {object} + * @returns {object[] | AggregationResult | QueryAnalysisEntry} The object that can be extracted from RowSet. + */ next() { + var this_ = this; switch(this.type) { case griddb.GS_ROW_SET_CONTAINER_ROWS: try { @@ -470,24 +1044,33 @@ class RowSet { break; case griddb.GS_ROW_SET_AGGREGATION_RESULT: try { - return new AggregationResult(this.rowSet.next()); + return new AggregationResult(this.rowSet.next(),this_); } catch(err) { throw(convertToGSException(err)); } break; case griddb.GS_ROW_SET_QUERY_ANALYSIS: try { - return new QueryAnalysisEntry(this.rowSet.next()); + return new QueryAnalysisEntry(this.rowSet.next(), this_); } catch(err) { throw(convertToGSException(err)); } break; + default: throw "Invalid Rowset type"; break; } + } + /** + *

+ * Returns whether a Row set has at least one Row ahead of the current cursor position. + *

+ * @type {boolean} + * @returns {boolean} True if a Row exists ahead of the current cursor position + */ hasNext() { try { return this.rowSet.hasNext(); @@ -496,6 +1079,12 @@ class RowSet { } } + /** + *

+ * Releases related resources as necessary. + *

+ * @type {void} + */ closeSync() { try { this.rowSet.close(); @@ -505,19 +1094,56 @@ class RowSet { } } +/** + *

+ * Stores the result of an aggregation operation. + *
The type of the stored result depends on the type of aggregation operation and the type of the target Columns. + * For specific rules, see the TQL specifications. + *
The type of obtaining value depends on the stored type. + * Float type and long type are only available when a result is of numeric type, and datetime type when a result is of TIMESTAMP type. + *

+ * @type {object} + * @alias AggregationResult + */ class AggregationResult { - constructor(aggResult) { + constructor(aggResult, store) { this.aggResult = aggResult; + //need reference to avoid gc + this.store = store; } + + /** + *

+ * Set output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {void} + * @param {boolean} value - enable timestamp ouput float + * @returns {void} + */ set timestampOutput(value) { this.aggResult.timestampOutput = value; } + /** + *

+ * Get output type for row field timestamp. + *
The default of output timestsamp is datatime. + *

+ * @type {boolean} + * @returns {boolean} PartitionController instance + */ get timestampOutput() { return this.aggResult.timestampOutput; } - // Sync function + /** + *

+ * Returns the aggregation result as the value with specified type. + *

+ * @param {Type} type - Column type + * @returns {object} The aggregation result + */ get(type) { try { return this.aggResult.get(type); @@ -527,12 +1153,27 @@ class AggregationResult { } } +/** + *

+ * Represents one of information entries composing a query plan and the results of analyzing a query operation. + *

+ * @type {object} + * @alias QueryAnalysisEntry + */ class QueryAnalysisEntry { - constructor(queryAnalysis) { + constructor(queryAnalysis, store) { this.queryAnalysis = queryAnalysis; + //need reference to avoid gc + this.store = store; } - // Sync function + /** + *

+ * Returns one of information entries composing a query plan and the results of analyzing a query operation. + *

+ * @type {Array} + * @returns {Array} Query plan and the results of analyzing a query operation + */ get() { try { return this.queryAnalysis.get(); @@ -542,14 +1183,51 @@ class QueryAnalysisEntry { } } +/** + *

+ * Controller for acquiring and processing the partition status. + *
A partition is a theoretical region where data is stored. It is used to perform operations based on the data arrangement in a GridDB cluster. + *

+ * @type {object} + * @alias PartitionController + * @property {number} partitionCount=null - The number of partitions in the target GridDB cluster. (Read-only attribute) + */ class PartitionController { - constructor(partitionController) { + constructor(partitionController, store) { this.partitionController = partitionController; + //need reference to avoid gc + this.store = store; } + + /** + *

+ * Get partition count + *
Get the number of partitions in the target GridDB cluster. + *

+ * @type {number} + * @returns {number} The number of partitions in the target GridDB cluster + */ get partitionCount() { return this.partitionController.partitionCount; } - // Async function + + set partitionCount(count) { + try { + this.partitionController.partitionCount = count; + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Get the total number of containers belonging to a specified partition. + *
The calculated quantity when determining the number of containers is generally not dependent on the number of containers. + *

+ * @type {Promise} + * @param {number} partitionIndex - The partition index, from 0 to the number of partitions minus one + * @returns {Promise} The number of Container + */ getContainerCount(partitionIndex) { var this_ = this; return new Promise(function(resolve, reject) { @@ -562,6 +1240,19 @@ class PartitionController { }, 0); }); } + + /** + *

+ * Get a list of the Container names belonging to a specified partition. + *
For the specified partition, the sequence of the list of acquisition results before and after will not be changed when the relevant Container is excluded even if a Container is newly created, its composition changed or the Container is deleted. All other lists are compiled in no particular order. No duplicate names will be included. + *
If the upper limit of the number of acquisition cases is specified, the cases will be cut off starting from the ones at the back if the upper limit is exceeded. If no relevant specified condition exists, a blank list is returned. + *

+ * @type {Promise} + * @param {number} partitionIndex - The partition index, from 0 to the number of partitions minus one + * @param {number} start - The start position of the acquisition range. A value must be greater than or equal to 0 + * @param {number} limit - The upper limit of the number of cases acquired. It is optional. If not specified or limit < 0, it is considered as no upper limit. + * @returns {Promise} The list of Container name + */ getContainerNames(partitionIndex, start, limit) { var this_ = this; return new Promise(function(resolve, reject) { @@ -574,6 +1265,17 @@ class PartitionController { }, 0); }); } + + /** + *

+ * Get the partition index corresponding to the specified Container name. + *
Once a GridDB cluster is constructed, there will not be any changes in the partitions of the destination that the Container belongs to and the partition index will also be fixed. Whether there is a Container corresponding to the specified name or not does not depend on the results. + *
Information required in the computation of the partition index is cached and until the next cluster failure and cluster node failure is detected, no inquiry will be sent to the GridDB cluster again. + *

+ * @type {Promise} + * @param {string} containerName - Container name + * @returns {Promise} The partition index + */ getPartitionIndexOfContainer(containerName) { var this_ = this; return new Promise(function(resolve, reject) { @@ -586,6 +1288,14 @@ class PartitionController { }, 0); }); } + + /** + *

+ * The connection status with GridDB is released and related resources are released where necessary. + *

+ * @type {Promise} + * @returns {Promise} + */ close() { var this_ = this; return new Promise(function(resolve, reject) { @@ -599,7 +1309,12 @@ class PartitionController { }); } - // Sync function + /** + *

+ * The connection status with GridDB is released and related resources are released where necessary. + *

+ * @type {void} + */ closeSync() { try { this.partitionController.close(); @@ -609,15 +1324,54 @@ class PartitionController { } } +/** + *

+ * Represents the condition that a row key satisfies. + *
This is used as the search condition in Store.multiGet(). + *
There are two types of conditions, range condition and individual condition. The two types of conditions cannot be specified at the same time. If the condition is not specified, it means that the condition is satisfied in all the target row keys. + *

+ * @type {object} + * @alias RowKeyPredicate + * @property {Type} keyType - The type of Row key used as a search condition. (Read-only attribute) + */ class RowKeyPredicate { constructor(rowKeyPredicate) { this.rowKeyPredicate = rowKeyPredicate; } + + /** + *

+ * Get type of RowkeyPredicate + *

+ * @type {Type} + * @returns {Type} The type of RowkeyPredicate + */ get keyType() { return this.rowKeyPredicate.keyType; } - // Sync function + /** + *

+ * Set type of RowkeyPredicate + *

+ * @type {void} + * @param {number} value - Type of RowkeyPredicate + */ + set keyType(value) { + try { + this.rowKeyPredicate.keyType = value; + } catch(err) { + throw(convertToGSException(err)); + } + } + + /** + *

+ * Returns the value of Row key at the start and end position of the range condition. + *

+ * @type {Array.} + * @returns {Array.} The value of Row key at the start and end position of the range condition + */ getRange() { try { return this.rowKeyPredicate.getRange(); @@ -625,6 +1379,15 @@ class RowKeyPredicate { throw(convertToGSException(err)); } } + + /** + *

+ * Sets the value of Row key as the start and end position of the range conditions. + *

+ * @type {void} + * @param {object} start - The value of the Row key as the start position + * @param {object} end - The value of the Row key as the end position + */ setRange(start, end) { try { this.rowKeyPredicate.setRange(start, end); @@ -632,6 +1395,14 @@ class RowKeyPredicate { throw(convertToGSException(err)); } } + + /** + *

+ * Returns a list of the values of the Row keys that configure the individual condition. + *

+ * @type {void} + * @param {object[]} keys - List of the elements in the individual condition + */ setDistinctKeys(keys) { try { this.rowKeyPredicate.setDistinctKeys(keys); @@ -639,6 +1410,14 @@ class RowKeyPredicate { throw(convertToGSException(err)); } } + + /** + *

+ * Sets list of the elements in the individual condition. + *

+ * @type {Array.} + * @returns {object[]} List of the values of the Row keys that configure the individual condition + */ getDistinctKeys() { try { return this.rowKeyPredicate.getDistinctKeys(); @@ -648,18 +1427,42 @@ class RowKeyPredicate { } } +/** + *

+ * Represents the exception for GridDB. + *

+ * @type {object} + * @alias GSException + * @property {boolean} isTimeout=false - Read-only attribute to determine whether the result of the requested process shows the error code corresponding to the error that occurred when the requested process is not completed within a predetermined time + */ class GSException{ constructor(exception) { this.exception = exception; } - // Sync function + + /** + *

+ * Determine whether the result of the requested process shows the error code corresponding to the error that occurred when the requested process is not completed within a predetermined time. + *

+ * @type {boolean} + * @returns {boolean} Indicates whether the corresponding error code or not + */ isTimeout() { try { - return this.exception.isTimeout(); + return this.exception.isTimeout; } catch(err) { throw(convertToGSException(err)); } } + + /** + *

+ * Returns the stack size of last error information related to this resource. + *
Error information has become a stack structure. A large stack number corresponds to the more direct cause of the error. + *

+ * @type {number} + * @returns {number} The stack size. 0 is returned if corresponding information can not be obtained + */ getErrorStackSize() { try { return this.exception.getErrorStackSize(); @@ -667,6 +1470,16 @@ class GSException{ throw(convertToGSException(err)); } } + + /** + *

+ * Returns the error code of last error related to this resource. + *
0 indicates the successful execution for GridDB instructions. + *

+ * @type {number} + * @param {number} stackIndex - The index of error stack. A valid result will be returned only if a value which has more than 0 and less than the stack size is specified. + * @returns {number} The error code + */ getErrorCode(stackIndex) { try { return this.exception.getErrorCode(stackIndex); @@ -674,6 +1487,15 @@ class GSException{ throw(convertToGSException(err)); } } + + /** + *

+ * Returns the message of last error related to this resource. + *

+ * @type {string} + * @param {number} stackIndex - The index of error stack. A valid result will be returned only if a value which has more than 0 and less than the stack size is specified. + * @returns {string} The error message + */ getMessage(stackIndex) { try { return this.exception.getMessage(stackIndex); @@ -681,13 +1503,31 @@ class GSException{ throw(convertToGSException(err)); } } - getLocation() { + + /** + *

+ * Returns the error location of the internal module to the message of last error related to this resource. + *
It might always return empty string depending on the settings. + *

+ * @type {string} + * @param {number} stackIndex - The index of error stack. A valid result will be returned only if a value which has more than 0 and less than the stack size is specified. + * @returns {string} The string to store the error location information. + */ + getLocation(stackIndex) { try { return this.exception.getLocation(stackIndex); } catch(err) { throw(convertToGSException(err)); } } + + /** + *

+ * Returns the message include error code and error message + *

+ * @type {string} + * @returns {string} The error message and error message + */ what() { try { return this.exception.what(); @@ -695,8 +1535,26 @@ class GSException{ throw(convertToGSException(err)); } } + + /** + *

+ * Disconnects with GridDB and releases related resources as necessary. + *

+ * @type {void} + * @returns {void} + */ + close() { + this.exception.close(); + } } +/** + *

+ * Correct class name GSException. + *

+ * @type {GSException} + * @returns {GSException} GSException instance + */ function convertToGSException(exception) { if (exception.constructor.name == "_exports_GSException") { return new GSException(exception); From a78c7ab74be1fb282798b44d2cf9984abb499feb Mon Sep 17 00:00:00 2001 From: mochizk Date: Fri, 29 Mar 2019 11:36:51 +0900 Subject: [PATCH 6/6] Refactor and fix bugs of cpp files --- src/griddb.i | 13 +- src/gstype.i | 14 +- src/gstype_js_v8.i | 847 +++++++++++++++++++++++---------------------- 3 files changed, 440 insertions(+), 434 deletions(-) diff --git a/src/griddb.i b/src/griddb.i index b46be2d..a6a4212 100644 --- a/src/griddb.i +++ b/src/griddb.i @@ -48,6 +48,10 @@ %feature("new") griddb::Store::partition_info; %feature("new") griddb::StoreFactory::get_store; %feature("new") griddb::StoreFactory::get_instance; +#if defined(SWIGJAVASCRIPT) +//Mark attribute is new object +%feature("new") griddb::Store::partitionInfo; +#endif #if defined(SWIGPYTHON) %include "gstype_python.i" @@ -82,11 +86,6 @@ #include "Store.h" #include "StoreFactory.h" %} -#if !defined(SWIGJAVASCRIPT) -%{ -#include "TimestampUtils.h" -%} -#endif #if defined(SWIGJAVASCRIPT) || defined(SWIGPHP) %{ #include "EnumValue.h" @@ -99,6 +98,7 @@ %shared_ptr(griddb::TimeSeriesProperties) %shared_ptr(griddb::ExpirationInfo) %shared_ptr(griddb::ContainerInfo) +%shared_ptr(griddb::Row) %shared_ptr(griddb::QueryAnalysisEntry) %shared_ptr(griddb::RowSet) %shared_ptr(griddb::Query) @@ -123,9 +123,6 @@ %include "RowKeyPredicate.h" %include "Store.h" %include "StoreFactory.h" -#if !defined(SWIGJAVASCRIPT) -%include "TimestampUtils.h" -#endif #if defined(SWIGJAVASCRIPT) || defined(SWIGPHP) %include "EnumValue.h" #endif diff --git a/src/gstype.i b/src/gstype.i index d4ef836..ac3eeb7 100644 --- a/src/gstype.i +++ b/src/gstype.i @@ -75,11 +75,8 @@ enum GSTypeTag { GS_TYPE_LONG_ARRAY, GS_TYPE_FLOAT_ARRAY, GS_TYPE_DOUBLE_ARRAY, - GS_TYPE_TIMESTAMP_ARRAY - -#if GS_COMPATIBILITY_SUPPORT_3_5 + GS_TYPE_TIMESTAMP_ARRAY, GS_TYPE_NULL = -1 -#endif }; #endif @@ -97,15 +94,11 @@ enum GSFetchOptionTag { GS_FETCH_LIMIT, -#if GS_COMPATIBILITY_SUPPORT_1_5 - #if GS_INTERNAL_DEFINITION_VISIBLE #if !GS_COMPATIBILITY_DEPRECATE_FETCH_OPTION_SIZE GS_FETCH_SIZE = (GS_FETCH_LIMIT + 1) #endif -#endif - #endif }; @@ -132,12 +125,9 @@ enum GSTypeOptionTag { GS_TYPE_OPTION_KEY = 1 << 0, -#if GS_COMPATIBILITY_SUPPORT_3_5 GS_TYPE_OPTION_NULLABLE = 1 << 1, - GS_TYPE_OPTION_NOT_NULL = 1 << 2, -#endif - + GS_TYPE_OPTION_NOT_NULL = 1 << 2 }; typedef int32_t GSTypeOption; diff --git a/src/gstype_js_v8.i b/src/gstype_js_v8.i index 7d9a6c3..db17590 100644 --- a/src/gstype_js_v8.i +++ b/src/gstype_js_v8.i @@ -38,6 +38,7 @@ %ignore griddb::RowKeyPredicate::setOutputTimestamp; %ignore griddb::RowSet::setOutputTimestamp; %ignore griddb::Store::setOutputTimestamp; +%ignore ColumnInfoList; /* * Use attribute in Nodejs @@ -58,15 +59,17 @@ %attribute(griddb::RowSet, GSRowSetType, type, type); //Read only attribute Store::partition_info %attribute(griddb::Store, griddb::PartitionController*, partitionInfo, partition_info); + //Read only attribute ContainerInfo::name %attribute(griddb::ContainerInfo, GSChar*, name, get_name, set_name); //Read only attribute ContainerInfo::type %attribute(griddb::ContainerInfo, GSContainerType, type, get_type, set_type); -//Read only attribute ContainerInfo::rowKey +//Read only attribute ContainerInfo::rowKey %attribute(griddb::ContainerInfo, bool, rowKey, get_row_key_assigned, set_row_key_assigned); -//Read only attribute ContainerInfo::columnInfoList +//Read only attribute ContainerInfo::column_info_list %attributeval(griddb::ContainerInfo, ColumnInfoList, columnInfoList, get_column_info_list, set_column_info_list); //Read only attribute ContainerInfo::expiration +//%attributeval(griddb::ContainerInfo, griddb::ExpirationInfo, expiration, get_expiration_info, set_expiration_info); %attribute(griddb::ContainerInfo, griddb::ExpirationInfo*, expiration, get_expiration_info, set_expiration_info); //Read only attribute ExpirationInfo::time %attribute(griddb::ExpirationInfo, int, time, get_time, set_time); @@ -79,7 +82,7 @@ * Typemaps for catch GSException */ %typemap(throws) griddb::GSException %{ - SWIGV8_THROW_EXCEPTION(SWIG_V8_NewPointerObj(SWIG_as_voidptr(new griddb::GSException(&$1)), $descriptor(griddb::GSException *), SWIG_POINTER_OWN)); + SWIGV8_THROW_EXCEPTION(SWIG_V8_NewPointerObj(SWIG_as_voidptr(new (nothrow) griddb::GSException(&$1)), $descriptor(griddb::GSException *), SWIG_POINTER_OWN | 0)); %} %fragment("convertFieldToObject", "header", fragment = "convertTimestampToObject") { @@ -92,11 +95,12 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b case GS_TYPE_LONG: return SWIGV8_NUMBER_NEW(value->asLong); case GS_TYPE_STRING: + if (value->asString == NULL) { + return SWIGV8_NULL(); + } return SWIGV8_STRING_NEW(value->asString); -%#if GS_COMPATIBILITY_SUPPORT_3_5 case GS_TYPE_NULL: return SWIGV8_NULL(); -%#endif case GS_TYPE_BLOB: return Nan::CopyBuffer((char *)value->asBlob.data, value->asBlob.size).ToLocalChecked(); case GS_TYPE_BOOL: @@ -114,16 +118,14 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b case GS_TYPE_SHORT: return SWIGV8_INT32_NEW(value->asShort); case GS_TYPE_GEOMETRY: + if (value->asGeometry == NULL) { + return SWIGV8_NULL(); + } return SWIGV8_STRING_NEW(value->asGeometry); case GS_TYPE_INTEGER_ARRAY: { const int32_t *intArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asIntegerArray.size; - intArrVal = value->asIntegerArray.elements; -%#else size = value->asArray.length; intArrVal = value->asArray.elements.asInteger; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIG_From_int(intArrVal[i])); @@ -132,13 +134,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_STRING_ARRAY: { const GSChar *const *stringArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asStringArray.size; - stringArrVal = value->asStringArray.elements; -%#else size = value->asArray.length; stringArrVal = value->asArray.elements.asString; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIGV8_STRING_NEW((GSChar *)stringArrVal[i])); @@ -147,13 +144,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_BOOL_ARRAY: { const GSBool *boolArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asBoolArray.size; - boolArrVal = field.value.asBoolArray.elements; -%#else size = value->asArray.length; boolArrVal = value->asArray.elements.asBool; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIG_From_bool(boolArrVal[i])); @@ -162,13 +154,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_BYTE_ARRAY: { const int8_t *byteArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asByteArray.size; - byteArrVal = value->asByteArray.elements; -%#else size = value->asArray.length; byteArrVal = value->asArray.elements.asByte; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIG_From_int(byteArrVal[i])); @@ -177,13 +164,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_SHORT_ARRAY: { const int16_t *shortArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asShortArray.size; - shortArrVal = value->asShortArray.elements; -%#else size = value->asArray.length; shortArrVal = value->asArray.elements.asShort; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIG_From_int(shortArrVal[i])); @@ -192,13 +174,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_LONG_ARRAY: { const int64_t *longArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asLongArray.size; - longArrVal = value->asLongArray.elements; -%#else size = value->asArray.length; longArrVal = value->asArray.elements.asLong; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIGV8_NUMBER_NEW(longArrVal[i])); @@ -207,13 +184,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_FLOAT_ARRAY: { const float *floatArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asFloatArray.size; - floatArrVal = value->asFloatArray.elements; -%#else size = value->asArray.length; floatArrVal = value->asArray.elements.asFloat; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIGV8_NUMBER_NEW(((float *)floatArrVal)[i])); @@ -222,13 +194,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_DOUBLE_ARRAY: { const double *doubleArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asDoubleArray.size; - doubleArrVal = value->asDoubleArray.elements; -%#else size = value->asArray.length; doubleArrVal = value->asArray.elements.asDouble; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, SWIGV8_NUMBER_NEW(((double *)doubleArrVal)[i])); @@ -237,13 +204,8 @@ static v8::Handle convertFieldToObject(GSValue* value, GSType type, b } case GS_TYPE_TIMESTAMP_ARRAY: { const GSTimestamp *timestampArrVal; -%#if GS_COMPATIBILITY_VALUE_1_1_106 - size = value->asTimestampArray.size; - timestampArrVal = value->asTimestampArray.elements; -%#else size = value->asArray.length; timestampArrVal = value->asArray.elements.asTimestamp; -%#endif list = SWIGV8_ARRAY_NEW(); for (i = 0; i < size; i++) { list->Set(i, convertTimestampToObject((GSTimestamp*)&(timestampArrVal[i]), timestampToFloat)); @@ -266,11 +228,11 @@ static void cleanStringArray(GSChar** arrString, size_t size) { for (int i = 0; i < size; i++) { if (arrString[i]) { - free((void*)arrString[i]); + delete[] arrString[i]; } } - free(arrString); + delete[] arrString; } } @@ -289,8 +251,10 @@ static GSChar** convertObjectToStringArray(v8::Local value, int* size arraySize = (int) arr->Length(); *size = (int)arraySize; - arrString = (GSChar**) malloc(arraySize * sizeof(GSChar*)); - if (arrString == NULL) { + + try { + arrString = new GSChar*[arraySize](); + } catch (std::bad_alloc& ba) { return NULL; } @@ -308,7 +272,7 @@ static GSChar** convertObjectToStringArray(v8::Local value, int* size } if (v) { - arrString[i] = strdup(v); + griddb::Util::strdup((const GSChar**)(&arrString[i]), v); cleanString(v, alloc); } } @@ -367,7 +331,7 @@ static void cleanString(const GSChar* string, int alloc){ return; } - if (alloc == SWIG_NEWOBJ) { + if (string && alloc == SWIG_NEWOBJ) { delete [] string; } } @@ -407,25 +371,12 @@ static bool convertObjectToLong(v8::Local value, int64_t* longVal) { */ %fragment("convertObjectToDouble", "header") { static bool convertObjectToDouble(v8::Local value, double* floatValPtr) { - int checkConvert = 0; - if (value->IsInt32()) { - //input can be integer - long int intVal; - checkConvert = SWIG_AsVal_long(value, &intVal); - if (!SWIG_IsOK(checkConvert)) { - return false; - } - *floatValPtr = intVal; - //When input value is integer, it should be between -9007199254740992(-2^53)/9007199254740992(2^53). - return (-9007199254740992 <= intVal && 9007199254740992 >= intVal); - } else { - //input is float - if (!(value->IsNumber())) { - return false; - } - *floatValPtr = value->NumberValue(); - return true; + //input is float + if (!(value->IsNumber())) { + return false; } + *floatValPtr = value->NumberValue(); + return true; } } /** @@ -434,29 +385,13 @@ static bool convertObjectToDouble(v8::Local value, double* floatValPt */ %fragment("convertObjectToFloat", "header") { static bool convertObjectToFloat(v8::Local value, float* floatValPtr) { - int checkConvert = 0; - - if (value->IsInt32()) { - //input can be integer - long int intVal; - checkConvert = SWIG_AsVal_long(value, &intVal); - if (!SWIG_IsOK(checkConvert)) { - return false; - } - *floatValPtr = intVal; - //When input value is integer, it should be between -16777216(-2^24)/16777216(2^24). - return (-16777216 <= intVal && 16777216 >= intVal); - - } else { - //input is float - if (!(value->IsNumber())) { - return false; - } - *floatValPtr = value->NumberValue(); - - return (*floatValPtr <= std::numeric_limits::max() && - *floatValPtr >= -1 *std::numeric_limits::max()); + if (!(value->IsNumber())) { + return false; } + *floatValPtr = value->NumberValue(); + + return (*floatValPtr <= std::numeric_limits::max() && + *floatValPtr >= -1 *std::numeric_limits::max()); } } /** @@ -527,7 +462,7 @@ static bool convertToRowKeyFieldWithType(griddb::Field &field, v8::LocalIsString()) { return false; } @@ -536,22 +471,22 @@ static bool convertToRowKeyFieldWithType(griddb::Field &field, v8::LocalIsInt32()) { return false; } field.value.asInteger = value->IntegerValue(); break; - case GS_TYPE_LONG: + case (GS_TYPE_LONG): return convertObjectToLong(value, &field.value.asLong); break; - case GS_TYPE_TIMESTAMP: + case (GS_TYPE_TIMESTAMP): return convertObjectToGSTimestamp(value, &field.value.asTimestamp); break; default: @@ -580,13 +515,8 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local v8::Local arr; if (value->IsNull() || value->IsUndefined()) { -%#if GS_COMPATIBILITY_SUPPORT_3_5 ret = gsSetRowFieldNull(row, column); - return (ret == GS_RESULT_OK); -%#else - //Not support NULL - return false; -%#endif + return GS_SUCCEEDED(ret); } int checkConvert = 0; @@ -649,7 +579,7 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } ret = gsSetRowFieldByInteger(row, column, value->IntegerValue()); break; - case GS_TYPE_FLOAT: { + case (GS_TYPE_FLOAT): { float floatVal; vbool = convertObjectToFloat(value, &floatVal); if (!vbool) { @@ -698,14 +628,12 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } size = length; ret = gsSetRowFieldByStringArray(row, column, stringArrVal, size); - if (stringArrVal) { - for (i = 0; i < length; i++) { - if (stringArrVal[i]) { - free(const_cast (stringArrVal[i])); - } + for (i = 0; i < length; i++) { + if (stringArrVal[i]) { + delete[] stringArrVal[i]; } - free(const_cast (stringArrVal)); } + delete[] stringArrVal; break; } case GS_TYPE_GEOMETRY: { @@ -729,20 +657,22 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - intArrVal = (int32_t *) malloc(size * sizeof(int32_t)); - if (intArrVal == NULL) { + + try { + intArrVal = new int32_t[size](); + } catch (std::bad_alloc& ba) { return false; } for (i = 0; i < size; i++) { checkConvert = SWIG_AsVal_int(arr->Get(i), (intArrVal + i)); if (!SWIG_IsOK(checkConvert)) { - free((void*)intArrVal); + delete[] intArrVal; intArrVal = NULL; return false; } } ret = gsSetRowFieldByIntegerArray(row, column, (const int32_t *) intArrVal, size); - free ((void*) intArrVal); + delete[] intArrVal; break; } case GS_TYPE_BOOL_ARRAY: { @@ -752,20 +682,21 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - boolArrVal = (GSBool *) malloc(size * sizeof(GSBool)); - if (boolArrVal == NULL) { + try { + boolArrVal = new GSBool[size](); + } catch (std::bad_alloc& ba) { return false; } for (i = 0; i < size; i++) { vbool = convertObjectToBool(arr->Get(i), (bool*)(boolArrVal + i)); if (!vbool) { - free((void*)boolArrVal); + delete[] boolArrVal; boolArrVal = NULL; return false; } } ret = gsSetRowFieldByBoolArray(row, column, (const GSBool *)boolArrVal, size); - free ((void*) boolArrVal); + delete[] boolArrVal; break; } case GS_TYPE_BYTE_ARRAY: { @@ -775,8 +706,9 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - byteArrVal = (int8_t *) malloc(size * sizeof(int8_t)); - if (byteArrVal == NULL) { + try { + byteArrVal = new int8_t[size](); + } catch (std::bad_alloc& ba) { return false; } for (i = 0; i < size; i++) { @@ -786,13 +718,13 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local tmpInt < std::numeric_limits::min() || tmpInt > std::numeric_limits::max() || (!arr->Get(i)->IsInt32())) { - free((void*)byteArrVal); - byteArrVal = NULL; - return false; + delete[] byteArrVal; + byteArrVal = NULL; + return false; } } ret = gsSetRowFieldByByteArray(row, column, (const int8_t *)byteArrVal, size); - free ((void*) byteArrVal); + delete[] byteArrVal; break; } case GS_TYPE_SHORT_ARRAY: { @@ -802,24 +734,25 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - shortArrVal = (int16_t *) malloc(size * sizeof(int16_t)); - if (shortArrVal == NULL) { + try { + shortArrVal = new int16_t[size](); + } catch (std::bad_alloc& ba) { return false; } for (i = 0; i < size; i++) { checkConvert = SWIG_AsVal_int(arr->Get(i), &tmpInt); - shortArrVal[i] = (int16_t)tmpInt; if (!SWIG_IsOK(checkConvert) || tmpInt < std::numeric_limits::min() || tmpInt > std::numeric_limits::max() || (!arr->Get(i)->IsInt32())) { - free((void*)shortArrVal); + delete[] shortArrVal; shortArrVal = NULL; return false; } + shortArrVal[i] = (int16_t)tmpInt; } ret = gsSetRowFieldByShortArray(row, column, (const int16_t *)shortArrVal, size); - free ((void*) shortArrVal); + delete[] shortArrVal; break; } case GS_TYPE_LONG_ARRAY: { @@ -829,20 +762,21 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - longArrVal = (int64_t *) malloc(size * sizeof(int64_t)); - if (longArrVal == NULL) { + try { + longArrVal = new int64_t[size](); + } catch (std::bad_alloc& ba) { return false; } for (i = 0; i < size; i++) { vbool = convertObjectToLong(arr->Get(i), &longArrVal[i]); if (!vbool) { - free((void*)longArrVal); + delete[] longArrVal; longArrVal = NULL; return false; } } ret = gsSetRowFieldByLongArray(row, column, (const int64_t *)longArrVal, size); - free ((void*) longArrVal); + delete[] longArrVal; break; } case GS_TYPE_FLOAT_ARRAY: { @@ -852,20 +786,21 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - floatArrVal = (float *) malloc(size * sizeof(float)); - if (floatArrVal == NULL) { + try { + floatArrVal = new float[size](); + } catch (std::bad_alloc& ba) { return false; } for (i = 0; i < size; i++) { vbool = convertObjectToFloat(arr->Get(i), &floatArrVal[i]); if (!vbool) { - free((void*)floatArrVal); + delete[] floatArrVal; floatArrVal = NULL; return false; } } ret = gsSetRowFieldByFloatArray(row, column, (const float *) floatArrVal, size); - free ((void*) floatArrVal); + delete[] floatArrVal; break; } case GS_TYPE_DOUBLE_ARRAY: { @@ -876,21 +811,22 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - doubleArrVal = (double *) malloc(size * sizeof(double)); - if (doubleArrVal == NULL) { + try { + doubleArrVal = new double[size](); + } catch (std::bad_alloc& ba) { return false; } for (i = 0; i < size; i++) { vbool = convertObjectToDouble(arr->Get(i), &tmpDouble); doubleArrVal[i] = tmpDouble; if (!vbool) { - free((void*)doubleArrVal); + delete[] doubleArrVal; doubleArrVal = NULL; return false; } } ret = gsSetRowFieldByDoubleArray(row, column, (const double *)doubleArrVal, size); - free ((void*) doubleArrVal); + delete[] doubleArrVal; break; } case GS_TYPE_TIMESTAMP_ARRAY: { @@ -900,21 +836,22 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local } arr = v8::Local::Cast(value); size = (int) arr->Length(); - timestampArrVal = (GSTimestamp *) malloc(size * sizeof(GSTimestamp)); - if (timestampArrVal == NULL) { + try { + timestampArrVal = new GSTimestamp[size](); + } catch (std::bad_alloc& ba) { return false; } bool checkRet; for (i = 0; i < size; i++) { checkRet = convertObjectToGSTimestamp(arr->Get(i), (timestampArrVal + i)); if (!checkRet) { - free((void*)timestampArrVal); + delete[] timestampArrVal; timestampArrVal = NULL; return false; } } ret = gsSetRowFieldByTimestampArray(row, column, (const GSTimestamp *)timestampArrVal, size); - free ((void*) timestampArrVal); + delete[] timestampArrVal; break; } default: @@ -922,75 +859,7 @@ static bool convertToFieldWithType(GSRow *row, int column, v8::Local return false; break; } - return (ret == GS_RESULT_OK); -} -} - -/** -* Typemaps for set_properties() function -*/ -%typemap(in, fragment = "SWIG_AsCharPtrAndSize", fragment = "freeargSetProperties") (const GSPropertyEntry* props, int propsCount) -(v8::Local obj, v8::Local keys, int j, size_t size = 0, int* alloc = 0, int res, char* v = 0) { - if (!$input->IsObject()) { - SWIG_V8_Raise("Expected object property as input"); - SWIG_fail; - } - obj = $input->ToObject(); - keys = obj->GetOwnPropertyNames(); - $2 = (int) keys->Length(); - $1 = NULL; - if ($2 > 0) { - $1 = (GSPropertyEntry *) malloc($2*sizeof(GSPropertyEntry)); - alloc = (int*) malloc($2 * 2 * sizeof(int)); - if ($1 == NULL || alloc == NULL) { - freeargSetProperties($1, $2, alloc); - SWIG_V8_Raise("Memory allocation error"); - SWIG_fail; - } - memset(alloc, 0, $2 * 2 * sizeof(int)); - - j = 0; - for (int i = 0; i < $2; i++) { - res = SWIG_AsCharPtrAndSize(keys->Get(i), &v, &size, &alloc[j]); - if (!SWIG_IsOK(res)) { - freeargSetProperties($1, $2, alloc); - %variable_fail(res, "String", "name"); - } - - $1[i].name = v; - res = SWIG_AsCharPtrAndSize(obj->Get(keys->Get(i)), &v, &size, &alloc[j + 1]); - if (!SWIG_IsOK(res)) { - freeargSetProperties($1, $2, alloc); - %variable_fail(res, "String", "value"); - } - $1[i].value = v; - j+=2; - } - } -} - -%typemap(freearg, fragment = "freeargSetProperties") (const GSPropertyEntry* props, int propsCount){ - freeargSetProperties($1, $2, alloc$argnum); -} - -%fragment("freeargSetProperties", "header", fragment = "cleanString") { - //SWIG does not include freearg in fail: label (not like Python, so we need this function) -static void freeargSetProperties(GSPropertyEntry* entry, int size, int* alloc) { - int j = 0; - if (entry) { - for (int i = 0; i < size; i++) { - cleanString(entry[i].name, alloc[j]); - cleanString(entry[i].value, alloc[j + 1]); - j += 2; - } - free((void *) entry); - entry = NULL; - } - - if (alloc) { - free(alloc); - alloc = NULL; - } + return GS_SUCCEEDED(ret); } } @@ -1018,8 +887,12 @@ static void freeargSetProperties(GSPropertyEntry* entry, int size, int* alloc) { $7 = NULL; $8 = NULL; if (len > 0) { - alloc = (int*) malloc(len * 2 * sizeof(int)); - memset(alloc, 0, len * 2 * sizeof(int)); + try { + alloc = new int[len * 2](); + } catch (std::bad_alloc& ba) { + SWIG_V8_Raise("Memory allocation error"); + SWIG_fail; + } j = 0; for (int i = 0; i < len; i++) { @@ -1034,38 +907,44 @@ static void freeargSetProperties(GSPropertyEntry* entry, int size, int* alloc) { if (obj->Get(keys->Get(i))->IsInt32()) { $2 = obj->Get(keys->Get(i))->IntegerValue(); } else { + cleanString(name, alloc[j]); freeargGetStore($1, $3, $4, $5, $6, $7, $8, alloc); %variable_fail(res, "String", "value"); } } else { res = SWIG_AsCharPtrAndSize(obj->Get(keys->Get(i)), &v, &size, &alloc[j + 1]); if (!SWIG_IsOK(res)) { + cleanString(name, alloc[j]); freeargGetStore($1, $3, $4, $5, $6, $7, $8, alloc); %variable_fail(res, "String", "value"); } if (strcmp(name, "host") == 0 && v) { - $1 = strdup(v); + griddb::Util::strdup((const GSChar**)&$1, v); } else if (strcmp(name, "clusterName") == 0 && v) { - $3 = strdup(v); + griddb::Util::strdup((const GSChar**)&$3, v); } else if (strcmp(name, "database") == 0 && v) { - $4 = strdup(v); + griddb::Util::strdup((const GSChar**)&$4, v); } else if (strcmp(name, "username") == 0 && v) { - $5 = strdup(v); + griddb::Util::strdup((const GSChar**)&$5, v); } else if (strcmp(name, "password") == 0 && v) { - $6 = strdup(v); + griddb::Util::strdup((const GSChar**)&$6, v); } else if (strcmp(name, "notificationMember") == 0 && v) { - $7 = strdup(v); + griddb::Util::strdup((const GSChar**)&$7, v); } else if (strcmp(name, "notificationProvider") == 0 && v) { - $8 = strdup(v); + griddb::Util::strdup((const GSChar**)&$8, v); } else { cleanString(name, alloc[j]); + cleanString(v, alloc[j + 1]); freeargGetStore($1, $3, $4, $5, $6, $7, $8, alloc); SWIG_V8_Raise("Invalid Property"); SWIG_fail; } } cleanString(name, alloc[j]); - cleanString(v, alloc[j + 1]); + if (v) { + cleanString(v, alloc[j + 1]); + v = NULL; + } j += 2; } @@ -1084,28 +963,28 @@ static void freeargGetStore(const char* host, const char* cluster_name, const char* database, const char* username, const char* password, const char* notification_member, const char* notification_provider, int* alloc) { if (host) { - free((void*) host); + delete[] host; } if (cluster_name) { - free((void*) cluster_name); + delete[] cluster_name; } if (database) { - free((void*) database); + delete[] database; } if (username) { - free((void*) username); + delete[] username; } if (password) { - free((void*) password); + delete[] password; } if (notification_member) { - free((void*) notification_member); + delete[] notification_member; } if (notification_provider) { - free((void*) notification_provider); + delete[] notification_provider; } if (alloc) { - free(alloc); + delete[] alloc; } } } @@ -1126,8 +1005,9 @@ static void freeargGetStore(const char* host, const char* cluster_name, $2 = (int) arr->Length(); $1 = NULL; if ($2 > 0) { - $1 = (GSQuery**) malloc($2*sizeof(GSQuery*)); - if ($1 == NULL) { + try { + $1 = new GSQuery*[$2](); + } catch (std::bad_alloc& ba) { SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } @@ -1135,9 +1015,7 @@ static void freeargGetStore(const char* host, const char* cluster_name, query = arr->Get(i); res = SWIG_ConvertPtr(query, (void**)&vquery, $descriptor(griddb::Query*), 0); if (!SWIG_IsOK(res)) { - if ($1) { - free((void *) $1); - } + delete[] $1; SWIG_V8_Raise("Convert pointer failed"); SWIG_fail; } @@ -1149,7 +1027,7 @@ static void freeargGetStore(const char* host, const char* cluster_name, %typemap(freearg) (GSQuery* const* queryList, size_t queryCount) { if ($1) { - free((void *) $1); + delete[] $1; } } @@ -1215,7 +1093,9 @@ static void freeargGetStore(const char* host, const char* cluster_name, } /** -* Typemaps for put_row() function +* Typemaps for RowSet::update() and Container::put() function +* The argument "GSRow *rowdata" is not used in the function body, it only for the purpose of typemap matching pattern +* The actual input data is store in class member and can be get by function getGSRowPtr() */ %typemap(in, fragment = "convertToFieldWithType") (GSRow* row) { if (!$input->IsArray()) { @@ -1226,37 +1106,14 @@ static void freeargGetStore(const char* host, const char* cluster_name, int leng = (int)arr->Length(); GSRow *tmpRow = arg1->getGSRowPtr(); int colNum = arg1->getColumnCount(); - GSType* typeList = arg1->getGSTypeList(); - for (int i = 0; i < leng; i++) { - GSType type = typeList[i]; - if (!(convertToFieldWithType(tmpRow, i, arr->Get(i), type))) { - %variable_fail(1, "String", "Can not create row based on input"); - } - } -} - -/** -* Typemaps for Container::put() function -*/ -%typemap(in, fragment = "convertToFieldWithType") (GSRow *rowContainer) { - if (!$input->IsArray()) { - SWIG_V8_Raise("Expected array as input"); - SWIG_fail; - } - v8::Local arr = v8::Local::Cast($input); - int leng = (int)arr->Length(); - - if (leng != arg1->getColumnCount()) { + if (leng != colNum) { SWIG_V8_Raise("Num row is different with container info"); SWIG_fail; } GSType* typeList = arg1->getGSTypeList(); - GSType type; - GSRow* row; - row = arg1->getGSRowPtr(); for (int i = 0; i < leng; i++) { - type = typeList[i]; - if (!(convertToFieldWithType(row, i, arr->Get(i), type))) { + GSType type = typeList[i]; + if (!(convertToFieldWithType(tmpRow, i, arr->Get(i), type))) { char errorMsg[60]; sprintf(errorMsg, "Invalid value for column %d, type should be : %d", i, type); SWIG_V8_Raise(errorMsg); @@ -1271,12 +1128,7 @@ static void freeargGetStore(const char* host, const char* cluster_name, %typemap(in, fragment = "convertToRowKeyFieldWithType") (griddb::Field* keyFields)(griddb::Field field) { $1 = &field; if ($input->IsNull() || $input->IsUndefined()) { -%#if GS_COMPATIBILITY_SUPPORT_3_5 $1->type = GS_TYPE_NULL; -%#else - SWIG_V8_Raise("Not support for NULL"); - SWIG_fail; -%#endif } else { GSType* typeList = arg1->getGSTypeList(); GSType type = typeList[0]; @@ -1303,9 +1155,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim for (int i = 0; i < columnCount; i++) { //Check NULL value GSBool nullValue; -%#if GS_COMPATIBILITY_SUPPORT_3_5 + ret = gsGetRowFieldNull(row, (int32_t) i, &nullValue); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { *columnError = i; retVal = false; *fieldTypeError = GS_TYPE_NULL; @@ -1315,71 +1167,104 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim outList->Set(i, SWIGV8_NULL()); continue; } -%#endif + switch(typeList[i]) { case GS_TYPE_LONG: { int64_t longValue; ret = gsGetRowFieldAsLong(row, (int32_t) i, &longValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_NUMBER_NEW(longValue)); break; } case GS_TYPE_STRING: { GSChar* stringValue; ret = gsGetRowFieldAsString(row, (int32_t) i, (const GSChar **)&stringValue); - outList->Set(i, SWIGV8_STRING_NEW(stringValue)); + if (!GS_SUCCEEDED(ret)) { + break; + } + outList->Set(i, SWIGV8_STRING_NEW((const char * )stringValue)); break; } case GS_TYPE_BLOB: { GSBlob blobValue; ret = gsGetRowFieldAsBlob(row, (int32_t) i, &blobValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, Nan::CopyBuffer((char *)blobValue.data, blobValue.size).ToLocalChecked()); break; } case GS_TYPE_BOOL: { GSBool boolValue; ret = gsGetRowFieldAsBool(row, (int32_t) i, &boolValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_BOOLEAN_NEW((bool)boolValue)); break; } case GS_TYPE_INTEGER: { int32_t intValue; ret = gsGetRowFieldAsInteger(row, (int32_t) i, &intValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_INT32_NEW(intValue)); break; } case GS_TYPE_FLOAT: { float floatValue; ret = gsGetRowFieldAsFloat(row, (int32_t) i, &floatValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_NUMBER_NEW(floatValue)); break; } case GS_TYPE_DOUBLE: { double doubleValue; ret = gsGetRowFieldAsDouble(row, (int32_t) i, &doubleValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_NUMBER_NEW(doubleValue)); break; } case GS_TYPE_TIMESTAMP: { GSTimestamp timestampValue; ret = gsGetRowFieldAsTimestamp(row, (int32_t) i, ×tampValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, convertTimestampToObject(×tampValue, timestampOutput)); break; } case GS_TYPE_BYTE: { int8_t byteValue; ret = gsGetRowFieldAsByte(row, (int32_t) i, &byteValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_INT32_NEW(byteValue)); break; } case GS_TYPE_SHORT: { int16_t shortValue; ret = gsGetRowFieldAsShort(row, (int32_t) i, &shortValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_INT32_NEW(shortValue)); break; } case GS_TYPE_GEOMETRY: { GSChar* geoValue; ret = gsGetRowFieldAsGeometry(row, (int32_t) i, (const GSChar **)&geoValue); + if (!GS_SUCCEEDED(ret)) { + break; + } outList->Set(i, SWIGV8_STRING_NEW(geoValue)); break; } @@ -1387,6 +1272,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim int32_t* intArr; size_t size; ret = gsGetRowFieldAsIntegerArray (row, (int32_t) i, (const int32_t **)&intArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIG_From_int(intArr[j])); @@ -1398,6 +1286,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim GSChar** stringArrVal; size_t size; ret = gsGetRowFieldAsStringArray (row, (int32_t) i, ( const GSChar *const **)&stringArrVal, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIGV8_STRING_NEW((GSChar *)stringArrVal[j])); @@ -1409,6 +1300,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim GSBool* boolArr; size_t size; ret = gsGetRowFieldAsBoolArray(row, (int32_t) i, (const GSBool **)&boolArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIG_From_bool(boolArr[j])); @@ -1420,6 +1314,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim int8_t* byteArr; size_t size; ret = gsGetRowFieldAsByteArray(row, (int32_t) i, (const int8_t **)&byteArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIG_From_int(byteArr[j])); @@ -1431,6 +1328,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim int16_t* shortArr; size_t size; ret = gsGetRowFieldAsShortArray(row, (int32_t) i, (const int16_t **)&shortArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIG_From_int(shortArr[j])); @@ -1442,6 +1342,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim int64_t* longArr; size_t size; ret = gsGetRowFieldAsLongArray(row, (int32_t) i, (const int64_t **)&longArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIGV8_NUMBER_NEW(longArr[j])); @@ -1453,6 +1356,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim float* floatArr; size_t size; ret = gsGetRowFieldAsFloatArray(row, (int32_t) i, (const float **)&floatArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIGV8_NUMBER_NEW(((float *)floatArr)[j])); @@ -1464,6 +1370,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim double* doubleArr; size_t size; ret = gsGetRowFieldAsDoubleArray(row, (int32_t) i, (const double **)&doubleArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, SWIGV8_NUMBER_NEW(((double *)doubleArr)[j])); @@ -1475,6 +1384,9 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim GSTimestamp* timestampArr; size_t size; ret = gsGetRowFieldAsTimestampArray(row, (int32_t) i, (const GSTimestamp **)×tampArr, &size); + if (!GS_SUCCEEDED(ret)) { + break; + } v8::Local list = SWIGV8_ARRAY_NEW(); for (int j = 0; j < size; j++) { list->Set(j, convertTimestampToObject((GSTimestamp*)&(timestampArr[j]), timestampOutput)); @@ -1488,7 +1400,7 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim break; } } - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { *columnError = i; *fieldTypeError = typeList[i]; retVal = false; @@ -1499,6 +1411,11 @@ static bool getRowFields(GSRow* row, int columnCount, GSType* typeList, bool tim } } +/* +* This typemap argument out does not get data from argument "GSRow *rowdata" +* The argument "GSRow *rowdata" is not used in the function Container::get(), it only for the purpose of typemap matching pattern +* The actual output data is store in class member and can be get by function getGSRowPtr() +*/ %typemap(argout, fragment = "getRowFields") (GSRow *rowdata) (v8::Local obj, v8::Handle val) { if (result == GS_FALSE) { $result = SWIGV8_NULL(); @@ -1540,72 +1457,127 @@ size_t sizeTmp = 0, int* alloc = 0, char* v = 0) { griddb::Container* tmpContainer; if ($4 > 0) { - $1 = new GSRow**[$4]; - $2 = (int*) malloc($4 * sizeof(int)); - $3 = (char **) malloc($4 * sizeof(char*)); - alloc = (int*) malloc($4*sizeof(int)); - if ($1 == NULL || $2 == NULL || $3 == NULL || alloc == NULL) { + try { + $1 = new GSRow**[$4](); + $2 = new int[$4](); + $3 = new char*[$4](); + alloc = new int[$4](); + } catch (std::bad_alloc& ba) { freeargStoreMultiPut($1, $2, $3, $4, alloc); SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } - memset(alloc, 0x0, $4*sizeof(int)); for (int i = 0; i < $4; i++) { // Get container name res = SWIG_AsCharPtrAndSize(keys->Get(i), &v, &sizeTmp, &alloc[i]); if (!SWIG_IsOK(res)) { - freeargStoreMultiPut($1, $2, $3, i, alloc); + freeargStoreMultiPut($1, $2, $3, $4, alloc); %variable_fail(res, "String", "containerName"); } if (v) { - $3[i] = strdup(v); + griddb::Util::strdup((const GSChar**)&$3[i], v); cleanString(v, alloc[i]); } else { $3[i] = NULL; } // Get row if (!(obj->Get(keys->Get(i)))->IsArray()) { - freeargStoreMultiPut($1, $2, $3, i, alloc); + freeargStoreMultiPut($1, $2, $3, $4, alloc); SWIG_V8_Raise("Expected an array as rowList"); SWIG_fail; } arr = v8::Local::Cast(obj->Get(keys->Get(i))); $2[i] = (int) arr->Length(); - $1[i] = new GSRow* [$2[i]]; - + try { + $1[i] = new GSRow*[$2[i]](); + } catch (std::bad_alloc& ba) { + freeargStoreMultiPut($1, $2, $3, $4, alloc); + SWIG_V8_Raise("Memory allocation error"); + SWIG_fail; + } //Get container info - griddb::ContainerInfo* containerInfoTmp = arg1->get_container_info($3[i]); + griddb::ContainerInfo* containerInfoTmp = NULL; + try { + containerInfoTmp = arg1->get_container_info($3[i]); + } catch (griddb::GSException& e) { + freeargStoreMultiPut($1, $2, $3, $4, alloc); + string innerErrMsg((&e)->what()); + string errMessage = "Get container info for Multiput Error: " + innerErrMsg; + SWIG_V8_Raise(errMessage.c_str()); + SWIG_fail; + } + if (containerInfoTmp == NULL) { + freeargStoreMultiPut($1, $2, $3, $4, alloc); + SWIG_V8_Raise("Can not get Container info"); + SWIG_fail; + } ColumnInfoList infoListTmp = containerInfoTmp->get_column_info_list(); - int* typeArr = (int*) malloc(infoListTmp.size * sizeof(int)); + int* typeArr; + try { + typeArr = new int[infoListTmp.size](); + } catch (std::bad_alloc& ba) { + freeargStoreMultiPut($1, $2, $3, $4, alloc); + delete containerInfoTmp; + SWIG_V8_Raise("Memory allocation error"); + SWIG_fail; + } for (int m = 0; m < infoListTmp.size; m++) { typeArr[m] = infoListTmp.columnInfo[m].type; } - tmpContainer = arg1->get_container($3[i]); + try { + tmpContainer = arg1->get_container($3[i]); + } catch (griddb::GSException& e) { + freeargStoreMultiPut($1, $2, $3, $4, alloc); + delete containerInfoTmp; + string innerErrMsg((&e)->what()); + string errMessage = "Get container for Multiput Error: " + innerErrMsg; + SWIG_V8_Raise(errMessage.c_str()); + SWIG_fail; + } + if (tmpContainer == NULL) { + delete containerInfoTmp; + delete[] typeArr; + freeargStoreMultiPut($1, $2, $3, $4, alloc); + SWIG_V8_Raise("Expect row is array"); + SWIG_fail; + } GSResult ret; for (int j = 0; j < $2[i]; j++) { ret = gsCreateRowByContainer(tmpContainer->getGSContainerPtr(), &$1[i][j]); rowArr = v8::Local::Cast(arr->Get(j)); + if (!rowArr->IsArray()) { + delete containerInfoTmp; + delete[] typeArr; + delete tmpContainer; + freeargStoreMultiPut($1, $2, $3, $4, alloc); + SWIG_V8_Raise("Expect row is array"); + SWIG_fail; + } int rowLen = (int) rowArr->Length(); int k; for (k = 0; k < rowLen; k++) { if (!(convertToFieldWithType($1[i][j], k, rowArr->Get(k), typeArr[k]))) { char errorMsg[60]; sprintf(errorMsg, "Invalid value for column %d, type should be : %d", k, typeArr[k]); + delete tmpContainer; delete containerInfoTmp; - free((void *) typeArr); - freeargStoreMultiPut($1, $2, $3, i, alloc); + delete[] typeArr; + freeargStoreMultiPut($1, $2, $3, $4, alloc); SWIG_V8_Raise(errorMsg); SWIG_fail; } } } + delete tmpContainer; + delete[] typeArr; + delete containerInfoTmp; } } } -%typemap(freearg, fragment = "freeargStoreMultiPut") (GSRow*** listRow, const int *listRowContainerCount, char ** listContainerName, size_t containerCount) { +%typemap(freearg, fragment = "freeargStoreMultiPut") (GSRow*** listRow, const int *listRowContainerCount, const char ** listContainerName, size_t containerCount) { freeargStoreMultiPut($1, $2, $3, $4, alloc$argnum); } @@ -1626,18 +1598,18 @@ static void freeargStoreMultiPut(GSRow*** listRow, const int *listRowContainerCo listRow = NULL; } - if (listRowContainerCount) delete listRowContainerCount; + if (listRowContainerCount) delete [] listRowContainerCount; if (listContainerName) { for (int i = 0; i < containerCount; i++) { if (listContainerName[i]) { - free((void*)listContainerName[i]); + delete[] listContainerName[i]; listContainerName[i] = NULL; } } - free((void *) listContainerName); + delete[] listContainerName; } if (alloc) { - free((void *) alloc); + delete[] alloc; } } } @@ -1664,25 +1636,28 @@ static void freeargStoreMultiPut(GSRow*** listRow, const int *listRowContainerCo $6 = &tmpTypeList; $7 = &tmpOrderFromInput; if ($2 > 0) { - pList = (GSRowKeyPredicateEntry*) malloc($2*sizeof(GSRowKeyPredicateEntry)); - if (pList == NULL) { + try { + pList = new GSRowKeyPredicateEntry[$2](); + } catch (std::bad_alloc& ba) { SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } $1 = &pList; - alloc = (int*) malloc($2 * 2 * sizeof(int)); - if (alloc == NULL) { - freeargStoreMultiGet($1, $2, $3, $4, $5, $6, $7, alloc); + + try { + alloc = new int[$2 * 2](); + } catch (std::bad_alloc& ba) { + freeargStoreMultiGet($1, $2, NULL, NULL, NULL, NULL, NULL, NULL); SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } - memset(alloc, 0, $2 * 2 * sizeof(int)); + for (int i = 0; i < $2; i++) { GSRowKeyPredicateEntry *predicateEntry = &pList[i]; // Get container name res = SWIG_AsCharPtrAndSize(keys->Get(i), &v, &size, &alloc[i]); if (!SWIG_IsOK(res)) { - freeargStoreMultiGet($1, $2, $3, $4, $5, $6, $7, alloc); + freeargStoreMultiGet($1, $2, NULL, NULL, NULL, NULL, NULL, alloc); %variable_fail(res, "String", "containerName"); } predicateEntry->containerName = v; @@ -1690,12 +1665,15 @@ static void freeargStoreMultiPut(GSRow*** listRow, const int *listRowContainerCo // Get predicate res = SWIG_ConvertPtr((obj->Get(keys->Get(i))), (void**)&vpredicate, $descriptor(griddb::RowKeyPredicate*), 0); if (!SWIG_IsOK(res)) { - freeargStoreMultiGet($1, $2, $3, $4, $5, $6, $7, alloc); + freeargStoreMultiGet($1, $2, NULL, NULL, NULL, NULL, NULL, alloc); SWIG_V8_Raise("Convert RowKeyPredicate pointer failed"); SWIG_fail; } predicateEntry->predicate = vpredicate->gs_ptr(); } + } else { + SWIG_V8_Raise("Input should not be empty object"); + SWIG_fail; } } @@ -1747,23 +1725,27 @@ static void freeargStoreMultiGet(const GSRowKeyPredicateEntry *const * predicate cleanString((*predicateList)[i].containerName, alloc[i]); } if (pList) { - free(pList); + delete[] pList; + pList = NULL; } } if (alloc) { - free(alloc); + delete[] alloc; + alloc = NULL; } - if (*colNumList) { + if (colNumList && *colNumList) { delete [] *colNumList; + *colNumList = NULL; } - if (*typeList) { + if (typeList && *typeList) { for (int j = 0; j < (int) predicateCount; j++) { if ((*typeList)[j]) { - free ((void*) (*typeList)[j]); + delete[] (*typeList)[j]; } } delete [] (*typeList); + *typeList = NULL; } if (entryList) { GSRow* row; @@ -1773,9 +1755,11 @@ static void freeargStoreMultiGet(const GSRowKeyPredicateEntry *const * predicate gsCloseRow(&row); } } + entryList = NULL; } - if (*orderFromInput) { + if (orderFromInput && *orderFromInput) { delete [] *orderFromInput; + *orderFromInput = NULL; } } } @@ -1785,25 +1769,19 @@ static void freeargStoreMultiGet(const GSRowKeyPredicateEntry *const * predicate */ %typemap(in, fragment = "convertToRowKeyFieldWithType") (griddb::Field* startKey)(griddb::Field field) { $1 = &field; - if ($1 == NULL) { - SWIG_V8_Raise("Memory allocation error"); - SWIG_fail; - } GSType type = arg1->get_key_type(); if (!(convertToRowKeyFieldWithType(*$1, $input, type))) { - %variable_fail(1, "String", "Can not create row based on input"); + SWIG_V8_Raise("Can not create row based on input"); + SWIG_fail; } } %typemap(in, fragment = "convertToRowKeyFieldWithType") (griddb::Field* finishKey)(griddb::Field field) { $1 = &field; - if ($1 == NULL) { - SWIG_V8_Raise("Memory allocation error"); - SWIG_fail; - } GSType type = arg1->get_key_type(); if (!(convertToRowKeyFieldWithType(*$1, $input, type))) { - %variable_fail(1, "String", "Can not create row based on input"); + SWIG_V8_Raise("Can not create row based on input"); + SWIG_fail; } } @@ -1834,15 +1812,19 @@ static void freeargStoreMultiGet(const GSRowKeyPredicateEntry *const * predicate v8::Local arr = v8::Local::Cast($input); $2 = (int)arr->Length(); $1 = NULL; + if ($2 > 0) { - $1 = new griddb::Field[$2]; - if ($1 == NULL) { + try { + $1 = new griddb::Field[$2](); + } catch (std::bad_alloc& ba) { SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } GSType type = arg1->get_key_type(); for (int i = 0; i < $2; i++) { if (!(convertToRowKeyFieldWithType($1[i], arr->Get(i), type))) { + delete [] $1; + $1 = NULL; SWIG_V8_Raise("Can not create row based on input"); SWIG_fail; } @@ -1875,22 +1857,40 @@ static void freeargStoreMultiGet(const GSRowKeyPredicateEntry *const * predicate $result = obj; } +%typemap(freearg) (griddb::Field **keys, size_t* keyCount) { + if ($1) { + delete [] (*$1); + } +} + /** * Typemap for Container::multi_put */ %typemap(in, fragment = "convertToFieldWithType", fragment = "freeargContainerMultiPut") (GSRow** listRowdata, int rowCount) { if (!$input->IsArray()) { - SWIG_V8_Raise("Expected array as input"); + SWIG_V8_Raise("Expected array of array as input"); SWIG_fail; } v8::Local arr = v8::Local::Cast($input); $2 = (size_t)arr->Length(); + for (int i = 0; i < $2; i++) { + if (!arr->Get(i)->IsArray()) { + SWIG_V8_Raise("Expected array of array as input"); + SWIG_fail; + } + } + if ($2 > 0) { GSContainer *mContainer = arg1->getGSContainerPtr(); GSType* typeList = arg1->getGSTypeList(); - $1 = new GSRow*[$2]; + try { + $1 = new GSRow*[$2](); + } catch (std::bad_alloc& ba) { + SWIG_V8_Raise("Memory allocation error"); + SWIG_fail; + } int length; for (int i = 0; i < $2; i++) { v8::Local fieldArr = v8::Local::Cast(arr->Get(i)); @@ -1901,7 +1901,7 @@ static void freeargStoreMultiGet(const GSRowKeyPredicateEntry *const * predicate SWIG_fail; } GSResult ret = gsCreateRowByContainer(mContainer, &$1[i]); - if (ret != GS_RESULT_OK) { + if (!GS_SUCCEEDED(ret)) { freeargContainerMultiPut($1, i); SWIG_V8_Raise("Can't create GSRow"); SWIG_fail; @@ -1961,6 +1961,22 @@ static void freeargContainerMultiPut(GSRow** listRowdata, int rowCount) { $result = obj; } +%typemap(freearg) (GSQueryAnalysisEntry* queryAnalysis) { + if ($1) { + if ($1->statement) { + delete [] $1->statement; + } + if ($1->type) { + delete [] $1->type; + } + if ($1->value) { + delete [] $1->value; + } + if ($1->valueType) { + delete [] $1->valueType; + } + } +} /** * Typemap for Rowset::next() @@ -1975,18 +1991,20 @@ static void freeargContainerMultiPut(GSRow** listRowdata, int rowCount) { $3 = &queryAnalysisTmp; $4 = &aggResultTmp; } + %typemap(argout) (GSRowSetType* type, bool* hasNextRow, griddb::QueryAnalysisEntry** queryAnalysis, griddb::AggregationResult** aggResult) - (v8::Local obj, v8::Handle value) { + (v8::Local obj) { GSRow* row; - switch (typeTmp$argnum) { - case GS_ROW_SET_CONTAINER_ROWS: { - bool retVal; - int errorColumn; - GSType errorType; - if (hasNextRowTmp$argnum == false) { - $result = SWIGV8_NULL(); - } else { + + if (hasNextRowTmp$argnum == false) { + $result = SWIGV8_NULL(); + } else { + switch (typeTmp$argnum) { + case (GS_ROW_SET_CONTAINER_ROWS): { + bool retVal; + int errorColumn; + GSType errorType; row = arg1->getGSRowPtr(); obj = SWIGV8_ARRAY_NEW(); if (obj->IsNull()) { @@ -2001,29 +2019,19 @@ static void freeargContainerMultiPut(GSRow** listRowdata, int rowCount) { SWIG_fail; } $result = obj; + break; } - break; + case (GS_ROW_SET_AGGREGATION_RESULT): + $result = SWIG_V8_NewPointerObj((void *)aggResultTmp$argnum, $descriptor(griddb::AggregationResult *), SWIG_POINTER_OWN); + break; + case (GS_ROW_SET_QUERY_ANALYSIS): + $result = SWIG_V8_NewPointerObj((void *)queryAnalysisTmp$argnum, $descriptor(griddb::QueryAnalysisEntry *), SWIG_POINTER_OWN); + break; + default: + SWIG_V8_Raise("Invalid Rowset type"); + SWIG_fail; + break; } - case GS_ROW_SET_AGGREGATION_RESULT: - if (hasNextRowTmp$argnum == true) { - value = SWIG_V8_NewPointerObj((void *)aggResultTmp$argnum, $descriptor(griddb::AggregationResult *), SWIG_POINTER_OWN); - $result = value; - } else { - $result = SWIGV8_NULL(); - } - break; - case GS_ROW_SET_QUERY_ANALYSIS: - if (hasNextRowTmp$argnum == true) { - value = SWIG_V8_NewPointerObj((void *)queryAnalysisTmp$argnum, $descriptor(griddb::QueryAnalysisEntry *), SWIG_POINTER_OWN); - $result = value; - } else { - $result = SWIGV8_NULL(); - } - break; - default: - SWIG_V8_Raise("Invalid Rowset type"); - SWIG_fail; - break; } } @@ -2040,21 +2048,22 @@ static void freeargContainerMultiPut(GSRow** listRowdata, int rowCount) { GSColumnInfo* containerInfo; $1 = &infolist; if (len) { - containerInfo = (GSColumnInfo*) malloc(len * sizeof(GSColumnInfo)); - if (containerInfo == NULL ) { + try { + containerInfo = new GSColumnInfo[len](); + } catch (std::bad_alloc& ba) { SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } - alloc = (int*) malloc(len*sizeof(int)); - if (alloc == NULL) { - free((void*) containerInfo); + + try { + alloc = new int[len](); + } catch (std::bad_alloc& ba) { + delete[] containerInfo; SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } $1->columnInfo = containerInfo; $1->size = len; - memset(containerInfo, 0x0, len*sizeof(GSColumnInfo)); - memset(alloc, 0x0, len*sizeof(int)); for (int i = 0; i < len; i++) { if (!(arr->Get(i))->IsArray()) { @@ -2079,32 +2088,35 @@ static void freeargContainerMultiPut(GSRow** listRowdata, int rowCount) { } if (!value->IsNumber()) { + cleanString(v, alloc[i]); freeargColumnInfoList($1, alloc); SWIG_V8_Raise("Expected Integer as type of Column type"); SWIG_fail; } - containerInfo[i].name = v; + containerInfo[i].name = strdup(v); + cleanString(v, alloc[i]); containerInfo[i].type = value->Uint32Value(); if (colInfo->Length() == 3) { -%#if GS_COMPATIBILITY_SUPPORT_3_5 v8::Local options = colInfo->Get(2); - if (!options->IsNumber()) { + if (!options->IsUint32()) { freeargColumnInfoList($1, alloc); SWIG_V8_Raise("Expected Integer as type of Column options"); SWIG_fail; } containerInfo[i].options = options->Uint32Value(); -%#else + } + + if (colInfo->Length() > 3) { freeargColumnInfoList($1, alloc); - SWIG_V8_Raise("Expected two elements for ColumnInfo property"); + SWIG_V8_Raise("Expected at most 3 elements for ColumnInfo property"); SWIG_fail; -%#endif } } + } } @@ -2119,11 +2131,12 @@ static void freeargColumnInfoList(ColumnInfoList* infoList, int* alloc) { if (infoList->columnInfo) { if (alloc) { for (int i = 0; i < len; i++) { - cleanString(infoList->columnInfo[i].name, alloc[i]); + //cleanString(infoList->columnInfo[i].name, alloc[i]); + free((void*)infoList->columnInfo[i].name); } - free(alloc); + delete[] alloc; } - free ((void *)infoList->columnInfo); + delete[] infoList->columnInfo; } } } @@ -2143,19 +2156,18 @@ static void freeargColumnInfoList(ColumnInfoList* infoList, int* alloc) { v8::Handle str = SWIGV8_STRING_NEW2($1->columnInfo[i].name, strlen((char*)$1->columnInfo[i].name)); prop->Set(0, str); prop->Set(1, SWIGV8_NUMBER_NEW($1->columnInfo[i].type)); -%#if GS_COMPATIBILITY_SUPPORT_3_5 prop->Set(2, SWIGV8_NUMBER_NEW($1->columnInfo[i].options)); -%#endif obj->Set(i, prop); } } $result = obj; + delete $1; } /** * Typemaps for create_index()/ drop_index function : support keyword parameter ({"columnName" : str, "indexType" : int, "name" : str}) */ -%typemap(in, fragment = "SWIG_AsCharPtrAndSize", fragment = "cleanString" , fragment = "freeargContainerIndex") (const char* column_name, GSIndexTypeFlags index_type, const char* name) +%typemap(in, fragment = "SWIG_AsCharPtrAndSize", fragment = "cleanString" , fragment = "freeargContainerIndex") (const char* column_name, GSIndexTypeFlags index_type, const char* name) (v8::Local obj, v8::Local keys, int i, int j, size_t size = 0,size_t size1 = 0, int* alloc = 0, int res, char* v = 0) { char* name; if (!$input->IsObject()) { @@ -2179,7 +2191,7 @@ static void freeargColumnInfoList(ColumnInfoList* infoList, int* alloc) { freeargContainerIndex($1, $3); %variable_fail(res, "String", "name"); } - if (strcmp(name, "columnName") == 0) { + if (strcmp(name, "columnName") == 0 || strcmp(name, "name") == 0) { if (!obj->Get(keys->Get(i))->IsString()) { sprintf(errorMsg, "Invalid value for property %s", name); cleanString(name, allocKey); @@ -2193,35 +2205,22 @@ static void freeargColumnInfoList(ColumnInfoList* infoList, int* alloc) { %variable_fail(res, "String", "value"); } if (v) { - $1 = strdup(v); + if (strcmp(name, "columnName") == 0 ) { + griddb::Util::strdup((const GSChar**)&$1, v); + } else { + griddb::Util::strdup((const GSChar**)&$3, v); + } cleanString(v, allocValue); } } else if (strcmp(name, "indexType") == 0) { if (!obj->Get(keys->Get(i))->IsInt32()) { - sprintf(errorMsg, "Invalid value for property %s", name); - cleanString(name, allocKey); freeargContainerIndex($1, $3); - SWIG_V8_Raise(errorMsg); - SWIG_fail; - } - $2 = obj->Get(keys->Get(i))->IntegerValue(); - } else if (strcmp(name, "name") == 0) { - if (!obj->Get(keys->Get(i))->IsString()) { sprintf(errorMsg, "Invalid value for property %s", name); cleanString(name, allocKey); - freeargContainerIndex($1, $3); SWIG_V8_Raise(errorMsg); SWIG_fail; } - res = SWIG_AsCharPtrAndSize(obj->Get(keys->Get(i)), &v, &size1, &allocValue); - if (!SWIG_IsOK(res)) { - freeargContainerIndex($1, $3); - %variable_fail(res, "String", "value"); - } - if (v) { - $3 = strdup(v); - cleanString(v, allocValue); - } + $2 = obj->Get(keys->Get(i))->IntegerValue(); } else { sprintf(errorMsg, "Invalid property %s", name); cleanString(name, allocKey); @@ -2242,16 +2241,16 @@ static void freeargColumnInfoList(ColumnInfoList* infoList, int* alloc) { //SWIG does not include freearg in fail: label (not like Python, so we need this function) static void freeargContainerIndex(const char* column_name, const char* name) { if (column_name) { - free((void*) column_name); + delete[] column_name; } if (name) { - free((void*) name); + delete[] name; } } } /** -* Typemaps for set_fetch_options() : support keyword parameter ({"limit" : int}) +* Typemaps for set_fetch_options() : support keyword parameter ({"limit" : int, "partial" : bool}) */ %typemap(in, fragment = "SWIG_AsCharPtrAndSize") (int limit, bool partial) (v8::Local obj, v8::Local keys, int i, int j, size_t size = 0, int* alloc = 0, int res) { @@ -2268,6 +2267,7 @@ static void freeargContainerIndex(const char* column_name, const char* name) { $2 = false; int allocKey; char errorMsg[60]; + bool boolVal, vbool; if (len > 0) { for (int i = 0; i < len; i++) { res = SWIG_AsCharPtrAndSize(keys->Get(i), &name, &size, &allocKey); @@ -2277,11 +2277,16 @@ static void freeargContainerIndex(const char* column_name, const char* name) { if (strcmp(name, "limit") == 0) { if (!obj->Get(keys->Get(i))->IsInt32()) { sprintf(errorMsg, "Invalid value for property %s", name); - SWIG_V8_Raise(errorMsg); cleanString(name, allocKey); + SWIG_V8_Raise(errorMsg); SWIG_fail; } $1 = obj->Get(keys->Get(i))->IntegerValue(); + } else if (strcmp(name, "partial") == 0) { + cleanString(name, allocKey); + //Throw error when parse partial parameter + SWIG_V8_Raise("Not support partial parameter"); + SWIG_fail; } else { sprintf(errorMsg, "Invalid property %s", name); cleanString(name, allocKey); @@ -2312,7 +2317,7 @@ static void freeargContainerIndex(const char* column_name, const char* name) { $2 = NULL; $3 = 0; $4 = GS_CONTAINER_COLLECTION; - $5 = NULL; + $5 = true; //defautl value rowKey = true $6 = NULL; int allocKey; int allocValue; @@ -2321,6 +2326,7 @@ static void freeargContainerIndex(const char* column_name, const char* name) { v8::Local colInfo; bool boolVal, vbool; griddb::ExpirationInfo* expiration; + GSChar *nameStr; if (len > 0) { for (int i = 0; i < len; i++) { res = SWIG_AsCharPtrAndSize(keys->Get(i), &name, &size, &allocKey); @@ -2345,7 +2351,8 @@ static void freeargContainerIndex(const char* column_name, const char* name) { SWIG_fail; } if (v) { - $1 = strdup(v); + delete[] $1; + griddb::Util::strdup((const GSChar**)&$1, v); cleanString(v, allocValue); } } else if (strcmp(name, "columnInfoList") == 0) { @@ -2359,25 +2366,35 @@ static void freeargContainerIndex(const char* column_name, const char* name) { arr = v8::Local::Cast(obj->Get(keys->Get(i))); $3 = (int) arr->Length(); if ($3 > 0) { - $2 = (GSColumnInfo *) malloc($3*sizeof(GSColumnInfo)); - alloc = (int*) malloc($3*sizeof(int)); - if ($2 == NULL || alloc == NULL) { + try { + $2 = new GSColumnInfo[$3](); + } catch (std::bad_alloc& ba) { + freeargContainerInfo($1, $2, $3, alloc); + cleanString(name, allocKey); + SWIG_V8_Raise("Memory allocation error"); + SWIG_fail; + } + + try { + alloc = new int[$3](); + } catch (std::bad_alloc& ba) { freeargContainerInfo($1, $2, $3, alloc); + cleanString(name, allocKey); SWIG_V8_Raise("Memory allocation error"); SWIG_fail; } - memset($2, 0x0, $3*sizeof(GSColumnInfo)); - memset(alloc, 0x0, $3*sizeof(int)); for (int j = 0; j < $3; j++) { if (!(arr->Get(j))->IsArray()) { freeargContainerInfo($1, $2, $3, alloc); + cleanString(name, allocKey); SWIG_V8_Raise("Expected array property as ColumnInfo element"); SWIG_fail; } colInfo = v8::Local::Cast(arr->Get(j)); if ((int)colInfo->Length() < 2 || (int)colInfo->Length() > 3) { freeargContainerInfo($1, $2, $3, alloc); + cleanString(name, allocKey); SWIG_V8_Raise("Expected 2 or 3 elements for ColumnInfo property"); SWIG_fail; } @@ -2385,28 +2402,30 @@ static void freeargContainerIndex(const char* column_name, const char* name) { res = SWIG_AsCharPtrAndSize(colInfo->Get(0), &v, &size, &alloc[j]); if (!SWIG_IsOK(res)) { freeargContainerInfo($1, $2, $3, alloc); + cleanString(name, allocKey); %variable_fail(res, "String", "Column name"); } if (!colInfo->Get(1)->IsInt32()) { + cleanString(v, alloc[j]); freeargContainerInfo($1, $2, $3, alloc); + cleanString(name, allocKey); SWIG_V8_Raise("Expected Integer as type of Column type"); SWIG_fail; } $2[j].name = v; $2[j].type = (int) colInfo->Get(1)->Uint32Value(); -%#if GS_COMPATIBILITY_SUPPORT_3_5 if ((int)colInfo->Length() == 3) { v8::Local options = colInfo->Get(2); if (!options->IsInt32()) { freeargContainerInfo($1, $2, $3, alloc); + cleanString(name, allocKey); SWIG_V8_Raise("Expected Integer as type of Column options"); SWIG_fail; } $2[j].options = (int) options->Uint32Value(); } -%#endif } } } else if (strcmp(name, "type") == 0) { @@ -2459,17 +2478,17 @@ static void freeargContainerIndex(const char* column_name, const char* name) { static void freeargContainerInfo(const GSChar* name, const GSColumnInfo* props, int propsCount, int* alloc) { if (name) { - free((void*) name); + delete[] name; } if (props) { for (int i = 0; i < propsCount; i++) { cleanString(props[i].name, alloc[i]); } - free((void *) props); + delete[] props; } if (alloc) { - free(alloc); + delete[] alloc; } } }