diff --git a/.clang-format b/.clang-format index 53e7a39919fbdec161c3906163f990a34eb6be07..c0aa629aad994269935ccb7a17d6162d77897b5e 100644 --- a/.clang-format +++ b/.clang-format @@ -34,6 +34,7 @@ AllowAllParametersOfDeclarationOnNextLine: false # 枚举值不会在一行 AllowShortEnumsOnASingleLine: false +# 短语句不会在一行 AllowShortBlocksOnASingleLine: false # 允许短的case标签放在同一行 diff --git a/data_object/.clang-format b/data_object/.clang-format deleted file mode 100644 index acad20138c758e45571591664df6f2a7e243248c..0000000000000000000000000000000000000000 --- a/data_object/.clang-format +++ /dev/null @@ -1,187 +0,0 @@ -Language: Cpp - -AccessModifierOffset: -4 - -AlignAfterOpenBracket: DontAlign - -AlignConsecutiveAssignments: false - -AlignConsecutiveDeclarations: false - -AlignOperands: true - -AlignTrailingComments: true - -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: false - -AllowShortCaseLabelsOnASingleLine: false - -AllowShortFunctionsOnASingleLine: None - -AllowShortIfStatementsOnASingleLine: false - -AllowShortLoopsOnASingleLine: false - -AlwaysBreakAfterDefinitionReturnType: None - -AlwaysBreakAfterReturnType: None - -AlwaysBreakBeforeMultilineStrings: false - -AlwaysBreakTemplateDeclarations: false - -BinPackArguments: true - -BinPackParameters: true - -BreakBeforeBinaryOperators: NonAssignment - -BreakBeforeBraces: Custom - -AlignEscapedNewlines: Left - -BreakBeforeInheritanceComma: false - -BreakBeforeTernaryOperators: true - -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeColon - -BreakInheritanceList: BeforeComma -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true - -ColumnLimit: 119 - -CommentPragmas: '^ NOLINT' -CompactNamespaces: false - -ConstructorInitializerAllOnOneLineOrOnePerLine: false - -ConstructorInitializerIndentWidth: 4 - -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: false - -DerivePointerAlignment: false - -PointerAlignment: Right - -ExperimentalAutoDetectBinPacking: false - -FixNamespaceComments: true - -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Regroup - -IncludeCategories: - - Regex: '^' - Priority: 2 - - Regex: '^<.*\.h>' - Priority: 1 - - Regex: '^<.*' - Priority: 2 - - Regex: '.*' - Priority: 3 -IncludeIsMainRegex: '([-_](test|benchmark))?$' - -IndentCaseLabels: true -IndentPPDirectives: None - -IndentWidth: 4 - -IndentWrappedFunctionNames: false - -JavaScriptQuotes: Leave -JavaScriptWrapImports: true - -KeepEmptyLinesAtTheStartOfBlocks: false - -MacroBlockBegin: '[A-Z_]+_BEGIN\(.*\)$' - -MacroBlockEnd: '.[A-Z_]+_END\(.*\)$' - -MaxEmptyLinesToKeep: 1 - -NamespaceIndentation: None - -ObjCBinPackProtocolList: Never - -ObjCBlockIndentWidth: 4 - -ObjCSpaceAfterProperty: false - -ObjCSpaceBeforeProtocolList: true - -PenaltyBreakBeforeFirstCallParameter: 1000 - -PenaltyBreakComment: 100 - -PenaltyBreakFirstLessLess: 5 - -PenaltyBreakString: 10 - -PenaltyBreakTemplateDeclaration: 10 - -PenaltyExcessCharacter: 20 - -PenaltyReturnTypeOnItsOwnLine: 50 - -PenaltyBreakAssignment: 10 - -ReflowComments: false - -SortIncludes: true - -SortUsingDeclarations: true - -SpaceAfterCStyleCast: false - -SpaceAfterTemplateKeyword: false - -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true - -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true - -SpaceInEmptyParentheses: false - -SpacesBeforeTrailingComments: 1 - -SpacesInAngles: false - -SpacesInContainerLiterals: true - -SpacesInCStyleCastParentheses: false - -SpacesInParentheses: false - -SpacesInSquareBrackets: false - -Standard: Cpp11 - -TabWidth: 4 - -UseTab: Never - -BraceWrapping: - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: true - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - -DisableFormat: false diff --git a/data_object/frameworks/innerkitsimpl/include/adaptor/hitrace.h b/data_object/frameworks/innerkitsimpl/include/adaptor/hitrace.h index 85ac55e8ff9f6399943dff98083b1f17f3788f73..7ceb5980aa3b4a68beca3ea49dd196da29acdc90 100644 --- a/data_object/frameworks/innerkitsimpl/include/adaptor/hitrace.h +++ b/data_object/frameworks/innerkitsimpl/include/adaptor/hitrace.h @@ -19,14 +19,14 @@ namespace OHOS { namespace ObjectStore { -class HiTrace final { +class DataObjectHiTrace final { public: - inline HiTrace(const std::string &value) + inline DataObjectHiTrace(const std::string &value) { StartTrace(HITRACE_TAG_DISTRIBUTEDDATA, value); } - inline ~HiTrace() + inline ~DataObjectHiTrace() { FinishTrace(HITRACE_TAG_DISTRIBUTEDDATA); } diff --git a/data_object/frameworks/innerkitsimpl/include/communicator/app_device_handler.h b/data_object/frameworks/innerkitsimpl/include/communicator/app_device_handler.h index 0bca19bb8de289f6f3b0b0c20bdb7f6db4c2a348..f32a906bde493a0baf35b9a0de927dce8f14c93e 100644 --- a/data_object/frameworks/innerkitsimpl/include/communicator/app_device_handler.h +++ b/data_object/frameworks/innerkitsimpl/include/communicator/app_device_handler.h @@ -34,7 +34,7 @@ public: DeviceInfo GetLocalDevice(); std::vector GetDeviceList() const; - std::string GetUdidByNodeId(const std::string &nodeId) const; + std::string GetUuidByNodeId(const std::string &nodeId) const; // get local device node information; DeviceInfo GetLocalBasicInfo() const; // get all remote connected device's node information; diff --git a/data_object/frameworks/innerkitsimpl/include/communicator/dev_manager.h b/data_object/frameworks/innerkitsimpl/include/communicator/dev_manager.h index 166e7f15ff6d33a372982db315c6eaddeb7dd1c9..ce68638934815bce201245bc6e2be961d5f212ef 100644 --- a/data_object/frameworks/innerkitsimpl/include/communicator/dev_manager.h +++ b/data_object/frameworks/innerkitsimpl/include/communicator/dev_manager.h @@ -15,6 +15,7 @@ #ifndef DATA_OBJECT_DEV_MANAGER_H #define DATA_OBJECT_DEV_MANAGER_H #include +#include namespace OHOS { namespace ObjectStore { class DevManager { @@ -25,6 +26,7 @@ public: return instance; } void RegisterDevCallback(); + std::string GetUuidByNodeId(const std::string &nodeId) const; private: DevManager(); diff --git a/data_object/frameworks/innerkitsimpl/include/communicator/softbus_adapter.h b/data_object/frameworks/innerkitsimpl/include/communicator/softbus_adapter.h index 54714feaecb008fbaa82d078107629ca7cb345b9..93d9fb487657a194ca5fa008c88b54418fd8cfd0 100644 --- a/data_object/frameworks/innerkitsimpl/include/communicator/softbus_adapter.h +++ b/data_object/frameworks/innerkitsimpl/include/communicator/softbus_adapter.h @@ -45,7 +45,6 @@ public: void NotifyAll(const DeviceInfo &deviceInfo, const DeviceChangeType &type); DeviceInfo GetLocalDevice(); std::vector GetDeviceList() const; - std::string GetUdidByNodeId(const std::string &nodeId) const; // get local device node information; DeviceInfo GetLocalBasicInfo() const; // get all remote connected device's node information; @@ -92,7 +91,7 @@ private: }; std::shared_ptr> GetSemaphore (int32_t sessinId); mutable std::mutex networkMutex_{}; - mutable std::map networkId2Udid_{}; + mutable std::map networkId2Uuid_{}; DeviceInfo localInfo_{}; static std::shared_ptr instance_; std::mutex deviceChangeMutex_; diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_impl.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_impl.cpp index 1e1722ab1d4cba1f1c54f99fd1e4b1af639d2e56..d7c0e464e1acede27cfcb5d37a8198e17889ad1c 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_impl.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_impl.cpp @@ -55,7 +55,7 @@ uint32_t GetNum(Bytes &data, uint32_t offset, void *val, uint32_t valLen) uint32_t DistributedObjectImpl::PutDouble(const std::string &key, double value) { - HiTrace trace(std::string(__FUNCTION__)); + DataObjectHiTrace trace(std::string(__FUNCTION__)); Bytes data; Type type = Type::TYPE_DOUBLE; PutNum(&type, 0, sizeof(type), data); @@ -69,7 +69,7 @@ uint32_t DistributedObjectImpl::PutDouble(const std::string &key, double value) uint32_t DistributedObjectImpl::PutBoolean(const std::string &key, bool value) { - HiTrace trace(std::string(__FUNCTION__)); + DataObjectHiTrace trace(std::string(__FUNCTION__)); Bytes data; Type type = Type::TYPE_BOOLEAN; PutNum(&type, 0, sizeof(type), data); @@ -83,7 +83,7 @@ uint32_t DistributedObjectImpl::PutBoolean(const std::string &key, bool value) uint32_t DistributedObjectImpl::PutString(const std::string &key, const std::string &value) { - HiTrace trace(std::string(__FUNCTION__)); + DataObjectHiTrace trace(std::string(__FUNCTION__)); Bytes data; Type type = Type::TYPE_STRING; PutNum(&type, 0, sizeof(type), data); @@ -172,7 +172,7 @@ DistributedObjectImpl::DistributedObjectImpl(const std::string &sessionId, FlatO uint32_t DistributedObjectImpl::PutComplex(const std::string &key, const std::vector &value) { - HiTrace trace(std::string(__FUNCTION__)); + DataObjectHiTrace trace(std::string(__FUNCTION__)); Bytes data; Type type = Type::TYPE_COMPLEX; PutNum(&type, 0, sizeof(type), data); diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_store_impl.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_store_impl.cpp index 510778234fa75fd96a7309adcf0479e0da17e9c2..c99c4019dfadf2c51b225f6c0e4dcbcf001c6f65 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_store_impl.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/distributed_object_store_impl.cpp @@ -62,7 +62,7 @@ void DistributedObjectStoreImpl::RemoveCacheObject(const std::string &sessionId) DistributedObject *DistributedObjectStoreImpl::CreateObject(const std::string &sessionId) { - HiTrace trace(std::string(__FUNCTION__)); + DataObjectHiTrace trace(std::string(__FUNCTION__)); if (flatObjectStore_ == nullptr) { LOG_ERROR("DistributedObjectStoreImpl::CreateObject store not opened!"); return nullptr; @@ -83,7 +83,7 @@ DistributedObject *DistributedObjectStoreImpl::CreateObject(const std::string &s DistributedObject *DistributedObjectStoreImpl::CreateObject(const std::string &sessionId, uint32_t &status) { - HiTrace trace(std::string(__FUNCTION__)); + DataObjectHiTrace trace(std::string(__FUNCTION__)); if (flatObjectStore_ == nullptr) { LOG_ERROR("DistributedObjectStoreImpl::CreateObject store not opened!"); status = ERR_NULL_OBJECTSTORE; @@ -106,7 +106,7 @@ DistributedObject *DistributedObjectStoreImpl::CreateObject(const std::string &s uint32_t DistributedObjectStoreImpl::DeleteObject(const std::string &sessionId) { - HiTrace trace(std::string(__FUNCTION__)); + DataObjectHiTrace trace(std::string(__FUNCTION__)); if (flatObjectStore_ == nullptr) { LOG_ERROR("DistributedObjectStoreImpl::Sync object err "); return ERR_NULL_OBJECTSTORE; @@ -223,7 +223,11 @@ DistributedObjectStore *DistributedObjectStore::GetInstance(const std::string &b } // Use instMemory to make sure this singleton not free before other object. // This operation needn't to malloc memory, we needn't to check nullptr. - instPtr = new DistributedObjectStoreImpl(flatObjectStore); + instPtr = new (std::nothrow) DistributedObjectStoreImpl(flatObjectStore); + if (instPtr == nullptr) { + LOG_ERROR("no memory for DistributedObjectStoreImpl malloc!"); + return nullptr; + } } } return instPtr; diff --git a/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp b/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp index dba081c2c6a09b021939e563213ed44ade619006..96b87453bf1b22ff87310dc99d56cedb6a7c51f1 100644 --- a/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp +++ b/data_object/frameworks/innerkitsimpl/src/adaptor/flat_object_store.cpp @@ -276,9 +276,13 @@ int32_t CacheManager::SaveObject(const std::string &bundleName, const std::strin sptr proxy = ClientAdaptor::GetObjectService(); if (proxy == nullptr) { LOG_ERROR("proxy is nullptr."); + return ERR_PROCESSING; + } + sptr objectSaveCallback = new (std::nothrow) ObjectSaveCallback(callback); + if (objectSaveCallback == nullptr) { + LOG_ERROR("CacheManager::SaveObject no memory for ObjectSaveCallback malloc!"); return ERR_NULL_PTR; } - sptr objectSaveCallback = new ObjectSaveCallback(callback); int32_t status = proxy->ObjectStoreSave( bundleName, sessionId, deviceId, objectData, objectSaveCallback->AsObject().GetRefPtr()); if (status != SUCCESS) { @@ -294,9 +298,14 @@ int32_t CacheManager::RevokeSaveObject( sptr proxy = ClientAdaptor::GetObjectService(); if (proxy == nullptr) { LOG_ERROR("proxy is nullptr."); + return ERR_PROCESSING; + } + sptr objectRevokeSaveCallback = new (std::nothrow) + ObjectRevokeSaveCallback(callback); + if (objectRevokeSaveCallback == nullptr) { + LOG_ERROR("CacheManager::RevokeSaveObject no memory for ObjectRevokeSaveCallback malloc!"); return ERR_NULL_PTR; } - sptr objectRevokeSaveCallback = new ObjectRevokeSaveCallback(callback); int32_t status = proxy->ObjectStoreRevokeSave( bundleName, sessionId, objectRevokeSaveCallback->AsObject().GetRefPtr()); if (status != SUCCESS) { @@ -314,7 +323,11 @@ int32_t CacheManager::ResumeObject(const std::string &bundleName, const std::str LOG_ERROR("proxy is nullptr."); return ERR_NULL_PTR; } - sptr objectRetrieveCallback = new ObjectRetrieveCallback(callback); + sptr objectRetrieveCallback = new (std::nothrow) ObjectRetrieveCallback(callback); + if (objectRetrieveCallback == nullptr) { + LOG_ERROR("CacheManager::ResumeObject no memory for ObjectRetrieveCallback malloc!"); + return ERR_NULL_PTR; + } int32_t status = proxy->ObjectStoreRetrieve( bundleName, sessionId, objectRetrieveCallback->AsObject().GetRefPtr()); if (status != SUCCESS) { @@ -332,7 +345,11 @@ int32_t CacheManager::SubscribeDataChange(const std::string &bundleName, const s LOG_ERROR("proxy is nullptr."); return ERR_NULL_PTR; } - sptr objectRemoteResumeCallback = new ObjectChangeCallback(callback); + sptr objectRemoteResumeCallback = new (std::nothrow) ObjectChangeCallback(callback); + if (objectRemoteResumeCallback == nullptr) { + LOG_ERROR("CacheManager::SubscribeDataChange no memory for ObjectChangeCallback malloc!"); + return ERR_NULL_PTR; + } ClientAdaptor::RegisterClientDeathListener(bundleName, objectRemoteResumeCallback->AsObject()); int32_t status = proxy->RegisterDataObserver( bundleName, sessionId, objectRemoteResumeCallback->AsObject().GetRefPtr()); diff --git a/data_object/frameworks/innerkitsimpl/src/communicator/app_device_handler.cpp b/data_object/frameworks/innerkitsimpl/src/communicator/app_device_handler.cpp index 9518c61ea6a6c02c5dd8f0240920ca2eac220a59..3ccfca24d972697425e2ac5ad2c3c038d475014d 100644 --- a/data_object/frameworks/innerkitsimpl/src/communicator/app_device_handler.cpp +++ b/data_object/frameworks/innerkitsimpl/src/communicator/app_device_handler.cpp @@ -66,9 +66,9 @@ std::vector AppDeviceHandler::GetRemoteNodesBasicInfo() const return softbusAdapter_->GetRemoteNodesBasicInfo(); } -std::string AppDeviceHandler::GetUdidByNodeId(const std::string &nodeId) const +std::string AppDeviceHandler::GetUuidByNodeId(const std::string &nodeId) const { - return softbusAdapter_->GetUdidByNodeId(nodeId); + return devManager_->GetUuidByNodeId(nodeId); } } // namespace ObjectStore } // namespace OHOS diff --git a/data_object/frameworks/innerkitsimpl/src/communicator/dev_manager.cpp b/data_object/frameworks/innerkitsimpl/src/communicator/dev_manager.cpp index ff03a7cf86f70b39131ac0953ad6c51dc9cdaa6d..0d6442f4a98f7c2a82806b3ac7b2d094e989f51d 100644 --- a/data_object/frameworks/innerkitsimpl/src/communicator/dev_manager.cpp +++ b/data_object/frameworks/innerkitsimpl/src/communicator/dev_manager.cpp @@ -44,24 +44,24 @@ private: void DMStateCallback::OnDeviceOnline(const DmDeviceInfo &deviceInfo) { - std::string udid = softBusAdapter_->GetUdidByNodeId(std::string(deviceInfo.networkId)); - LOG_INFO("[Online] id:%{public}s, name:%{public}s, typeId:%{public}d", SoftBusAdapter::ToBeAnonymous(udid).c_str(), + std::string uuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(deviceInfo.networkId)); + LOG_INFO("[Online] id:%{public}s, name:%{public}s, typeId:%{public}d", SoftBusAdapter::ToBeAnonymous(uuid).c_str(), deviceInfo.deviceName, deviceInfo.deviceTypeId); NotifyAll(deviceInfo, DeviceChangeType::DEVICE_ONLINE); } void DMStateCallback::OnDeviceOffline(const DmDeviceInfo &deviceInfo) { - std::string udid = softBusAdapter_->GetUdidByNodeId(std::string(deviceInfo.networkId)); + std::string uuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(deviceInfo.networkId)); LOG_INFO("[Offline] id:%{public}s, name:%{public}s, typeId:%{public}d", - SoftBusAdapter::ToBeAnonymous(udid).c_str(), deviceInfo.deviceName, deviceInfo.deviceTypeId); + SoftBusAdapter::ToBeAnonymous(uuid).c_str(), deviceInfo.deviceName, deviceInfo.deviceTypeId); NotifyAll(deviceInfo, DeviceChangeType::DEVICE_OFFLINE); } void DMStateCallback::OnDeviceChanged(const DmDeviceInfo &deviceInfo) { - std::string udid = softBusAdapter_->GetUdidByNodeId(std::string(deviceInfo.networkId)); - LOG_INFO("[InfoChange] id:%{public}s, name:%{public}s", SoftBusAdapter::ToBeAnonymous(udid).c_str(), + std::string uuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(deviceInfo.networkId)); + LOG_INFO("[InfoChange] id:%{public}s, name:%{public}s", SoftBusAdapter::ToBeAnonymous(uuid).c_str(), deviceInfo.deviceName); } @@ -136,5 +136,17 @@ void DevManager::RegisterDevCallback() th.detach(); } +std::string DevManager::GetUuidByNodeId(const std::string &nodeId) const +{ + std::string uuid = ""; + int32_t ret = DistributedHardware::DeviceManager::GetInstance().GetEncryptedUuidByNetworkId( + "ohos.objectstore", nodeId.c_str(), uuid); + if (ret != DM_OK) { + LOG_WARN("GetEncryptedUuidByNetworkId error, nodeId:%{public}s", SoftBusAdapter::ToBeAnonymous(nodeId).c_str()); + return ""; + } + return uuid; +} + } // namespace ObjectStore } // namespace OHOS \ No newline at end of file diff --git a/data_object/frameworks/innerkitsimpl/src/communicator/softbus_adapter_standard.cpp b/data_object/frameworks/innerkitsimpl/src/communicator/softbus_adapter_standard.cpp index d72b0f83b06ce4aa23f9a0fc0029d21a9ff59491..dea59211b0aa19eb2a71448bcee45b2e1121e386 100644 --- a/data_object/frameworks/innerkitsimpl/src/communicator/softbus_adapter_standard.cpp +++ b/data_object/frameworks/innerkitsimpl/src/communicator/softbus_adapter_standard.cpp @@ -24,6 +24,7 @@ #include "session.h" #include "softbus_adapter.h" #include "softbus_bus_center.h" +#include "dev_manager.h" namespace OHOS { namespace ObjectStore { @@ -38,7 +39,6 @@ constexpr int32_t SOFTBUS_ERR = 1; constexpr int32_t INVALID_SESSION_ID = -1; constexpr int32_t SESSION_NAME_SIZE_MAX = 65; constexpr int32_t DEVICE_ID_SIZE_MAX = 65; -constexpr int32_t ID_BUF_LEN = 65; constexpr size_t TASK_CAPACITY_MAX = 15; using namespace std; @@ -127,15 +127,15 @@ void SoftBusAdapter::NotifyAll(const DeviceInfo &deviceInfo, const DeviceChangeT } } LOG_DEBUG("high"); - std::string udid = GetUdidByNodeId(deviceInfo.deviceId); - LOG_DEBUG("[Notify] to DB from: %{public}s, type:%{public}d", ToBeAnonymous(udid).c_str(), type); + std::string uuid = DevManager::GetInstance()->GetUuidByNodeId(deviceInfo.deviceId); + LOG_DEBUG("[Notify] to DB from: %{public}s, type:%{public}d", ToBeAnonymous(uuid).c_str(), type); UpdateRelationship(deviceInfo.deviceId, type); for (const auto &device : listeners) { if (device == nullptr) { continue; } if (device->GetChangeLevelType() == ChangeLevelType::HIGH) { - DeviceInfo di = { udid, deviceInfo.deviceName, deviceInfo.deviceType }; + DeviceInfo di = { uuid, deviceInfo.deviceName, deviceInfo.deviceType }; device->OnDeviceChanged(di, type); break; } @@ -146,7 +146,7 @@ void SoftBusAdapter::NotifyAll(const DeviceInfo &deviceInfo, const DeviceChangeT continue; } if (device->GetChangeLevelType() == ChangeLevelType::LOW) { - DeviceInfo di = { udid, deviceInfo.deviceName, deviceInfo.deviceType }; + DeviceInfo di = { uuid, deviceInfo.deviceName, deviceInfo.deviceType }; device->OnDeviceChanged(di, DeviceChangeType::DEVICE_OFFLINE); device->OnDeviceChanged(di, type); } @@ -157,7 +157,7 @@ void SoftBusAdapter::NotifyAll(const DeviceInfo &deviceInfo, const DeviceChangeT continue; } if (device->GetChangeLevelType() == ChangeLevelType::MIN) { - DeviceInfo di = { udid, deviceInfo.deviceName, deviceInfo.deviceType }; + DeviceInfo di = { uuid, deviceInfo.deviceName, deviceInfo.deviceType }; device->OnDeviceChanged(di, type); } } @@ -180,8 +180,8 @@ std::vector SoftBusAdapter::GetDeviceList() const LOG_INFO("GetAllNodeDeviceInfo success infoNum=%{public}d", infoNum); for (int i = 0; i < infoNum; i++) { - std::string udid = GetUdidByNodeId(std::string(info[i].networkId)); - DeviceInfo deviceInfo = { udid, std::string(info[i].deviceName), std::to_string(info[i].deviceTypeId) }; + std::string uuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(info[i].networkId)); + DeviceInfo deviceInfo = { uuid, std::string(info[i].deviceName), std::to_string(info[i].deviceTypeId) }; dis.push_back(deviceInfo); } if (info != nullptr) { @@ -202,25 +202,13 @@ DeviceInfo SoftBusAdapter::GetLocalDevice() LOG_ERROR("GetLocalNodeDeviceInfo error"); return DeviceInfo(); } - std::string uuid = GetUdidByNodeId(std::string(info.networkId)); + std::string uuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(info.networkId)); LOG_DEBUG("[LocalDevice] id:%{private}s, name:%{private}s, type:%{private}d", ToBeAnonymous(uuid).c_str(), info.deviceName, info.deviceTypeId); localInfo_ = { uuid, std::string(info.deviceName), std::to_string(info.deviceTypeId) }; return localInfo_; } -std::string SoftBusAdapter::GetUdidByNodeId(const std::string &nodeId) const -{ - char udid[ID_BUF_LEN] = { 0 }; - int32_t ret = GetNodeKeyInfo("ohos.objectstore", nodeId.c_str(), NodeDeviceInfoKey::NODE_KEY_UDID, - reinterpret_cast(udid), ID_BUF_LEN); - if (ret != SOFTBUS_OK) { - LOG_WARN("GetNodeKeyInfo error, nodeId:%{public}s", ToBeAnonymous(nodeId).c_str()); - return ""; - } - return std::string(udid); -} - DeviceInfo SoftBusAdapter::GetLocalBasicInfo() const { LOG_DEBUG("begin"); @@ -265,19 +253,19 @@ std::vector SoftBusAdapter::GetRemoteNodesBasicInfo() const void SoftBusAdapter::UpdateRelationship(const std::string &networkid, const DeviceChangeType &type) { - auto udid = GetUdidByNodeId(networkid); + auto uuid = DevManager::GetInstance()->GetUuidByNodeId(networkid); lock_guard lock(networkMutex_); switch (type) { case DeviceChangeType::DEVICE_OFFLINE: { - auto size = this->networkId2Udid_.erase(networkid); + auto size = this->networkId2Uuid_.erase(networkid); if (size == 0) { LOG_WARN("not found id:%{public}s.", networkid.c_str()); } break; } case DeviceChangeType::DEVICE_ONLINE: { - std::pair value = { networkid, udid }; - auto res = this->networkId2Udid_.insert(std::move(value)); + std::pair value = { networkid, uuid }; + auto res = this->networkId2Uuid_.insert(std::move(value)); if (!res.second) { LOG_WARN("insert failed."); } @@ -293,8 +281,8 @@ std::string SoftBusAdapter::ToNodeID(const std::string &nodeId) const { { lock_guard lock(networkMutex_); - for (auto const &e : networkId2Udid_) { - if (nodeId == e.second) { // id is udid + for (auto const &e : networkId2Uuid_) { + if (nodeId == e.second) { // id is uuid return e.first; } } @@ -309,12 +297,12 @@ std::string SoftBusAdapter::ToNodeID(const std::string &nodeId) const if (ret == SOFTBUS_OK) { lock_guard lock(networkMutex_); for (int i = 0; i < infoNum; i++) { - if (networkId2Udid_.find(info[i].networkId) != networkId2Udid_.end()) { + if (networkId2Uuid_.find(info[i].networkId) != networkId2Uuid_.end()) { continue; } - auto udid = GetUdidByNodeId(std::string(info[i].networkId)); - networkId2Udid_.insert({ info[i].networkId, udid }); - if (udid == nodeId) { + auto uuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(info[i].networkId)); + networkId2Uuid_.insert({ info[i].networkId, uuid }); + if (uuid == nodeId) { networkId = info[i].networkId; } } @@ -588,15 +576,15 @@ int AppDataListenerWrap::OnSessionOpened(int sessionId, int result) LOG_WARN("get my peer device id failed, session id is %{public}d.", sessionId); return SOFTBUS_ERR; } - std::string peerUdid = softBusAdapter_->GetUdidByNodeId(std::string(peerDevId)); + std::string peerUuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(peerDevId)); LOG_DEBUG("[SessionOpen] mySessionName:%{public}s, " "peerSessionName:%{public}s, peerDevId:%{public}s", - mySessionName, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUdid).c_str()); + mySessionName, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUuid).c_str()); if (strlen(peerSessionName) < 1) { - softBusAdapter_->InsertSession(std::string(mySessionName) + peerUdid); + softBusAdapter_->InsertSession(std::string(mySessionName) + peerUuid); } else { - softBusAdapter_->InsertSession(std::string(peerSessionName) + peerUdid); + softBusAdapter_->InsertSession(std::string(peerSessionName) + peerUuid); } return 0; } @@ -624,15 +612,15 @@ void AppDataListenerWrap::OnSessionClosed(int sessionId) LOG_WARN("get my peer device id failed, session id is %{public}d.", sessionId); return; } - std::string peerUdid = softBusAdapter_->GetUdidByNodeId(std::string(peerDevId)); + std::string peerUuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(peerDevId)); LOG_DEBUG("[SessionClosed] mySessionName:%{public}s, " "peerSessionName:%{public}s, peerDevId:%{public}s", - mySessionName, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUdid).c_str()); + mySessionName, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUuid).c_str()); if (strlen(peerSessionName) < 1) { - softBusAdapter_->DeleteSession(std::string(mySessionName) + peerUdid); + softBusAdapter_->DeleteSession(std::string(mySessionName) + peerUuid); } else { - softBusAdapter_->DeleteSession(std::string(peerSessionName) + peerUdid); + softBusAdapter_->DeleteSession(std::string(peerSessionName) + peerUuid); } } @@ -654,11 +642,11 @@ void AppDataListenerWrap::OnMessageReceived(int sessionId, const void *data, uns LOG_WARN("get my peer device id failed, session id is %{public}d.", sessionId); return; } - std::string peerUdid = softBusAdapter_->GetUdidByNodeId(std::string(peerDevId)); + std::string peerUuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(peerDevId)); LOG_DEBUG("[MessageReceived] session id:%{public}d, " "peerSessionName:%{public}s, peerDevId:%{public}s", - sessionId, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUdid).c_str()); - NotifyDataListeners(reinterpret_cast(data), dataLen, peerUdid, { std::string(peerSessionName) }); + sessionId, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUuid).c_str()); + NotifyDataListeners(reinterpret_cast(data), dataLen, peerUuid, { std::string(peerSessionName) }); } void AppDataListenerWrap::OnBytesReceived(int sessionId, const void *data, unsigned int dataLen) @@ -679,11 +667,11 @@ void AppDataListenerWrap::OnBytesReceived(int sessionId, const void *data, unsig LOG_WARN("get my peer device id failed, session id is %{public}d.", sessionId); return; } - std::string peerUdid = softBusAdapter_->GetUdidByNodeId(std::string(peerDevId)); + std::string peerUuid = DevManager::GetInstance()->GetUuidByNodeId(std::string(peerDevId)); LOG_DEBUG("[BytesReceived] session id:%{public}d, peerSessionName:%{public}s, " "peerDevId:%{public}s", - sessionId, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUdid).c_str()); - NotifyDataListeners(reinterpret_cast(data), dataLen, peerUdid, { std::string(peerSessionName) }); + sessionId, peerSessionName, SoftBusAdapter::ToBeAnonymous(peerUuid).c_str()); + NotifyDataListeners(reinterpret_cast(data), dataLen, peerUuid, { std::string(peerSessionName) }); } void AppDataListenerWrap::NotifyDataListeners( diff --git a/data_object/frameworks/innerkitsimpl/test/unittest/src/communicator_test.cpp b/data_object/frameworks/innerkitsimpl/test/unittest/src/communicator_test.cpp index 15249e706f1ac966f2b4d602c04f01fc97496258..8d6d3adb68de6f123ca441e9c8e6024ef9be69fe 100644 --- a/data_object/frameworks/innerkitsimpl/test/unittest/src/communicator_test.cpp +++ b/data_object/frameworks/innerkitsimpl/test/unittest/src/communicator_test.cpp @@ -26,6 +26,7 @@ #include "token_setproc.h" #include "app_types.h" #include "softbus_adapter.h" +#include "dev_manager.h" #include "app_device_status_change_listener.h" #include "app_data_change_listener.h" #include "mock_app_device_change_listener.h" @@ -456,16 +457,14 @@ HWTEST_F(NativeCommunicatorTest, SoftBusAdapter_GetLocalDevice_001, TestSize.Lev /** - * @tc.name: SoftBusAdapter_GetUdidByNodeId_001 - * @tc.desc: test SoftBusAdapter GetUdidByNodeId. + * @tc.name: DevManager_GetUuidByNodeId_001 + * @tc.desc: test DevManager GetUuidByNodeId. * @tc.type: FUNC */ -HWTEST_F(NativeCommunicatorTest, SoftBusAdapter_GetUdidByNodeId_001, TestSize.Level1) +HWTEST_F(NativeCommunicatorTest, DevManager_GetUuidByNodeId_001, TestSize.Level1) { std::string nodeId = "nodeId01"; - SoftBusAdapter *softBusAdapter = new SoftBusAdapter(); - auto ret = softBusAdapter->GetUdidByNodeId(nodeId); + auto ret = DevManager::GetInstance()->GetUuidByNodeId(nodeId); EXPECT_EQ(true, ret.empty()); - delete softBusAdapter; } } \ No newline at end of file diff --git a/data_object/frameworks/innerkitsimpl/test/unittest/src/object_store_test.cpp b/data_object/frameworks/innerkitsimpl/test/unittest/src/object_store_test.cpp index 4effc12b380c26120e441d801bfd00d5015a42c9..2a7ca405100c20f28fc6b666dbf9e2bc0311fea9 100644 --- a/data_object/frameworks/innerkitsimpl/test/unittest/src/object_store_test.cpp +++ b/data_object/frameworks/innerkitsimpl/test/unittest/src/object_store_test.cpp @@ -64,39 +64,6 @@ void StatusNotifierImpl::OnChanged(const std::string &sessionId, const std::string &onlineStatus) { } -static void TestSetSessionId(std::string bundleName, std::string sessionId) -{ - DistributedObjectStore *objectStore = DistributedObjectStore::GetInstance(bundleName); - EXPECT_NE(nullptr, objectStore); - DistributedObject *object = objectStore->CreateObject(sessionId); - EXPECT_NE(nullptr, object); - - uint32_t ret = objectStore->DeleteObject(sessionId); - EXPECT_EQ(SUCCESS, ret); -} - -static void TestSaveAndRevokeSave(std::string bundleName, std::string sessionId) -{ - DistributedObjectStore *objectStore = DistributedObjectStore::GetInstance(bundleName); - EXPECT_NE(nullptr, objectStore); - DistributedObject *object = objectStore->CreateObject(sessionId); - EXPECT_NE(nullptr, object); - - uint32_t ret = object->PutString("name", "zhangsan"); - EXPECT_EQ(SUCCESS, ret); - ret = object->PutDouble("salary", SALARY); - EXPECT_EQ(SUCCESS, ret); - ret = object->PutBoolean("isTrue", true); - EXPECT_EQ(SUCCESS, ret); - - ret = object->Save("local"); - EXPECT_EQ(SUCCESS, ret); - ret = object->RevokeSave(); - EXPECT_EQ(SUCCESS, ret); - - ret = objectStore->DeleteObject(sessionId); - EXPECT_EQ(SUCCESS, ret); -} void GrantPermissionNative() { @@ -400,9 +367,18 @@ HWTEST_F(NativeObjectStoreTest, DistributedObject_GetSessionId_001, TestSize.Lev */ HWTEST_F(NativeObjectStoreTest, DistributedObject_TestSetSessionId_001, TestSize.Level1) { - std::thread t1(TestSetSessionId, "default1", "session1"); - std::thread t2(TestSetSessionId, "default2", "session2"); - std::thread t3(TestSetSessionId, "default3", "session3"); + auto testSetSessionId = [] (std::string bundleName, std::string sessionId) { + DistributedObjectStore *objectStore = DistributedObjectStore::GetInstance(bundleName); + EXPECT_NE(nullptr, objectStore); + DistributedObject *object = objectStore->CreateObject(sessionId); + EXPECT_NE(nullptr, object); + + uint32_t ret = objectStore->DeleteObject(sessionId); + EXPECT_EQ(SUCCESS, ret); + }; + std::thread t1(testSetSessionId, "default1", "session1"); + std::thread t2(testSetSessionId, "default2", "session2"); + std::thread t3(testSetSessionId, "default3", "session3"); t1.join(); t2.join(); t3.join(); @@ -454,7 +430,25 @@ HWTEST_F(NativeObjectStoreTest, DistributedObject_Save_RevokeSave_001, TestSize. { std::string bundleName = "default"; std::string sessionId = "123456"; - TestSaveAndRevokeSave(bundleName, sessionId); + DistributedObjectStore *objectStore = DistributedObjectStore::GetInstance(bundleName); + EXPECT_NE(nullptr, objectStore); + DistributedObject *object = objectStore->CreateObject(sessionId); + EXPECT_NE(nullptr, object); + + uint32_t ret = object->PutString("name", "zhangsan"); + EXPECT_EQ(SUCCESS, ret); + ret = object->PutDouble("salary", SALARY); + EXPECT_EQ(SUCCESS, ret); + ret = object->PutBoolean("isTrue", true); + EXPECT_EQ(SUCCESS, ret); + + ret = object->Save("local"); + EXPECT_EQ(SUCCESS, ret); + ret = object->RevokeSave(); + EXPECT_EQ(SUCCESS, ret); + + ret = objectStore->DeleteObject(sessionId); + EXPECT_EQ(SUCCESS, ret); } /** @@ -464,9 +458,30 @@ HWTEST_F(NativeObjectStoreTest, DistributedObject_Save_RevokeSave_001, TestSize. */ HWTEST_F(NativeObjectStoreTest, DistributedObject_Save_RevokeSave_002, TestSize.Level1) { - std::thread t1(TestSaveAndRevokeSave, "default1", "session1"); - std::thread t2(TestSaveAndRevokeSave, "default2", "session2"); - std::thread t3(TestSaveAndRevokeSave, "default3", "session3"); + auto testSaveAndRevokeSave = [](std::string bundleName, std::string sessionId) { + DistributedObjectStore *objectStore = DistributedObjectStore::GetInstance(bundleName); + EXPECT_NE(nullptr, objectStore); + DistributedObject *object = objectStore->CreateObject(sessionId); + EXPECT_NE(nullptr, object); + + uint32_t ret = object->PutString("name", "zhangsan"); + EXPECT_EQ(SUCCESS, ret); + ret = object->PutDouble("salary", SALARY); + EXPECT_EQ(SUCCESS, ret); + ret = object->PutBoolean("isTrue", true); + EXPECT_EQ(SUCCESS, ret); + + ret = object->Save("local"); + EXPECT_EQ(SUCCESS, ret); + ret = object->RevokeSave(); + EXPECT_EQ(SUCCESS, ret); + + ret = objectStore->DeleteObject(sessionId); + EXPECT_EQ(SUCCESS, ret); + }; + std::thread t1(testSaveAndRevokeSave, "default1", "session1"); + std::thread t2(testSaveAndRevokeSave, "default2", "session2"); + std::thread t3(testSaveAndRevokeSave, "default3", "session3"); t1.join(); t2.join(); t3.join(); diff --git a/data_object/frameworks/jskitsimpl/include/adaptor/js_common.h b/data_object/frameworks/jskitsimpl/include/adaptor/js_common.h index 33b8cf7c9bf2ca6f76282114193867a8084bd5c6..dddd4732bec322bbff44bf9340f6945f119b5e74 100644 --- a/data_object/frameworks/jskitsimpl/include/adaptor/js_common.h +++ b/data_object/frameworks/jskitsimpl/include/adaptor/js_common.h @@ -24,6 +24,7 @@ namespace OHOS::ObjectStore { return nullptr; \ } \ } + #define CHECK_EQUAL_WITH_RETURN_VOID(status, value) \ { \ if (status != value) { \ @@ -31,6 +32,7 @@ namespace OHOS::ObjectStore { return; \ } \ } + #define CHECK_EQUAL_WITH_RETURN_FALSE(status, value) \ { \ if (status != value) { \ @@ -38,6 +40,7 @@ namespace OHOS::ObjectStore { return false; \ } \ } + #define ASSERT_MATCH_ELSE_RETURN_VOID(condition) \ { \ if (!(condition)) { \ @@ -45,6 +48,7 @@ namespace OHOS::ObjectStore { return; \ } \ } + #define ASSERT_MATCH_ELSE_RETURN_NULL(condition) \ { \ if (!(condition)) { \ @@ -52,6 +56,7 @@ namespace OHOS::ObjectStore { return nullptr; \ } \ } + #define ASSERT_MATCH_ELSE_GOTO_ERROR(condition) \ { \ if (!(condition)) { \ @@ -59,6 +64,27 @@ namespace OHOS::ObjectStore { goto ERROR; \ } \ } + +#define CHECK_API_VALID_ELSE_RETURN_VOID(assertion) \ + do { \ + if (!(assertion)) { \ + std::shared_ptr apiError = std::make_shared(); \ + ctxt->SetError(apiError); \ + ctxt->status = napi_generic_failure; \ + return; \ + } \ + } while (0) + +#define CHECK_VALID_ELSE_RETURN_VOID(assertion, msg) \ + do { \ + if (!(assertion)) { \ + std::shared_ptr innerError = std::make_shared(); \ + ctxt->SetError(innerError); \ + ctxt->status = napi_generic_failure; \ + ctxt->message = msg; \ + return; \ + } \ + } while (0) } // namespace OHOS::ObjectStore static const char *CHANGE = "change"; static const char *STATUS = "status"; diff --git a/data_object/frameworks/jskitsimpl/include/common/object_error.h b/data_object/frameworks/jskitsimpl/include/common/object_error.h index a982e9bcb45469bc1c9b4ecc693586dfdde514bd..8ebe82e4deeb8843baf5208dd503a12248dd40a2 100644 --- a/data_object/frameworks/jskitsimpl/include/common/object_error.h +++ b/data_object/frameworks/jskitsimpl/include/common/object_error.h @@ -20,6 +20,7 @@ namespace OHOS { namespace ObjectStore { +static const int EXCEPTION_DEVICE_NOT_SUPPORT = 801; static const int EXCEPTION_PARAMETER_CHECK = 401; static const int EXCEPTION_NO_PERMISSION = 201; static const int EXCEPTION_DB_EXIST = 15400001; @@ -73,6 +74,13 @@ public: std::string GetMessage() override; int GetCode() override; }; + +class DeviceNotSupportedError : public Error { +public: + DeviceNotSupportedError() = default; + std::string GetMessage() override; + int GetCode() override; +}; } // namespace ObjectStore } // namespace OHOS diff --git a/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobject.cpp b/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobject.cpp index 5800f164c459dad02c648acc24726436408563fa..d6686780892de2d9bb94bc61a99dc1959d697ef3 100644 --- a/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobject.cpp +++ b/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobject.cpp @@ -248,6 +248,16 @@ napi_value JSDistributedObject::JSSave(napi_env env, napi_callback_info info) }; ctxt->GetCbInfo(env, info, getCbOpe); CHECH_STATUS_ERRCODE(env, ctxt->status != napi_invalid_arg, ctxt->error); + auto execute = [ctxt]() { + LOG_INFO("start"); + CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null"); + CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null"); + uint32_t status = ctxt->wrapper->GetObject()->Save(ctxt->deviceId); + CHECK_API_VALID_ELSE_RETURN_VOID(status != ERR_PROCESSING); + CHECK_VALID_ELSE_RETURN_VOID(status == SUCCESS, "operation failed"); + ctxt->status = napi_ok; + LOG_INFO("end"); + }; auto output = [env, ctxt](napi_value &result) { if (ctxt->status == napi_ok) { CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null"); @@ -258,22 +268,6 @@ napi_value JSDistributedObject::JSSave(napi_env env, napi_callback_info info) CHECK_STATUS_RETURN_VOID(ctxt, "output failed!"); } }; - auto execute = [ctxt]() { - LOG_INFO("start"); - CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null"); - CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null"); - uint32_t status = ctxt->wrapper->GetObject()->Save(ctxt->deviceId); - if (status != SUCCESS) { - LOG_ERROR("Save failed, status = %{public}d", status); - auto innerError = std::make_shared(); - ctxt->SetError(innerError); - ctxt->status = napi_generic_failure; - ctxt->message = std::string("operation failed"); - return; - } - ctxt->status = napi_ok; - LOG_INFO("end"); - }; return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); } @@ -300,7 +294,15 @@ napi_value JSDistributedObject::JSRevokeSave(napi_env env, napi_callback_info in napi_throw_error((env), std::to_string(ctxt->error->GetCode()).c_str(), ctxt->error->GetMessage().c_str()); return nullptr; } - + auto execute = [ctxt]() { + CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null"); + CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null"); + uint32_t status = ctxt->wrapper->GetObject()->RevokeSave(); + CHECK_API_VALID_ELSE_RETURN_VOID(status != ERR_PROCESSING); + CHECK_VALID_ELSE_RETURN_VOID(status == SUCCESS, "operation failed"); + ctxt->status = napi_ok; + LOG_INFO("end"); + }; auto output = [env, ctxt](napi_value &result) { if (ctxt->status == napi_ok) { CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null"); @@ -311,25 +313,7 @@ napi_value JSDistributedObject::JSRevokeSave(napi_env env, napi_callback_info in CHECK_STATUS_RETURN_VOID(ctxt, "output failed!"); } }; - return NapiQueue::AsyncWork( - env, ctxt, std::string(__FUNCTION__), - [ctxt]() { - LOG_INFO("start"); - CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null"); - CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null"); - uint32_t status = ctxt->wrapper->GetObject()->RevokeSave(); - if (status != SUCCESS) { - LOG_ERROR("Save failed, status = %{public}d", status); - auto innerError = std::make_shared(); - ctxt->SetError(innerError); - ctxt->status = napi_generic_failure; - ctxt->message = std::string("operation failed"); - return; - } - ctxt->status = napi_ok; - LOG_INFO("end"); - }, - output); + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); } napi_value JSDistributedObject::GetSaveResultCons( diff --git a/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobjectstore.cpp b/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobjectstore.cpp index e8c92e825e7ee2c2c7b40c07bf3443976b633dd4..2ff2021027ff0cda4fb54ff73db26878e6793c5f 100644 --- a/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobjectstore.cpp +++ b/data_object/frameworks/jskitsimpl/src/adaptor/js_distributedobjectstore.cpp @@ -108,7 +108,11 @@ napi_value JSDistributedObjectStore::NewDistributedObject( napi_value result; napi_status status = napi_new_instance(env, JSDistributedObject::GetCons(env), 0, nullptr, &result); CHECK_EQUAL_WITH_RETURN_NULL(status, napi_ok); - JSObjectWrapper *objectWrapper = new JSObjectWrapper(objectStore, object); + JSObjectWrapper *objectWrapper = new (std::nothrow) JSObjectWrapper(objectStore, object); + if (objectWrapper == nullptr) { + LOG_ERROR("JSDistributedObjectStore::NewDistributedObject no memory for objectWrapper malloc!"); + return nullptr; + } objectWrapper->SetObjectId(objectId); status = napi_wrap( env, result, objectWrapper, diff --git a/data_object/frameworks/jskitsimpl/src/adaptor/js_watcher.cpp b/data_object/frameworks/jskitsimpl/src/adaptor/js_watcher.cpp index 40f964723426f183b1f57251af89a174438b1380..9e1895d00db962a804d1d3d830678c3ebc9c3af7 100644 --- a/data_object/frameworks/jskitsimpl/src/adaptor/js_watcher.cpp +++ b/data_object/frameworks/jskitsimpl/src/adaptor/js_watcher.cpp @@ -105,7 +105,11 @@ void JSWatcher::Emit(const char *type, const std::string &sessionId, const std:: } for (EventHandler *handler = listener->handlers_; handler != nullptr; handler = handler->next) { - ChangeArgs *changeArgs = new ChangeArgs(handler->callbackRef, sessionId, changeData); + ChangeArgs *changeArgs = new (std::nothrow) ChangeArgs(handler->callbackRef, sessionId, changeData); + if (changeArgs == nullptr) { + LOG_ERROR("JSWatcher::Emit no memory for changeArgs malloc!"); + return; + } CallFunction(ProcessChange, changeArgs); } } @@ -171,7 +175,11 @@ void JSWatcher::Emit( } for (EventHandler *handler = listener->handlers_; handler != nullptr; handler = handler->next) { - StatusArgs *changeArgs = new StatusArgs(handler->callbackRef, sessionId, networkId, status); + StatusArgs *changeArgs = new (std::nothrow) StatusArgs(handler->callbackRef, sessionId, networkId, status); + if (changeArgs == nullptr) { + LOG_ERROR("JSWatcher::Emit no memory for StatusArgs malloc!"); + return; + } CallFunction(ProcessStatus, changeArgs); } return; @@ -248,10 +256,18 @@ bool EventListener::Add(napi_env env, napi_value handler) } if (handlers_ == nullptr) { - handlers_ = new EventHandler(); + handlers_ = new (std::nothrow) EventHandler(); + if (handlers_ == nullptr) { + LOG_ERROR("EventListener::Add no memory for EventHandler malloc!"); + return false; + } handlers_->next = nullptr; } else { - auto temp = new EventHandler(); + auto temp = new (std::nothrow) EventHandler(); + if (temp == nullptr) { + LOG_ERROR("EventListener::Add no memory for EventHandler malloc!"); + return false; + } temp->next = handlers_; handlers_ = temp; } diff --git a/data_object/frameworks/jskitsimpl/src/common/object_error.cpp b/data_object/frameworks/jskitsimpl/src/common/object_error.cpp index 0f03e14b35911adb857621b8cf0247269b2c7c18..12347fd0d2022895f9fcc68068e56742e2591120 100644 --- a/data_object/frameworks/jskitsimpl/src/common/object_error.cpp +++ b/data_object/frameworks/jskitsimpl/src/common/object_error.cpp @@ -67,5 +67,15 @@ int InnerError::GetCode() { return EXCEPTION_INNER; } + +std::string DeviceNotSupportedError::GetMessage() +{ + return "Capability not supported."; +} + +int DeviceNotSupportedError::GetCode() +{ + return EXCEPTION_DEVICE_NOT_SUPPORT; +} } // namespace ObjectStore } // namespace OHOS \ No newline at end of file diff --git a/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunit.test.js b/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunit.test.js index 380d88084ad1fa9cee32a522bd7b99c6e369d6ef..aed6d72f88a9f24a904d03c8e31ee7bdc7306f89 100644 --- a/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunit.test.js +++ b/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunit.test.js @@ -63,6 +63,7 @@ function statusCallback4(sessionId, networkId, status) { const TIMEOUT = 1500; const PERMISSION_USER_SET = 1; const PERMISSION_USER_NAME = "ohos.permission.DISTRIBUTED_DATASYNC"; +const CATCH_ERR = -1; var tokenID = undefined; async function grantPerm() { console.info("====grant Permission start===="); @@ -677,33 +678,74 @@ describe('objectStoreTest',function () { * @tc.name: testSave001 * @tc.desc: test save local * @tc.type: FUNC - * @tc.require: I4WDAK + * @tc.require: */ - it('testSave001', 0, async function () { + it('testSave001', 0, async function (done) { console.log(TAG + "************* testSave001 start *************"); var g_object = distributedObject.createDistributedObject({ name: "Amy", age: 18, isVis: false }); expect(g_object == undefined).assertEqual(false); - g_object.setSessionId("tmpsession1"); - expect("tmpsession1" == g_object.__sessionId).assertEqual(true); - - let result = await g_object.save("local"); - expect(result.sessionId == "tmpsession1").assertEqual(true); - expect(result.version == g_object.__version).assertEqual(true); - expect(result.deviceId == "local").assertEqual(true); + g_object.setSessionId("testSession001"); + expect("testSession001" == g_object.__sessionId).assertEqual(true); + + g_object.save("local").then((ret) => { + expect(ret.sessionId == "testSession001").assertEqual(true); + expect(ret.version == g_object.__version).assertEqual(true); + expect(ret.deviceId == "local").assertEqual(true); + done(); + + g_object.setSessionId(""); + g_object.name = undefined; + g_object.age = undefined; + g_object.isVis = undefined; + g_object.setSessionId("testSession001"); + + expect(g_object.name == "Amy").assertEqual(true); + expect(g_object.age == 18).assertEqual(true); + expect(g_object.isVis == false).assertEqual(true); + }).catch((err) => { + expect("801").assertEqual(err.code.toString()); + done(); + }); + console.log(TAG + "************* testSave001 end *************"); + }) - g_object.setSessionId(""); - g_object.name = undefined; - g_object.age = undefined; - g_object.isVis = undefined; - g_object.setSessionId("tmpsession1"); + /** + * @tc.name: testSave002 + * @tc.desc: test save local + * @tc.type: FUNC + * @tc.require: + */ + it('testSave002', 0, async function (done) { + console.log(TAG + "************* testSave002 start *************"); + var g_object = distributedObject.createDistributedObject({ name: "Amy", age: 18, isVis: false }); + expect(g_object == undefined).assertEqual(false); - expect(g_object.name == "Amy").assertEqual(true); - expect(g_object.age == 18).assertEqual(true); - expect(g_object.isVis == false).assertEqual(true); - console.log(TAG + "************* testSave001 end *************"); - g_object.setSessionId(""); + g_object.setSessionId("testSession002"); + expect("testSession002" == g_object.__sessionId).assertEqual(true); + g_object.save("local", (err, result) => { + if (err) { + expect("801").assertEqual(err.code.toString()); + done(); + return; + } + expect(result.sessionId == "testSession002").assertEqual(true); + expect(result.version == g_object.__version).assertEqual(true); + expect(result.deviceId == "local").assertEqual(true); + done(); + + g_object.setSessionId(""); + g_object.name = undefined; + g_object.age = undefined; + g_object.isVis = undefined; + g_object.setSessionId("testSession002"); + + expect(g_object.name == "Amy").assertEqual(true); + expect(g_object.age == 18).assertEqual(true); + expect(g_object.isVis == false).assertEqual(true); + }) + console.log(TAG + "************* testSave002 end *************"); }) /** @@ -712,36 +754,92 @@ describe('objectStoreTest',function () { * @tc.type: FUNC * @tc.require: I4WDAK */ - it('testRevokeSave001', 0, async function () { + it('testRevokeSave001', 0, async function (done) { console.log(TAG + "************* testRevokeSave001 start *************"); var g_object = distributedObject.createDistributedObject({ name: "Amy", age: 18, isVis: false }); expect(g_object == undefined).assertEqual(false); - g_object.setSessionId("123456"); - expect("123456" == g_object.__sessionId).assertEqual(true); + g_object.setSessionId("testSession003"); + expect("testSession003" == g_object.__sessionId).assertEqual(true); - let result = await g_object.save("local"); - expect(result.sessionId == "123456").assertEqual(true); - expect(result.version == g_object.__version).assertEqual(true); - expect(result.deviceId == "local").assertEqual(true); + g_object.save("local", (err, result) => { + if (err) { + expect("801").assertEqual(err.code.toString()); + done(); + return; + } + expect(result.sessionId == "testSession003").assertEqual(true); + expect(result.version == g_object.__version).assertEqual(true); + expect(result.deviceId == "local").assertEqual(true); + g_object.revokeSave((err, result) => { + if (err) { + expect("801").assertEqual(err.code.toString()); + done(); + return; + } + expect("testSession003" == result.sessionId).assertEqual(true); + g_object.setSessionId(""); + g_object.name = undefined; + g_object.age = undefined; + g_object.isVis = undefined; + g_object.setSessionId("testSession003"); + + expect(g_object.name == undefined).assertEqual(true); + expect(g_object.age == undefined).assertEqual(true); + expect(g_object.isVis == undefined).assertEqual(true); + done(); + }) + }); - result = await g_object.revokeSave(); + console.log(TAG + "************* testRevokeSave001 end *************"); + }) + /** + * @tc.name: testRevokeSave002 + * @tc.desc: test save local + * @tc.type: FUNC + * @tc.require: + */ + it('testRevokeSave002', 0, async function () { + console.log(TAG + "************* testRevokeSave002 start *************"); + var g_object = distributedObject.createDistributedObject({ name: "Amy", age: 18, isVis: false }); + expect(g_object == undefined).assertEqual(false); + + g_object.setSessionId("testSession004"); + expect("testSession004" == g_object.__sessionId).assertEqual(true); + + let result = await g_object.save("local").catch((err)=> { + expect("801").assertEqual(err.code.toString()); + return CATCH_ERR; + }); + if (result === CATCH_ERR) { + return; + } + + expect(result.sessionId.toString() == "testSession004").assertEqual(true); + expect(result.version.toString() == g_object.__version.toString()).assertEqual(true); + expect(result.deviceId.toString() == "local").assertEqual(true); + + result = await g_object.revokeSave().catch((err)=> { + expect("801").assertEqual(err.code.toString()); + return CATCH_ERR; + }); + + if (result === CATCH_ERR) { + return; + } g_object.setSessionId(""); g_object.name = undefined; g_object.age = undefined; g_object.isVis = undefined; - g_object.setSessionId("123456"); + g_object.setSessionId("testSession004"); expect(g_object.name == undefined).assertEqual(true); expect(g_object.age == undefined).assertEqual(true); expect(g_object.isVis == undefined).assertEqual(true); - expect(result.sessionId == "123456").assertEqual(true); - - console.log(TAG + "************* testRevokeSave001 end *************"); - g_object.setSessionId(""); + console.log(TAG + "************* testRevokeSave002 end *************"); }) /** @@ -752,25 +850,21 @@ describe('objectStoreTest',function () { */ it('OnstatusRestored001', 0, async function () { console.log(TAG + "************* OnstatusRestored001 start *************"); - var g_object = distributedObject.createDistributedObject({ name: undefined, age: undefined, isVis: undefined }); - g_object.setSessionId("123456"); - g_object.name = "jack"; - g_object.age = 19; - g_object.isVis = true; - - let result = await g_object.save("local"); - expect(result.sessionId == "123456").assertEqual(true); + var g_object = distributedObject.createDistributedObject({ name: "Amy", age: 18, isVis: false }); + g_object.on("status", statusCallback4); + g_object.setSessionId("testSession005"); + let result = await g_object.save("local").catch((err)=> { + expect("801").assertEqual(err.code.toString()); + return CATCH_ERR; + }); + if (result === CATCH_ERR) { + return; + } + expect(result.sessionId == "testSession005").assertEqual(true); expect(result.version == g_object.__version).assertEqual(true); expect(result.deviceId == "local").assertEqual(true); - g_object.setSessionId(""); - - g_object.on("status", statusCallback4); - - g_object.setSessionId("123456"); - g_object.setSessionId(""); console.log(TAG + "************* OnstatusRestored001 end *************"); - }) console.log(TAG + "*************Unit Test End*************"); diff --git a/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunitV9.test.js b/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunitV9.test.js index c1e3d4b89ce71086a59001d387ca8bff5ca7c95c..02b69e9b0db433d7d74a75a118ed3487ed5485aa 100644 --- a/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunitV9.test.js +++ b/data_object/frameworks/jskitsimpl/test/unittest/src/ObjectStoreJsunitV9.test.js @@ -42,6 +42,7 @@ function statusCallback2(sessionId, networkId, status) { const PERMISSION_USER_SET = 1; const PERMISSION_USER_NAME = "ohos.permission.DISTRIBUTED_DATASYNC"; +const CATCH_ERR = -1; var tokenID = undefined; async function grantPerm() { console.info("====grant Permission start===="); @@ -373,7 +374,7 @@ describe('objectStoreTest', function () { }) /** - * @tc.name:V9testOff002 + * @tc.name: V9testOff002 * @tc.desc object join session and off,object can not receive callback * @tc.type: FUNC */ @@ -458,44 +459,38 @@ describe('objectStoreTest', function () { * @tc.desc: test save local * @tc.type: FUNC */ - it('V9testSave001', 0, async function () { + it('V9testSave001', 0, async function (done) { console.log(TAG + "************* V9testSave001 start *************"); var g_object = distributedObject.create(context, {name: "Amy", age: 18, isVis: false}); expect(g_object == undefined).assertEqual(false); - g_object.setSessionId("tmpsession1").then(() => { + g_object.setSessionId("mySession1").then(() => { console.info("join session"); }).catch((error) => { console.info(TAG + error.code + error.message); }); - expect("tmpsession1" == g_object.__sessionId).assertEqual(true); + expect("mySession1" == g_object.__sessionId).assertEqual(true); - let result = await g_object.save("local"); - expect(result.sessionId == "tmpsession1").assertEqual(true); - expect(result.version == g_object.__version).assertEqual(true); - expect(result.deviceId == "local").assertEqual(true); + g_object.save("local").then((ret) => { + expect(ret.sessionId == "mySession1").assertEqual(true); + expect(ret.version == g_object.__version).assertEqual(true); + expect(ret.deviceId == "local").assertEqual(true); + done(); - g_object.setSessionId((error, data) => { - console.info(TAG + error + "," + data); - }); - g_object.name = undefined; - g_object.age = undefined; - g_object.isVis = undefined; - g_object.setSessionId("tmpsession1").then(() => { - console.info("join session"); - }).catch((error) => { - console.info(TAG + error.code + error.message); - }); + g_object.setSessionId(""); + g_object.name = undefined; + g_object.age = undefined; + g_object.isVis = undefined; + g_object.setSessionId("mySession1"); - expect(g_object.name == "Amy").assertEqual(true); - expect(g_object.age == 18).assertEqual(true); - expect(g_object.isVis == false).assertEqual(true); - console.log(TAG + "************* V9testSave001 end *************"); - g_object.setSessionId().then(() => { - console.info("leave session"); - }).catch((error) => { - console.info(TAG + error.code + error.message); + expect(g_object.name == "Amy").assertEqual(true); + expect(g_object.age == 18).assertEqual(true); + expect(g_object.isVis == false).assertEqual(true); + }).catch((err) => { + expect("801").assertEqual(err.code.toString()); + done(); }); + console.log(TAG + "************* V9testSave001 end *************"); }) /** @@ -503,20 +498,57 @@ describe('objectStoreTest', function () { * @tc.desc: test save local * @tc.type: FUNC */ - it('V9testSave002', 0, async function () { + it('V9testSave002', 0, async function (done) { console.log(TAG + "************* V9testSave002 start *************"); var g_object = distributedObject.create(context, {name: "Amy", age: 18, isVis: false}); expect(g_object == undefined).assertEqual(false); - g_object.setSessionId("tmpsession1").then(() => { + g_object.setSessionId("mySession2"); + expect("mySession2" == g_object.__sessionId).assertEqual(true); + + g_object.save("local", (err, result) => { + if (err) { + expect("801").assertEqual(err.code.toString()); + done(); + return; + } + expect(result.sessionId == "mySession2").assertEqual(true); + expect(result.version == g_object.__version).assertEqual(true); + expect(result.deviceId == "local").assertEqual(true); + + g_object.setSessionId(""); + g_object.name = undefined; + g_object.age = undefined; + g_object.isVis = undefined; + g_object.setSessionId("mySession2"); + + expect(g_object.name == "Amy").assertEqual(true); + expect(g_object.age == 18).assertEqual(true); + expect(g_object.isVis == false).assertEqual(true); + done(); + }); + console.log(TAG + "************* V9testSave002 end *************"); + }) + + /** + * @tc.name: V9testSave003 + * @tc.desc: test save local + * @tc.type: FUNC + */ + it('V9testSave003', 0, async function () { + console.log(TAG + "************* V9testSave003 start *************"); + var g_object = distributedObject.create(context, {name: "Amy", age: 18, isVis: false}); + expect(g_object == undefined).assertEqual(false); + + g_object.setSessionId("mySession3").then(() => { console.info("join session"); }).catch((error) => { console.info(TAG + error.code + error.message); }); - expect("tmpsession1" == g_object.__sessionId).assertEqual(true); + expect("mySession3" == g_object.__sessionId).assertEqual(true); try { g_object.save(1234).then((result) => { - expect(result.sessionId == "tmpsession1").assertEqual(true); + expect(result.sessionId == "mySession3").assertEqual(true); expect(result.version == g_object.__version).assertEqual(true); expect(result.deviceId == "local").assertEqual(true); }) @@ -524,20 +556,20 @@ describe('objectStoreTest', function () { expect(error.message == "Parameter error. The type of 'deviceId' must be 'string'.").assertEqual(true); } g_object.save("errorDeviceId").then((result) => { - expect(result.sessionId == "tmpsession1").assertEqual(true); + expect(result.sessionId == "mySession3").assertEqual(true); expect(result.version == g_object.__version).assertEqual(true); expect(result.deviceId == "local").assertEqual(true); }).catch((error) => { expect(error != undefined).assertEqual(true); }); - + try { g_object.save("local", 123); } catch (error) { expect(error.code == 401).assertEqual(true); expect(error.message == "Parameter error. The type of 'callback' must be 'function'.").assertEqual(true); } - console.log(TAG + "************* V9testSave002 end *************"); + console.log(TAG + "************* V9testSave003 end *************"); g_object.setSessionId().then(() => { console.info("leave session"); }).catch((error) => { @@ -550,81 +582,129 @@ describe('objectStoreTest', function () { * @tc.desc: test RevokeSave * @tc.type: FUNC */ - it('V9testRevokeSave001', 0, async function () { + it('V9testRevokeSave001', 0, async function (done) { console.log(TAG + "************* V9testRevokeSave001 start *************"); var g_object = distributedObject.create(context, {name: "Amy", age: 18, isVis: false}); expect(g_object == undefined).assertEqual(false); - g_object.setSessionId("123456").then(() => { - console.info("join session"); - }).catch((error) => { - console.info(TAG + error.code + error.message); + g_object.setSessionId("mySession4"); + expect("mySession4" == g_object.__sessionId).assertEqual(true); + + g_object.save("local", (err, result) => { + if (err) { + expect("801").assertEqual(err.code.toString()); + done(); + return; + } + expect(result.sessionId == "mySession4").assertEqual(true); + expect(result.version == g_object.__version).assertEqual(true); + expect(result.deviceId == "local").assertEqual(true); + g_object.revokeSave((err, result) => { + if (err) { + expect("801").assertEqual(err.code.toString()); + done(); + return; + } + expect("mySession4" == result.sessionId).assertEqual(true); + g_object.setSessionId(""); + g_object.name = undefined; + g_object.age = undefined; + g_object.isVis = undefined; + g_object.setSessionId("mySession4"); + + expect(g_object.name == undefined).assertEqual(true); + expect(g_object.age == undefined).assertEqual(true); + expect(g_object.isVis == undefined).assertEqual(true); + done(); + }) }); - expect("123456" == g_object.__sessionId).assertEqual(true); + console.log(TAG + "************* V9testRevokeSave001 end *************"); + }) - let result = await g_object.save("local"); - expect(result.sessionId == "123456").assertEqual(true); - expect(result.version == g_object.__version).assertEqual(true); - expect(result.deviceId == "local").assertEqual(true); - result = await g_object.revokeSave(); + /** + * @tc.name: V9testRevokeSave002 + * @tc.desc: test save local + * @tc.type: FUNC + * @tc.require: + */ + it('V9testRevokeSave002', 0, async function () { + console.log(TAG + "************* V9testRevokeSave002 start *************"); + var g_object = distributedObject.create(context, {name: "Amy", age: 18, isVis: false}); + expect(g_object != undefined).assertEqual(true); - g_object.setSessionId((error, data) => { - console.info(TAG + error + "," + data); + g_object.setSessionId("mySession5"); + expect("mySession5" == g_object.__sessionId.toString()).assertEqual(true); + + let result = await g_object.save("local").catch((err)=> { + expect("801").assertEqual(err.code.toString()); + return CATCH_ERR; }); + if (result === CATCH_ERR) { + return; + } + + expect(result.sessionId.toString() == "mySession5").assertEqual(true); + expect(result.version.toString() == g_object.__version.toString()).assertEqual(true); + expect(result.deviceId.toString() == "local").assertEqual(true); + + result = await g_object.revokeSave().catch((err)=> { + expect("801").assertEqual(err.code.toString()); + return CATCH_ERR; + }); + + if (result === CATCH_ERR) { + return; + } + g_object.setSessionId(""); g_object.name = undefined; g_object.age = undefined; g_object.isVis = undefined; - g_object.setSessionId("123456").then(() => { - console.info("join session"); - }).catch((error) => { - console.info(TAG + error.code + error.message); - }); + g_object.setSessionId("mySession5"); expect(g_object.name == undefined).assertEqual(true); expect(g_object.age == undefined).assertEqual(true); expect(g_object.isVis == undefined).assertEqual(true); - expect(result.sessionId == "123456").assertEqual(true); - console.log(TAG + "************* V9testRevokeSave001 end *************"); - g_object.setSessionId("", (error, data) => { - console.info(TAG + error + "," + data); - }); + + console.log(TAG + "************* V9testRevokeSave002 end *************"); }) /** - * @tc.name: V9testRevokeSave002 + * @tc.name: V9testRevokeSave003 * @tc.desc: test RevokeSave * @tc.type: FUNC */ - it('V9testRevokeSave002', 0, async function () { - console.log(TAG + "************* V9testRevokeSave002 start *************"); + it('V9testRevokeSave003', 0, async function () { + console.log(TAG + "************* V9testRevokeSave003 start *************"); var g_object = distributedObject.create(context, {name: "Amy", age: 18, isVis: false}); expect(g_object == undefined).assertEqual(false); - g_object.setSessionId("123456").then(() => { + g_object.setSessionId("mySession6").then(() => { console.info("join session"); }).catch((error) => { console.info(TAG + error.code + error.message); }); - expect("123456" == g_object.__sessionId).assertEqual(true); - let result = await g_object.save("local"); - expect(result.sessionId == "123456").assertEqual(true); + expect("mySession6" == g_object.__sessionId).assertEqual(true); + let result = await g_object.save("local").catch((err) => { + expect("801").assertEqual(err.code.toString()); + return CATCH_ERR; + }); + if (result === CATCH_ERR) { + return; + } + expect(result.sessionId == "mySession6").assertEqual(true); expect(result.version == g_object.__version).assertEqual(true); expect(result.deviceId == "local").assertEqual(true); try { g_object.revokeSave(123).then((result) => { - expect(result.sessionId == "tmpsession1").assertEqual(true) + expect(result.sessionId == "mySession6").assertEqual(true); }).catch((err) => { console.log(err.code + err.message); }); } catch (error) { console.info(error.code + error.message); - expect(error.code == 401).assertEqual(true); - expect(error.message == "Parameter error. The type of 'callback' must be 'function'.").assertEqual(true); + expect("401").assertEqual(error.code.toString()); } - console.log(TAG + "************* V9testRevokeSave002 end *************"); - g_object.setSessionId("", (error, data) => { - console.info(TAG + error + "," + data); - }); + console.log(TAG + "************* V9testRevokeSave003 end *************"); }) - + console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/data_object/interfaces/innerkits/BUILD.gn b/data_object/interfaces/innerkits/BUILD.gn index 2051c3efb9e06a9e7b8e9afdfa0525abd96d6918..0869ce974a377be658c07530428fd5ba8f1821ba 100644 --- a/data_object/interfaces/innerkits/BUILD.gn +++ b/data_object/interfaces/innerkits/BUILD.gn @@ -13,7 +13,7 @@ import("//build/ohos.gni") config("objectstore_config") { - visibility = [ "//foundation/distributeddatamgr/data_object:*" ] + visibility = [ ":*" ] cflags = [ "-DHILOG_ENABLE" ] diff --git a/data_object/interfaces/jskits/BUILD.gn b/data_object/interfaces/jskits/BUILD.gn index 5a3ea00dd6b1b98caea56bb970ea266d10360d44..d8d771bfafd3649e7e3eff58de715fd6244885fc 100644 --- a/data_object/interfaces/jskits/BUILD.gn +++ b/data_object/interfaces/jskits/BUILD.gn @@ -43,7 +43,7 @@ action("gen_distributed_data_object_abc") { } config("objectstore_config") { - visibility = [ "//foundation/distributeddatamgr/objectstore:*" ] + visibility = [ ":*" ] cflags = [ "-DHILOG_ENABLE" ] @@ -118,6 +118,7 @@ ohos_shared_library("distributeddataobject") { "ability_runtime:app_context", "ability_runtime:napi_base_context", "access_token:libaccesstoken_sdk", + "common_event_service:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "napi:ace_napi", ] diff --git a/data_object/interfaces/jskits/distributed_data_object.js b/data_object/interfaces/jskits/distributed_data_object.js index a7e2a89fc753a98b856afa9a8465d1c094dcb4f0..f32a1ce45b47cd425a4000a449a4620f6844c59c 100644 --- a/data_object/interfaces/jskits/distributed_data_object.js +++ b/data_object/interfaces/jskits/distributed_data_object.js @@ -13,328 +13,331 @@ * limitations under the License. */ -const distributedObject = requireInternal("data.distributedDataObject"); -const SESSION_ID = "__sessionId"; -const VERSION = "__version"; -const COMPLEX_TYPE = "[COMPLEX]"; -const STRING_TYPE = "[STRING]"; -const NULL_TYPE = "[NULL]" +const distributedObject = requireInternal('data.distributedDataObject'); +const SESSION_ID = '__sessionId'; +const VERSION = '__version'; +const COMPLEX_TYPE = '[COMPLEX]'; +const STRING_TYPE = '[STRING]'; +const NULL_TYPE = '[NULL]'; const JS_ERROR = 1; +const SDK_VERSION_8 = 8; +const SDK_VERSION_9 = 9; class Distributed { - constructor(obj) { - constructorMethod(this, obj); - } + constructor(obj) { + constructorMethod(this, obj); + } - setSessionId(sessionId) { - if (sessionId == null || sessionId == "") { - leaveSession(this.__sdkVersion, this.__proxy); - return false; - } - if (this.__proxy[SESSION_ID] == sessionId) { - console.info("same session has joined " + sessionId); - return true; - } - leaveSession(this.__sdkVersion, this.__proxy); - let object = joinSession(this.__sdkVersion, this.__proxy, this.__objectId, sessionId); - if (object != null) { - this.__proxy = object; - return true; - } - return false; + setSessionId(sessionId) { + if (sessionId == null || sessionId === '') { + leaveSession(this.__sdkVersion, this.__proxy); + return false; } - - on(type, callback) { - onWatch(this.__sdkVersion, type, this.__proxy, callback); - distributedObject.recordCallback(this.__sdkVersion, type, this.__objectId, callback); + if (this.__proxy[SESSION_ID] === sessionId) { + console.info('same session has joined ' + sessionId); + return true; + } + leaveSession(this.__sdkVersion, this.__proxy); + let object = joinSession(this.__sdkVersion, this.__proxy, this.__objectId, sessionId); + if (object != null) { + this.__proxy = object; + return true; } + return false; + } - off(type, callback) { - offWatch(this.__sdkVersion, type, this.__proxy, callback); - if (callback != undefined || callback != null) { - distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId, callback); - } else { - distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId); - } + on(type, callback) { + onWatch(this.__sdkVersion, type, this.__proxy, callback); + distributedObject.recordCallback(this.__sdkVersion, type, this.__objectId, callback); + } + + off(type, callback) { + offWatch(this.__sdkVersion, type, this.__proxy, callback); + if (callback !== undefined || callback != null) { + distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId, callback); + } else { + distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId); } + } - save(deviceId, callback) { - if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] == "") { - console.info("not join a session, can not do save"); - return JS_ERROR; - } - return this.__proxy.save(deviceId, this[VERSION], callback); + save(deviceId, callback) { + if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') { + console.info('not join a session, can not do save'); + return JS_ERROR; } + return this.__proxy.save(deviceId, this[VERSION], callback); + } - revokeSave(callback) { - if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] == "") { - console.info("not join a session, can not do revoke save"); - return JS_ERROR; - } - return this.__proxy.revokeSave(callback); + revokeSave(callback) { + if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') { + console.info('not join a session, can not do revoke save'); + return JS_ERROR; } + return this.__proxy.revokeSave(callback); + } - __proxy; - __objectId; - __version; - __sdkVersion = 8 ; + __proxy; + __objectId; + __version; + __sdkVersion = SDK_VERSION_8; } function constructorMethod(result, obj) { - result.__proxy = obj; - Object.keys(obj).forEach(key => { - Object.defineProperty(result, key, { - enumerable: true, - configurable: true, - get: function () { - return result.__proxy[key]; - }, - set: function (newValue) { - result[VERSION]++; - result.__proxy[key] = newValue; - } - }); + result.__proxy = obj; + Object.keys(obj).forEach(key => { + Object.defineProperty(result, key, { + enumerable: true, + configurable: true, + get: function () { + return result.__proxy[key]; + }, + set: function (newValue) { + result[VERSION]++; + result.__proxy[key] = newValue; + } }); - Object.defineProperty(result, SESSION_ID, { - enumerable: true, - configurable: true, - get: function () { - return result.__proxy[SESSION_ID]; - }, - set: function (newValue) { - result.__proxy[SESSION_ID] = newValue; - } - }); - result.__objectId = randomNum(); - result[VERSION] = 0; - console.info("constructor success "); + }); + Object.defineProperty(result, SESSION_ID, { + enumerable: true, + configurable: true, + get: function () { + return result.__proxy[SESSION_ID]; + }, + set: function (newValue) { + result.__proxy[SESSION_ID] = newValue; + } + }); + result.__objectId = randomNum(); + result[VERSION] = 0; + console.info('constructor success '); } function randomNum() { - return distributedObject.sequenceNum(); + return distributedObject.sequenceNum(); } function newDistributed(obj) { - console.info("start newDistributed"); - if (obj == null) { - console.error("object is null"); - return null; - } - return new Distributed(obj); + console.info('start newDistributed'); + if (obj == null) { + console.error('object is null'); + return null; + } + return new Distributed(obj); } function joinSession(version, obj, objectId, sessionId, context) { - console.info("start joinSession " + sessionId); - if (obj == null || sessionId == null || sessionId == "") { - console.error("object is null"); - return null; - } + console.info('start joinSession ' + sessionId); + if (obj == null || sessionId == null || sessionId === '') { + console.error('object is null'); + return null; + } - let object = null; - if (context != undefined || context != null) { - object = distributedObject.createObjectSync(version, sessionId, objectId, context); - } else { - object = distributedObject.createObjectSync(version, sessionId, objectId); - } + let object = null; + if (context !== undefined || context != null) { + object = distributedObject.createObjectSync(version, sessionId, objectId, context); + } else { + object = distributedObject.createObjectSync(version, sessionId, objectId); + } - if (object == null) { - console.error("create fail"); - return null; - } - Object.keys(obj).forEach(key => { - console.info("start define " + key); - Object.defineProperty(object, key, { - enumerable: true, - configurable: true, - get: function () { - console.info("start get " + key); - let result = object.get(key); - console.info("get " + result); - if (typeof result == "string") { - if (result.startsWith(STRING_TYPE)) { - result = result.substr(STRING_TYPE.length); - } else if (result.startsWith(COMPLEX_TYPE)) { - result = JSON.parse(result.substr(COMPLEX_TYPE.length)) - } else if (result.startsWith(NULL_TYPE)) { - result = null; - } else { - console.error("error type " + result); - } - } - console.info("get " + result + " success"); - return result; - }, - set: function (newValue) { - console.info("start set " + key + " " + newValue); - if (typeof newValue == "object") { - let value = COMPLEX_TYPE + JSON.stringify(newValue); - object.put(key, value); - console.info("set " + key + " " + value); - } else if (typeof newValue == "string") { - let value = STRING_TYPE + newValue; - object.put(key, value); - console.info("set " + key + " " + value); - } else if (newValue === null) { - let value = NULL_TYPE; - object.put(key, value); - console.info("set " + key + " " + value); - } else { - object.put(key, newValue); - console.info("set " + key + " " + newValue); - } - } - }); - if (obj[key] != undefined) { - object[key] = obj[key]; + if (object == null) { + console.error('create fail'); + return null; + } + Object.keys(obj).forEach(key => { + console.info('start define ' + key); + Object.defineProperty(object, key, { + enumerable: true, + configurable: true, + get: function () { + console.info('start get ' + key); + let result = object.get(key); + console.info('get ' + result); + if (typeof result === 'string') { + if (result.startsWith(STRING_TYPE)) { + result = result.substr(STRING_TYPE.length); + } else if (result.startsWith(COMPLEX_TYPE)) { + result = JSON.parse(result.substr(COMPLEX_TYPE.length)); + } else if (result.startsWith(NULL_TYPE)) { + result = null; + } else { + console.error('error type ' + result); + } } + console.info('get ' + result + ' success'); + return result; + }, + set: function (newValue) { + console.info('start set ' + key + ' ' + newValue); + if (typeof newValue === 'object') { + let value = COMPLEX_TYPE + JSON.stringify(newValue); + object.put(key, value); + console.info('set ' + key + ' ' + value); + } else if (typeof newValue === 'string') { + let value = STRING_TYPE + newValue; + object.put(key, value); + console.info('set ' + key + ' ' + value); + } else if (newValue == null) { + let value = NULL_TYPE; + object.put(key, value); + console.info('set ' + key + ' ' + value); + } else { + object.put(key, newValue); + console.info('set ' + key + ' ' + newValue); + } + } }); + if (obj[key] !== undefined) { + object[key] = obj[key]; + } + }); - Object.defineProperty(object, SESSION_ID, { - value: sessionId, - configurable: true, - }); - return object; + Object.defineProperty(object, SESSION_ID, { + value: sessionId, + configurable: true, + }); + return object; } function leaveSession(version, obj) { - console.info("start leaveSession"); - if (obj == null || obj[SESSION_ID] == null || obj[SESSION_ID] == "") { - console.warn("object is null"); - return; - } - Object.keys(obj).forEach(key => { - Object.defineProperty(obj, key, { - value: obj[key], - configurable: true, - writable: true, - enumerable: true, - }); + console.info('start leaveSession'); + if (obj == null || obj[SESSION_ID] == null || obj[SESSION_ID] === '') { + console.warn('object is null'); + return; + } + Object.keys(obj).forEach(key => { + Object.defineProperty(obj, key, { + value: obj[key], + configurable: true, + writable: true, + enumerable: true, }); - // disconnect,delete object - distributedObject.destroyObjectSync(version, obj); - delete obj[SESSION_ID]; + }); + // disconnect,delete object + distributedObject.destroyObjectSync(version, obj); + delete obj[SESSION_ID]; } function onWatch(version, type, obj, callback) { - console.info("start on " + obj[SESSION_ID]); - if (obj[SESSION_ID] != null && obj[SESSION_ID] != undefined && obj[SESSION_ID].length > 0) { - distributedObject.on(version, type, obj, callback); - } + console.info('start on ' + obj[SESSION_ID]); + if (obj[SESSION_ID] != null && obj[SESSION_ID] !== undefined && obj[SESSION_ID].length > 0) { + distributedObject.on(version, type, obj, callback); + } } function offWatch(version, type, obj, callback = undefined) { - console.info("start off " + obj[SESSION_ID] + " " + callback); - if (obj[SESSION_ID] != null && obj[SESSION_ID] != undefined && obj[SESSION_ID].length > 0) { - if (callback != undefined || callback != null) { - distributedObject.off(version, type, obj, callback); - } else { - distributedObject.off(version, type, obj); - } + console.info('start off ' + obj[SESSION_ID] + ' ' + callback); + if (obj[SESSION_ID] != null && obj[SESSION_ID] !== undefined && obj[SESSION_ID].length > 0) { + if (callback !== undefined || callback != null) { + distributedObject.off(version, type, obj, callback); + } else { + distributedObject.off(version, type, obj); } + } } function newDistributedV9(context, obj) { - console.info("start newDistributed"); - let checkparameter = function(parameter, type) { - throw { code : 401, - message :"Parameter error. The type of '" + parameter + "' must be '" + type + "'."}; - } - if(typeof context != "object") { - checkparameter("context", "Context"); - } - if(typeof obj != "object") { - checkparameter("source", "object"); - } - if (obj == null) { - console.error("object is null"); - return null; - } - return new DistributedV9(obj, context); + console.info('start newDistributed'); + let checkparameter = function(parameter, type) { + throw { + code: 401, + message :"Parameter error. The type of '" + parameter + "' must be '" + type + "'."}; + }; + if (typeof context !== 'object') { + checkparameter('context', 'Context'); + } + if (typeof obj !== 'object') { + checkparameter('source', 'object'); + } + if (obj == null) { + console.error('object is null'); + return null; + } + return new DistributedV9(obj, context); } class DistributedV9 { - constructor(obj, context) { - this.__context = context; - constructorMethod(this, obj); - } + constructor(obj, context) { + this.__context = context; + constructorMethod(this, obj); + } - setSessionId(sessionId, callback) { - if (typeof sessionId == "function" || sessionId == null || sessionId == "") { - leaveSession(this.__sdkVersion, this.__proxy); - if (typeof sessionId == "function") { - return sessionId(this.__proxy); - } else if (typeof callback == "function") { - return callback(null, this.__proxy); - } else { - return Promise.resolve(null, this.__proxy); - } - } - if (this.__proxy[SESSION_ID] == sessionId) { - console.info("same session has joined " + sessionId); - if (typeof callback == "function") { - return callback(null, this.__proxy); - } else { - return Promise.resolve(null, this.__proxy); - } - } - leaveSession(this.__sdkVersion, this.__proxy); - let object = joinSession(this.__sdkVersion, this.__proxy, this.__objectId, sessionId, this.__context); - if (object != null) { - this.__proxy = object; - if (typeof callback == "function") { - return callback(null, this.__proxy) - } else { - return Promise.resolve(null, object); - } - } else { - if (typeof callback == "function") { - return callback(null, null); - } else { - return Promise.reject(null, null); - } - } + setSessionId(sessionId, callback) { + if (typeof sessionId === 'function' || sessionId == null || sessionId === '') { + leaveSession(this.__sdkVersion, this.__proxy); + if (typeof sessionId === 'function') { + return sessionId(this.__proxy); + } else if (typeof callback === 'function') { + return callback(null, this.__proxy); + } else { + return Promise.resolve(null, this.__proxy); + } } - - on(type, callback) { - onWatch(this.__sdkVersion, type, this.__proxy, callback); - distributedObject.recordCallback(this.__sdkVersion, type, this.__objectId, callback); + if (this.__proxy[SESSION_ID] === sessionId) { + console.info('same session has joined ' + sessionId); + if (typeof callback === 'function') { + return callback(null, this.__proxy); + } else { + return Promise.resolve(null, this.__proxy); + } } + leaveSession(this.__sdkVersion, this.__proxy); + let object = joinSession(this.__sdkVersion, this.__proxy, this.__objectId, sessionId, this.__context); + if (object != null) { + this.__proxy = object; + if (typeof callback === 'function') { + return callback(null, this.__proxy); + } else { + return Promise.resolve(null, object); + } + } else { + if (typeof callback === 'function') { + return callback(null, null); + } else { + return Promise.reject(null, null); + } + } + } - off(type, callback) { - offWatch(this.__sdkVersion, type, this.__proxy, callback); - if (callback != undefined || callback != null) { - distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId, callback); - } else { - distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId); - } + on(type, callback) { + onWatch(this.__sdkVersion, type, this.__proxy, callback); + distributedObject.recordCallback(this.__sdkVersion, type, this.__objectId, callback); + } + + off(type, callback) { + offWatch(this.__sdkVersion, type, this.__proxy, callback); + if (callback !== undefined || callback != null) { + distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId, callback); + } else { + distributedObject.deleteCallback(this.__sdkVersion, type, this.__objectId); } + } - save(deviceId, callback) { - if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] == "") { - console.info("not join a session, can not do save"); - return JS_ERROR; - } - return this.__proxy.save(deviceId, this[VERSION], callback); + save(deviceId, callback) { + if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') { + console.info('not join a session, can not do save'); + return JS_ERROR; } + return this.__proxy.save(deviceId, this[VERSION], callback); + } - revokeSave(callback) { - if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] == "") { - console.info("not join a session, can not do revoke save"); - return JS_ERROR; - } - return this.__proxy.revokeSave(callback); + revokeSave(callback) { + if (this.__proxy[SESSION_ID] == null || this.__proxy[SESSION_ID] === '') { + console.info('not join a session, can not do revoke save'); + return JS_ERROR; } + return this.__proxy.revokeSave(callback); + } - __context; - __proxy; - __objectId; - __version; - __sdkVersion = 9; + __context; + __proxy; + __objectId; + __version; + __sdkVersion = SDK_VERSION_9; } export default { - createDistributedObject: newDistributed, - create: newDistributedV9, - genSessionId: randomNum -} \ No newline at end of file + createDistributedObject: newDistributed, + create: newDistributedV9, + genSessionId: randomNum +}; diff --git a/data_object/samples/distributedNotepad/ReadMe.md b/data_object/samples/distributedNotepad/ReadMe.md index 06f24a7b20809b41934bf9cc930ea19f4077cbff..247fe16e85c15308d377bd1cc0d556ed4b1554b2 100644 --- a/data_object/samples/distributedNotepad/ReadMe.md +++ b/data_object/samples/distributedNotepad/ReadMe.md @@ -150,10 +150,10 @@ changeCallback(sessionId, changeData) { changeData.forEach(element => { if (element == "documentList") { // 刷新界面上的备忘录数据列表 - this.dataModel.documentList = distr.g_dataModel.distributedObject.documentList; + this.dataModel.documentList = distr.dataModel.distributedObject.documentList; } else if (element == "documentSize") { - let size = distr.g_dataModel.distributedObject.documentSize; + let size = distr.dataModel.distributedObject.documentSize; // 刷新界面上列表总数 this.dataModel.distributedObject.documentSize = size; } @@ -168,9 +168,9 @@ changeCallback(sessionId, changeData) { onInit() { // 监听对端设备的数据变更 // 发起方要在changeCallback里刷新界面,则需要将正确的this绑定给changeCallback - distr.g_dataModel.setCallback(this.changeCallback.bind(this)); + distr.dataModel.setCallback(this.changeCallback.bind(this)); // 监听分布式对象的上下线状态 - distr.g_dataModel.setStatusCallback((sessionId, networkId, status) => { + distr.dataModel.setStatusCallback((sessionId, networkId, status) => { // 刷新红绿灯界面 if (status == "online") { this.dataModel.imgSrc = "common/green.png"; @@ -188,7 +188,7 @@ onInit() { ```js doAdd: function () { - distr.g_dataModel.add(this.title, this.content); + distr.dataModel.add(this.title, this.content); ... } ``` @@ -209,7 +209,7 @@ add(title, content) { ```js save: function () { // 使用页面数据更新分布式对象属性数据 - distr.g_dataModel.update(this.editIndex, this.title, this.content); + distr.dataModel.update(this.editIndex, this.title, this.content); ... } ``` @@ -230,7 +230,7 @@ update(index, title, content) { clear: function () { // 触发界面刷新 this.dataModel.documentList = []; - distr.g_dataModel.clear(); + distr.dataModel.clear(); this.dataModel.distributedObject.documentSize = 0; }, ``` diff --git a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/app.js b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/app.js index e3a0891c0350ac6dec03b34963b6e570653355f2..b8b9fcdb4a19a30d35f8bf82af8ed6532fca25da 100644 --- a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/app.js +++ b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/app.js @@ -14,10 +14,10 @@ */ export default { - onCreate() { - console.info("Application onCreate"); - }, - onDestroy() { - console.info("Application onDestroy"); - } + onCreate() { + console.info('Application onCreate'); + }, + onDestroy() { + console.info('Application onDestroy'); + } }; diff --git a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/add/add.js b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/add/add.js index 1dcc4d7aea1dd7cb4c506275091f82119914036c..073c120b2d81f11e1c2a2e6def4e014b351e7522 100644 --- a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/add/add.js +++ b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/add/add.js @@ -13,30 +13,30 @@ * limitations under the License. */ -import router from '@system.router' -import * as distr from '../../../model/DistributedDataModel.js' +import router from '@system.router'; +import * as distr from '../../../model/DistributedDataModel.js'; export default { - data: { - title: "天气不错奥", - content: "今天天气不错" - }, - onInit() { - console.info("objectstore in add page"); - }, - doAdd: function () { - console.info("doAdd " + JSON.stringify(distr.g_dataModel)); - distr.g_dataModel.add(this.title, this.content); - router.replace({ - uri: "pages/index/index", - params: { - dataModel: distr.g_dataModel - } - }) - }, - changeTitle: function (e) { - this.title = e.text; - }, - changeContent: function (e) { - this.content = e.text; - } -} + data: { + title: '天气不错奥', + content: '今天天气不错' + }, + onInit() { + console.info('objectstore in add page'); + }, + doAdd: function () { + console.info('doAdd ' + JSON.stringify(distr.dataModel)); + distr.dataModel.add(this.title, this.content); + router.replace({ + uri: 'pages/index/index', + params: { + dataModel: distr.dataModel + } + }); + }, + changeTitle: function (e) { + this.title = e.text; + }, + changeContent: function (e) { + this.content = e.text; + } +}; diff --git a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/detail/detail.js b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/detail/detail.js index 461f1798e8fa629c68e36587ef067ef67184663e..a808b7a08e8c37682d66761a904cddc40e95306f 100644 --- a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/detail/detail.js +++ b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/detail/detail.js @@ -13,40 +13,40 @@ * limitations under the License. */ -import router from '@system.router' -import * as distr from '../../../model/DistributedDataModel.js' +import router from '@system.router'; +import * as distr from '../../../model/DistributedDataModel.js'; export default { - data: { - title: "天气不错奥", - content: "今天天气不错", - edit: "保存" - }, - onInit() { - console.info("objectstore in detail page"); - }, - back: function () { - router.replace({ - uri: "pages/index/index", - params: { - dataModel: distr.g_dataModel - } - }) - }, - change: function (e) { - this.title = e.text; - }, - changeContent: function (e) { - this.content = e.text; - }, - save: function () { - console.info("start save "+ JSON.stringify(this.data)); - distr.g_dataModel.update(this.editIndex, this.title, this.content); - router.replace({ - uri: "pages/index/index", - params: { - dataModel: distr.g_dataModel - } - }) - } -} + data: { + title: '天气不错奥', + content: '今天天气不错', + edit: '保存' + }, + onInit() { + console.info('objectstore in detail page'); + }, + back: function () { + router.replace({ + uri: 'pages/index/index', + params: { + dataModel: distr.dataModel + } + }); + }, + change: function (e) { + this.title = e.text; + }, + changeContent: function (e) { + this.content = e.text; + }, + save: function () { + console.info('start save ' + JSON.stringify(this.data)); + distr.dataModel.update(this.editIndex, this.title, this.content); + router.replace({ + uri: 'pages/index/index', + params: { + dataModel: distr.dataModel + } + }); + } +}; diff --git a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/index/index.js b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/index/index.js index 0818c2968a644129f92346bebed99764e1dc1a8d..c0b2223995a1dd820e97ca31a98d3b9040e671f9 100644 --- a/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/index/index.js +++ b/data_object/samples/distributedNotepad/entry/src/main/js/MainAbility/pages/index/index.js @@ -13,69 +13,69 @@ * limitations under the License. */ -import router from '@system.router' -import * as distr from '../../../model/DistributedDataModel.js' +import router from '@system.router'; +import * as distr from '../../../model/DistributedDataModel.js'; export default { - data: { - dataModel: distr.g_dataModel - }, - changeCallback(sessionId, changeData) { - changeData.forEach(element => { - if (element == "documentList") { - console.info("newest data " + JSON.stringify(this.dataModel.distributedObject.documentList)); - // 触发界面刷新 - this.dataModel.documentList = distr.g_dataModel.distributedObject.documentList; - } else if (element == "documentSize") { - let size = distr.g_dataModel.distributedObject.documentSize; - console.info("newest size " + size); - // 触发界面刷新 - this.dataModel.distributedObject.documentSize = size; - } - }); - }, - onInit() { - console.info("objectstore in index page "); - console.info(JSON.stringify(this.dataModel.documentList)); - console.info(JSON.stringify(distr.g_dataModel.distributedObject.documentList)); - distr.g_dataModel.setCallback(this.changeCallback.bind(this)); - distr.g_dataModel.setStatusCallback((sessionId, networkId, status) => { - console.info("objectstore status change ${networkId} ${status}"); - if (status == "online") { - this.dataModel.imgSrc = "common/green.png"; - } else { - this.dataModel.imgSrc = "common/red.png"; - } - }) - }, - onDestroy() { - console.info("objectstore exit index page"); - distr.g_dataModel.clearCallback(); - }, - add: function () { - router.replace({ - uri: "pages/add/add" - }) - }, - clear: function () { + data: { + dataModel: distr.dataModel + }, + changeCallback(sessionId, changeData) { + changeData.forEach(element => { + if (element === 'documentList') { + console.info('newest data ' + JSON.stringify(this.dataModel.distributedObject.documentList)); // 触发界面刷新 - this.dataModel.documentList = []; - this.dataModel.distributedObject.documentSize = 0; - distr.g_dataModel.clear(); - }, - detail: function (msg) { - router.replace({ - uri: "pages/detail/detail", - params: { - title: msg.target.dataSet.title, - content: msg.target.dataSet.content, - oriTitle: msg.target.dataSet.title, - oriContent: msg.target.dataSet.content, - editIndex: msg.target.dataSet.index - } - }) - } -} + this.dataModel.documentList = distr.dataModel.distributedObject.documentList; + } else if (element === 'documentSize') { + let size = distr.dataModel.distributedObject.documentSize; + console.info('newest size ' + size); + // 触发界面刷新 + this.dataModel.distributedObject.documentSize = size; + } + }); + }, + onInit() { + console.info('objectstore in index page '); + console.info(JSON.stringify(this.dataModel.documentList)); + console.info(JSON.stringify(distr.dataModel.distributedObject.documentList)); + distr.dataModel.setCallback(this.changeCallback.bind(this)); + distr.dataModel.setStatusCallback((sessionId, networkId, status) => { + console.info('objectstore status change ${networkId} ${status}'); + if (status === 'online') { + this.dataModel.imgSrc = 'common/green.png'; + } else { + this.dataModel.imgSrc = 'common/red.png'; + } + }); + }, + onDestroy() { + console.info('objectstore exit index page'); + distr.dataModel.clearCallback(); + }, + add: function () { + router.replace({ + uri: 'pages/add/add' + }); + }, + clear: function () { + // 触发界面刷新 + this.dataModel.documentList = []; + this.dataModel.distributedObject.documentSize = 0; + distr.dataModel.clear(); + }, + detail: function (msg) { + router.replace({ + uri: 'pages/detail/detail', + params: { + title: msg.target.dataSet.title, + content: msg.target.dataSet.content, + oriTitle: msg.target.dataSet.title, + oriContent: msg.target.dataSet.content, + editIndex: msg.target.dataSet.index + } + }); + } +}; diff --git a/data_object/samples/distributedNotepad/entry/src/main/js/model/DistributedDataModel.js b/data_object/samples/distributedNotepad/entry/src/main/js/model/DistributedDataModel.js index 9881d32c38a625457277a849035b037eab3d13f5..e6b4e05dd24f78845330294f9f55d38c973a86e0 100644 --- a/data_object/samples/distributedNotepad/entry/src/main/js/model/DistributedDataModel.js +++ b/data_object/samples/distributedNotepad/entry/src/main/js/model/DistributedDataModel.js @@ -13,106 +13,108 @@ * limitations under the License. */ -import distributedObject from '@ohos.data.distributedDataObject' +import distributedObject from '@ohos.data.distributedDataObject'; import featureAbility from '@ohos.ability.featureAbility'; +const REQUEST_MODE = 666; + function grantPermission() { - console.info('grantPermission'); - let context = featureAbility.getContext(); - context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], 666, function (result) { - console.info(`result.requestCode=${result.requestCode}`) + console.info('grantPermission'); + let context = featureAbility.getContext(); + context.requestPermissionsFromUser(['ohos.permission.DISTRIBUTED_DATASYNC'], REQUEST_MODE, function (result) { + console.info(`result.requestCode=${result.requestCode}`); - }) - console.info('end grantPermission'); + }); + console.info('end grantPermission'); } export default class DistributedDataModel { - documentList = []; - distributedObject; // distributed proxy - imgSrc = "common/red.png"; - #callback; - #statusCallback; + documentList = []; + distributedObject; // distributed proxy + imgSrc = 'common/red.png'; + #callback; + #statusCallback; - constructor() { - this.distributedObject = distributedObject.createDistributedObject({ - documentList: this.documentList, - documentSize: 0 - }); - this.share(); - } + constructor() { + this.distributedObject = distributedObject.createDistributedObject({ + documentList: this.documentList, + documentSize: 0 + }); + this.share(); + } - clearCallback() { - this.distributedObject.off("change"); - this.#callback = undefined; - this.distributedObject.off("status"); - this.#statusCallback = undefined; - } + clearCallback() { + this.distributedObject.off('change'); + this.#callback = undefined; + this.distributedObject.off('status'); + this.#statusCallback = undefined; + } - setCallback(callback) { - if (this.#callback == callback) { - console.info("same callback"); - return; - } - console.info("start off"); - if (this.#callback != undefined) { - this.distributedObject.off("change", this.#callback); - } - this.#callback = callback; - console.info("start watch change"); - this.distributedObject.on("change", this.#callback); + setCallback(callback) { + if (this.#callback === callback) { + console.info('same callback'); + return; } - - setStatusCallback(callback) { - if (this.#statusCallback == callback) { - console.info("same callback"); - return; - } - console.info("start off"); - if (this.#statusCallback != undefined) { - this.distributedObject.off("status", this.#statusCallback); - } - this.#statusCallback = callback; - console.info("start watch change"); - this.distributedObject.on("status", this.#statusCallback); + console.info('start off'); + if (this.#callback !== undefined) { + this.distributedObject.off('change', this.#callback); } + this.#callback = callback; + console.info('start watch change'); + this.distributedObject.on('change', this.#callback); + } - share() { - console.info("start share"); - if (this.distributedObject.__sessionId == undefined) { - grantPermission() - this.distributedObject.setSessionId("123456") - } + setStatusCallback(callback) { + if (this.#statusCallback === callback) { + console.info('same callback'); + return; } - - update(index, title, content) { - console.info("doUpdate " + title + index); - this.documentList = this.distributedObject.documentList; - this.documentList[index] = { - index: index, title: title, content: content - }; - this.distributedObject.documentList = this.documentList; - console.info("update my documentList " + JSON.stringify(this.documentList)); + console.info('start off'); + if (this.#statusCallback !== undefined) { + this.distributedObject.off('status', this.#statusCallback); } + this.#statusCallback = callback; + console.info('start watch change'); + this.distributedObject.on('status', this.#statusCallback); + } - add(title, content) { - console.info("doAdd " + title + content); - console.info("documentList " + JSON.stringify(this.documentList)); - this.documentList = this.distributedObject.documentList; - this.documentList[this.distributedObject.documentSize] = { - index: this.distributedObject.documentSize, title: title, content: content - }; - this.distributedObject.documentList = this.documentList; - this.distributedObject.documentSize++; - console.info("add my documentList " + JSON.stringify(this.documentList)); - } + share() { + console.info('start share'); + if (this.distributedObject.__sessionId === undefined) { + grantPermission(); + this.distributedObject.setSessionId('123456'); + } + } + update(index, title, content) { + console.info('doUpdate ' + title + index); + this.documentList = this.distributedObject.documentList; + this.documentList[index] = { + index: index, title: title, content: content + }; + this.distributedObject.documentList = this.documentList; + console.info('update my documentList ' + JSON.stringify(this.documentList)); + } - clear() { - console.info("doClear "); - this.documentList = []; - this.distributedObject.documentList = this.documentList; - this.distributedObject.documentSize = 0; - console.info("doClear finish"); - } + add(title, content) { + console.info('doAdd ' + title + content); + console.info('documentList ' + JSON.stringify(this.documentList)); + this.documentList = this.distributedObject.documentList; + this.documentList[this.distributedObject.documentSize] = { + index: this.distributedObject.documentSize, title: title, content: content + }; + this.distributedObject.documentList = this.documentList; + this.distributedObject.documentSize++; + console.info('add my documentList ' + JSON.stringify(this.documentList)); + } + + + clear() { + console.info('doClear '); + this.documentList = []; + this.distributedObject.documentList = this.documentList; + this.distributedObject.documentSize = 0; + console.info('doClear finish'); + } } -export var g_dataModel = new DistributedDataModel(); \ No newline at end of file +export let dataModel = new DistributedDataModel(); \ No newline at end of file diff --git a/data_share/frameworks/js/napi/common/src/datashare_predicates_proxy.cpp b/data_share/frameworks/js/napi/common/src/datashare_predicates_proxy.cpp index a0c928203afdf539f365a6701f9e8107b9627dce..13e225526484793734c9eadffeb0d90c245c2735 100644 --- a/data_share/frameworks/js/napi/common/src/datashare_predicates_proxy.cpp +++ b/data_share/frameworks/js/napi/common/src/datashare_predicates_proxy.cpp @@ -85,7 +85,11 @@ napi_value DataSharePredicatesProxy::New(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thiz, nullptr)); if (is_constructor) { - auto *proxy = new DataSharePredicatesProxy(); + auto *proxy = new (std::nothrow) DataSharePredicatesProxy(); + if (proxy == nullptr) { + LOG_ERROR("DataSharePredicatesProxy::New new DataSharePredicatesProxy error."); + return nullptr; + } proxy->predicates_ = std::make_shared(); napi_status ret = napi_wrap(env, thiz, proxy, DataSharePredicatesProxy::Destructor, nullptr, nullptr); if (ret != napi_ok) { diff --git a/data_share/frameworks/js/napi/common/src/datashare_result_set_proxy.cpp b/data_share/frameworks/js/napi/common/src/datashare_result_set_proxy.cpp index 07702427c5ce729b036cb0b143ef82ba32dc538b..cab484adb07531defe7ec68dcc9e6c7e33412a66 100644 --- a/data_share/frameworks/js/napi/common/src/datashare_result_set_proxy.cpp +++ b/data_share/frameworks/js/napi/common/src/datashare_result_set_proxy.cpp @@ -106,7 +106,11 @@ napi_value DataShareResultSetProxy::Initialize(napi_env env, napi_callback_info { napi_value self = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); - auto *proxy = new DataShareResultSetProxy(); + auto *proxy = new (std::nothrow) DataShareResultSetProxy(); + if (proxy == nullptr) { + LOG_ERROR("DataShareResultSetProxy::Initialize new DataShareResultSetProxy error."); + return nullptr; + } auto finalize = [](napi_env env, void *data, void *hint) { DataShareResultSetProxy *proxy = reinterpret_cast(data); if (proxy != nullptr) { diff --git a/data_share/frameworks/js/napi/dataShare/BUILD.gn b/data_share/frameworks/js/napi/dataShare/BUILD.gn index 04925420105c57ee695e549e38aca713af42be2c..63ac72ccb749ff6457b9afc9c2def2b659ce6a07 100644 --- a/data_share/frameworks/js/napi/dataShare/BUILD.gn +++ b/data_share/frameworks/js/napi/dataShare/BUILD.gn @@ -24,6 +24,7 @@ ohos_shared_library("datashare") { sources = [ "${datashare_napi_path}/dataShare/src/async_call.cpp", "${datashare_napi_path}/dataShare/src/napi_datashare_helper.cpp", + "${datashare_napi_path}/dataShare/src/napi_datashare_inner_observer.cpp", "${datashare_napi_path}/dataShare/src/napi_datashare_observer.cpp", "${datashare_napi_path}/dataShare/src/native_datashare_module.cpp", ] @@ -42,6 +43,7 @@ ohos_shared_library("datashare") { "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "data_share:datashare_common", "data_share:datashare_consumer", "hiviewdfx_hilog_native:libhilog", diff --git a/data_share/frameworks/js/napi/dataShare/include/napi_datashare_inner_observer.h b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_inner_observer.h new file mode 100644 index 0000000000000000000000000000000000000000..f38e63c06a35e3f68a1a7e80e683823c48ed17b7 --- /dev/null +++ b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_inner_observer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 NAPI_DATASHARE_INNER_OBSERVER_H +#define NAPI_DATASHARE_INNER_OBSERVER_H + +#include + +#include "napi/native_common.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace DataShare { +class NAPIInnerObserver : public std::enable_shared_from_this { +public: + NAPIInnerObserver(napi_env env, napi_value callback); + void OnChange(); + void DeleteReference(); + napi_ref GetCallback(); +private: + static void OnComplete(uv_work_t *work, int status); + struct ObserverWorker { + std::weak_ptr observer_; + ObserverWorker(std::shared_ptr observerIn) + : observer_(observerIn) {} + }; + + napi_env env_ = nullptr; + napi_ref ref_ = nullptr; + uv_loop_s *loop_ = nullptr; +}; +} // namespace DataShare +} // namespace OHOS +#endif //NAPI_DATASHARE_INNER_OBSERVER_H \ No newline at end of file diff --git a/data_share/frameworks/js/napi/dataShare/include/napi_datashare_observer.h b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_observer.h index ae88f0362c36b5f698879dfa47533143f7f70f31..fb0ac07211128a3cb45bcba6f2aae5d54051ea87 100644 --- a/data_share/frameworks/js/napi/dataShare/include/napi_datashare_observer.h +++ b/data_share/frameworks/js/napi/dataShare/include/napi_datashare_observer.h @@ -16,30 +16,17 @@ #ifndef NAPI_DATASHARE_OBSERVER_H #define NAPI_DATASHARE_OBSERVER_H -#include #include "data_ability_observer_stub.h" -#include "napi/native_common.h" -#include "napi/native_api.h" -#include "napi/native_node_api.h" +#include "napi_datashare_inner_observer.h" namespace OHOS { namespace DataShare { class NAPIDataShareObserver : public AAFwk::DataAbilityObserverStub { public: - NAPIDataShareObserver(napi_env env, napi_value callback); + explicit NAPIDataShareObserver(const std::shared_ptr observer) : observer_(observer){}; virtual ~NAPIDataShareObserver(); void OnChange() override; - void DeleteReference(); - napi_ref GetCallback(); -private: - struct ObserverWorker { - const NAPIDataShareObserver *observer_ = nullptr; - ObserverWorker(const NAPIDataShareObserver *observerIn) : observer_(observerIn) {} - }; - - napi_env env_ = nullptr; - napi_ref ref_ = nullptr; - uv_loop_s *loop_ = nullptr; + std::shared_ptr observer_ = nullptr; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/js/napi/dataShare/src/async_call.cpp b/data_share/frameworks/js/napi/dataShare/src/async_call.cpp index f55ab910e786c3d5eb984282b994cfc72879a9e1..7ce19f082616e14c0db3026c29f064f32d3e9784 100644 --- a/data_share/frameworks/js/napi/dataShare/src/async_call.cpp +++ b/data_share/frameworks/js/napi/dataShare/src/async_call.cpp @@ -152,7 +152,7 @@ void AsyncCall::DeleteContext(napi_env env, AsyncContext *context) napi_delete_reference(env, context->self); napi_delete_async_work(env, context->work); } - if (context != nullptr) { + if (context != nullptr && context->ctx != nullptr) { context->ctx->exec_ = nullptr; context->ctx->input_ = nullptr; context->ctx->output_ = nullptr; diff --git a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp index 1a4586ee8a6803af945b3179543dd74c1e14db73..59b76a7e73f392a93d267957f4db674f90dd259f 100644 --- a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp +++ b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_helper.cpp @@ -192,10 +192,14 @@ napi_value NapiDataShareHelper::Initialize(napi_env env, napi_callback_info info LOG_ERROR("Parameters error, need at least 2 parameters!"); return nullptr; } - auto *proxy = new NapiDataShareHelper(); + auto *proxy = new (std::nothrow) NapiDataShareHelper(); + if (proxy == nullptr) { + return nullptr; + } auto finalize = [](napi_env env, void * data, void * hint) { NapiDataShareHelper *proxy = reinterpret_cast(data); delete proxy; + LOG_INFO("NapiDataShareHelper has been deleted successfully!"); }; if (napi_wrap(env, self, proxy, finalize, nullptr, nullptr) != napi_ok) { finalize(env, proxy, nullptr); @@ -700,7 +704,7 @@ bool NapiDataShareHelper::HasRegisteredObserver(napi_env env, std::listGetCallback())) { + if (DataShareJSUtils::Equals(env, callback, it->observer_->GetCallback())) { LOG_DEBUG("The observer has already subscribed."); return true; } @@ -718,7 +722,8 @@ void NapiDataShareHelper::RegisteredObserver(napi_env env, const std::string &ur LOG_DEBUG("has registered observer"); return; } - sptr observer(new (std::nothrow) NAPIDataShareObserver(env, callback)); + auto innerObserver = std::make_shared(env, callback); + sptr observer(new (std::nothrow) NAPIDataShareObserver(innerObserver)); if (observer == nullptr) { LOG_ERROR("observer is nullptr"); return; @@ -738,12 +743,12 @@ void NapiDataShareHelper::UnRegisteredObserver(napi_env env, const std::string & auto &list = obs->second; auto it = list.begin(); while (it != list.end()) { - if (!DataShareJSUtils::Equals(env, callback, (*it)->GetCallback())) { + if (!DataShareJSUtils::Equals(env, callback, (*it)->observer_->GetCallback())) { ++it; continue; } datashareHelper_->UnregisterObserver(Uri(uri), *it); - (*it)->DeleteReference(); + (*it)->observer_->DeleteReference(); it = list.erase(it); break; } @@ -764,7 +769,7 @@ void NapiDataShareHelper::UnRegisteredObserver(napi_env env, const std::string & auto it = list.begin(); while (it != list.end()) { datashareHelper_->UnregisterObserver(Uri(uri), *it); - (*it)->DeleteReference(); + (*it)->observer_->DeleteReference(); it = list.erase(it); } observerMap_.erase(uri); diff --git a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_inner_observer.cpp b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_inner_observer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2a21b3b3c281ee097793974a87e0ca98bb957d3 --- /dev/null +++ b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_inner_observer.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "napi_datashare_observer.h" + +#include +#include "datashare_log.h" + +namespace OHOS { +namespace DataShare { +NAPIInnerObserver::NAPIInnerObserver(napi_env env, napi_value callback) + : env_(env) +{ + napi_create_reference(env, callback, 1, &ref_); + napi_get_uv_event_loop(env, &loop_); +} + +void NAPIInnerObserver::OnComplete(uv_work_t *work, int status) +{ + LOG_DEBUG("uv_queue_work start"); + std::shared_ptr innerWorker(reinterpret_cast(work->data)); + auto observer = innerWorker->observer_.lock(); + if (observer == nullptr || observer->ref_ == nullptr) { + delete work; + LOG_ERROR("innerWorker->observer_->ref_ is nullptr"); + return; + } + napi_handle_scope scope = nullptr; + napi_open_handle_scope(observer->env_, &scope); + if (scope == nullptr) { + delete work; + return; + } + napi_value callback = nullptr; + napi_value args[2] = {0}; + napi_value global = nullptr; + napi_value result; + napi_get_reference_value(observer->env_, observer->ref_, &callback); + napi_get_global(observer->env_, &global); + napi_status callStatus = napi_call_function(observer->env_, global, callback, 2, args, &result); + napi_close_handle_scope(observer->env_, scope); + if (callStatus != napi_ok) { + LOG_ERROR("napi_call_function failed status : %{public}d", callStatus); + } + delete work; +} + +void NAPIInnerObserver::OnChange() +{ + LOG_DEBUG("NAPIInnerObserver Start"); + if (ref_ == nullptr) { + LOG_ERROR("ref_ is nullptr"); + return; + } + ObserverWorker *observerWorker = new (std::nothrow)ObserverWorker(shared_from_this()); + if (observerWorker == nullptr) { + LOG_ERROR("Failed to create observerWorker"); + return; + } + uv_work_t *work = new (std::nothrow)uv_work_t(); + if (work == nullptr) { + delete observerWorker; + LOG_ERROR("Failed to create uv work"); + return; + } + work->data = observerWorker; + int ret = uv_queue_work(loop_, work, [](uv_work_t *work) {}, NAPIInnerObserver::OnComplete); + if (ret != 0) { + LOG_ERROR("uv_queue_work failed"); + delete observerWorker; + delete work; + } +} + +void NAPIInnerObserver::DeleteReference() +{ + if (ref_ != nullptr) { + napi_delete_reference(env_, ref_); + ref_ = nullptr; + } +} + +napi_ref NAPIInnerObserver::GetCallback() +{ + return ref_; +} +} // namespace DataShare +} // namespace OHOS \ No newline at end of file diff --git a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_observer.cpp b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_observer.cpp index 0b6df0d0082b10fe3bbc48c7a87002d5d8679cb7..997cf479a2fd70662ea235010b66c5a627ed4a5f 100644 --- a/data_share/frameworks/js/napi/dataShare/src/napi_datashare_observer.cpp +++ b/data_share/frameworks/js/napi/dataShare/src/napi_datashare_observer.cpp @@ -19,82 +19,12 @@ namespace OHOS { namespace DataShare { -NAPIDataShareObserver::NAPIDataShareObserver(napi_env env, napi_value callback) - : env_(env) -{ - napi_create_reference(env, callback, 1, &ref_); - napi_get_uv_event_loop(env, &loop_); -} - NAPIDataShareObserver::~NAPIDataShareObserver() {} void NAPIDataShareObserver::OnChange() { - LOG_DEBUG("Start"); - if (ref_ == nullptr) { - LOG_ERROR("ref_ is nullptr"); - return; - } - ObserverWorker *observerWorker = new (std::nothrow)ObserverWorker(this); - if (observerWorker == nullptr) { - LOG_ERROR("Failed to create observerWorker"); - return; - } - uv_work_t *work = new (std::nothrow)uv_work_t(); - if (work == nullptr) { - delete observerWorker; - LOG_ERROR("Failed to create uv work"); - return; - } - work->data = observerWorker; - int ret = uv_queue_work(loop_, work, - [](uv_work_t *work) {}, - [](uv_work_t *work, int status) { - LOG_DEBUG("uv_queue_work start"); - std::shared_ptr innerWorker(reinterpret_cast(work->data)); - if (innerWorker->observer_->ref_ == nullptr) { - delete work; - LOG_ERROR("innerWorker->observer_->ref_ is nullptr"); - return; - } - napi_handle_scope scope = nullptr; - napi_open_handle_scope(innerWorker->observer_->env_, &scope); - if (scope == nullptr) { - return; - } - napi_value callback = nullptr; - napi_value args[2] = {0}; - napi_value global = nullptr; - napi_value result; - napi_get_reference_value(innerWorker->observer_->env_, - innerWorker->observer_->ref_, &callback); - napi_get_global(innerWorker->observer_->env_, &global); - napi_status callStatus = - napi_call_function(innerWorker->observer_->env_, global, callback, 2, args, &result); - napi_close_handle_scope(innerWorker->observer_->env_, scope); - if (callStatus != napi_ok) { - LOG_ERROR("napi_call_function failed status : %{public}d", callStatus); - } - delete work; - }); - if (ret != 0) { - LOG_ERROR("uv_queue_work failed"); - delete observerWorker; - delete work; - } -} - -void NAPIDataShareObserver::DeleteReference() -{ - if (ref_ != nullptr) { - napi_delete_reference(env_, ref_); - ref_ = nullptr; - } -} - -napi_ref NAPIDataShareObserver::GetCallback() -{ - return ref_; + LOG_DEBUG("NAPIDataShareObserver Start"); + observer_->OnChange(); } } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/js/napi/datashare_ext_ability/datashare_ext_ability.js b/data_share/frameworks/js/napi/datashare_ext_ability/datashare_ext_ability.js index f8204f453ec1f75fcbe185acc00e20c7724a2e31..7e4f2aff936d45f74d221e8703912bf6001918ca 100644 --- a/data_share/frameworks/js/napi/datashare_ext_ability/datashare_ext_ability.js +++ b/data_share/frameworks/js/napi/datashare_ext_ability/datashare_ext_ability.js @@ -14,53 +14,53 @@ */ class DataShareExtensionAbility { - onCreate(want, callback) { - console.log('onCreate, want:' + want.abilityName); - } + onCreate(want, callback) { + console.log('onCreate, want:' + want.abilityName); + } - getFileTypes(uri, mimeTypeFilter, callback) { - console.log('getFileTypes, uri:' + uri); - } + getFileTypes(uri, mimeTypeFilter, callback) { + console.log('getFileTypes, uri:' + uri); + } - openFile(uri, mode, callback) { - console.log('openFile, uri:' + uri); - } + openFile(uri, mode, callback) { + console.log('openFile, uri:' + uri); + } - openRawFile(uri, mode, callback) { - console.log('openRawFile, uri:' + uri); - } + openRawFile(uri, mode, callback) { + console.log('openRawFile, uri:' + uri); + } - insert(uri, value, callback) { - console.log('insert, uri:' + uri); - } + insert(uri, value, callback) { + console.log('insert, uri:' + uri); + } - update(uri, predicates, value, callback) { - console.log('update, uri:' + uri); - } + update(uri, predicates, value, callback) { + console.log('update, uri:' + uri); + } - delete(uri, predicates, callback) { - console.log('delete, uri:' + uri); - } + delete(uri, predicates, callback) { + console.log('delete, uri:' + uri); + } - query(uri, predicates, columns, callback) { - console.log('query, uri:' + uri); - } + query(uri, predicates, columns, callback) { + console.log('query, uri:' + uri); + } - getType(uri, callback) { - console.log('getType, uri:' + uri); - } + getType(uri, callback) { + console.log('getType, uri:' + uri); + } - batchInsert(uri, values, callback) { - console.log('batchInsert, uri:' + uri); - } + batchInsert(uri, values, callback) { + console.log('batchInsert, uri:' + uri); + } - normalizeUri(uri, callback) { - console.log('normalizeUri, uri:' + uri); - } + normalizeUri(uri, callback) { + console.log('normalizeUri, uri:' + uri); + } - denormalizeUri(uri, callback) { - console.log('denormalizeUri, uri:' + uri); - } + denormalizeUri(uri, callback) { + console.log('denormalizeUri, uri:' + uri); + } } -export default DataShareExtensionAbility \ No newline at end of file +export default DataShareExtensionAbility; \ No newline at end of file diff --git a/data_share/frameworks/js/napi/datashare_ext_ability_context/datashare_ext_ability_context.js b/data_share/frameworks/js/napi/datashare_ext_ability_context/datashare_ext_ability_context.js index 68ddf9c897f35b6969b8c5a9611e775692c6b951..268a766de255f9738929710646db87f050b77338 100644 --- a/data_share/frameworks/js/napi/datashare_ext_ability_context/datashare_ext_ability_context.js +++ b/data_share/frameworks/js/napi/datashare_ext_ability_context/datashare_ext_ability_context.js @@ -13,12 +13,12 @@ * limitations under the License. */ -var ExtensionContext = requireNapi("application.ExtensionContext") +let ExtensionContext = requireNapi('application.ExtensionContext'); class DataShareExtensionAbilityContext extends ExtensionContext { - constructor(obj) { - super(obj); - } + constructor(obj) { + super(obj); + } } -export default DataShareExtensionAbilityContext \ No newline at end of file +export default DataShareExtensionAbilityContext; \ No newline at end of file diff --git a/data_share/frameworks/native/common/include/adaptor.h b/data_share/frameworks/native/common/include/adaptor.h index 074ac634a8f71507e29c9680c58c6be69e1206ab..8f9b2290b53ef1c37ec95a78eae0de23f7c3ac03 100644 --- a/data_share/frameworks/native/common/include/adaptor.h +++ b/data_share/frameworks/native/common/include/adaptor.h @@ -25,7 +25,7 @@ #else #include "hitrace.h" -#define DISTRIBUTED_DATA_HITRACE(trace) HiTrace hitrace(trace) +#define DISTRIBUTED_DATA_HITRACE(trace) DO_NOTHING #endif diff --git a/data_share/frameworks/native/common/include/datashare_block_writer_impl.h b/data_share/frameworks/native/common/include/datashare_block_writer_impl.h index 97b70c8f80efcdd19059a03ace123c3ea356e017..74c53a5d33829c5420114217224a9b1026e0d6d0 100644 --- a/data_share/frameworks/native/common/include/datashare_block_writer_impl.h +++ b/data_share/frameworks/native/common/include/datashare_block_writer_impl.h @@ -16,7 +16,7 @@ #ifndef DATASHARE_BLOCK_WRITER_IMPL_H #define DATASHARE_BLOCK_WRITER_IMPL_H -#include "shared_block.h" +#include "shared_blocker.h" #include "result_set_bridge.h" #include "datashare_errno.h" @@ -76,7 +76,7 @@ public: /** * Get Block */ - AppDataFwk::SharedBlock *GetBlock() const; + SharedBlock *GetBlock() const; private: /** @@ -89,11 +89,11 @@ private: */ int ConvertErrorCode(int shareBlockErr) { - return shareBlockErr == AppDataFwk::SharedBlock::SHARED_BLOCK_OK ? E_OK : E_ERROR; + return shareBlockErr == SharedBlock::SHARED_BLOCK_OK ? E_OK : E_ERROR; } private: - AppDataFwk::SharedBlock *shareBlock_; + SharedBlock *shareBlock_; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/common/include/datashare_shared_result_set.h b/data_share/frameworks/native/common/include/datashare_shared_result_set.h index c8a5fc6fd3fdc36439434760fe6761bf98b48ff4..8bb7c75f13ae95f6b7a03648fea626556119eb44 100644 --- a/data_share/frameworks/native/common/include/datashare_shared_result_set.h +++ b/data_share/frameworks/native/common/include/datashare_shared_result_set.h @@ -17,7 +17,7 @@ #define DATASHARE_SHARED_RESULT_SET_H #include -#include "shared_block.h" +#include "shared_blocker.h" namespace OHOS { namespace DataShare { @@ -28,11 +28,11 @@ public: /** * Obtains a block from the {@link SharedResultSet} */ - virtual AppDataFwk::SharedBlock *GetBlock() const = 0; + virtual SharedBlock *GetBlock() const = 0; /** * Adds the data of a {@code SharedResultSet} to a {@link SharedBlock} */ - virtual void FillBlock(int startRowIndex, AppDataFwk::SharedBlock *block) = 0; + virtual void FillBlock(int startRowIndex, SharedBlock *block) = 0; /** * Called when the position of the result set changes */ diff --git a/data_share/frameworks/native/common/include/shared_block.h b/data_share/frameworks/native/common/include/shared_blocker.h similarity index 92% rename from data_share/frameworks/native/common/include/shared_block.h rename to data_share/frameworks/native/common/include/shared_blocker.h index 1230171c00e05fb17989e153451dc6f3fb6f7953..f6980c835b907758b01425456c20d147cab09c66 100644 --- a/data_share/frameworks/native/common/include/shared_block.h +++ b/data_share/frameworks/native/common/include/shared_blocker.h @@ -13,28 +13,29 @@ * limitations under the License. */ -#ifndef SHARED_BLOCK_H -#define SHARED_BLOCK_H +#ifndef SHARED_BLOCKER_H +#define SHARED_BLOCKER_H +#include #include - #include -#include + #include "message_parcel.h" #include "parcel.h" #include "securec.h" namespace OHOS { -namespace AppDataFwk { +namespace DataShare { static const uint32_t INVALID_ROW_RECORD = 0xFFFFFFFF; /** * This class stores a set of rows from a database in a buffer, * which is used as the set of query result. */ -class SharedBlock { +class SharedBlocker { public: /* Cell Unit types. */ - enum { + enum + { CELL_UNIT_TYPE_NULL = 0, CELL_UNIT_TYPE_INTEGER = 1, CELL_UNIT_TYPE_FLOAT = 2, @@ -43,7 +44,8 @@ public: }; /* SharedBlock error types. */ - enum { + enum + { SHARED_BLOCK_OK = 0, SHARED_BLOCK_BAD_VALUE = 1, SHARED_BLOCK_NO_MEMORY = 2, @@ -68,12 +70,12 @@ public: /** * SharedBlock constructor. */ - SharedBlock(const std::string &name, sptr ashmem, size_t size, bool readOnly); + SharedBlocker(const std::string &name, sptr ashmem, size_t size, bool readOnly); /** * SharedBlock constructor. */ - ~SharedBlock(); + ~SharedBlocker(); /** * Init current shared block. @@ -83,7 +85,7 @@ public: /** * Create a shared block. */ - static int Create(const std::string &name, size_t size, SharedBlock *&outSharedBlock); + static int Create(const std::string &name, size_t size, SharedBlocker *&outSharedBlock); /** * Clear current shared block. @@ -204,7 +206,7 @@ public: int WriteMessageParcel(MessageParcel &parcel); - static int ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block); + static int ReadMessageParcel(MessageParcel &parcel, SharedBlocker *&block); /** * Write raw data in block. */ @@ -263,7 +265,7 @@ private: */ static const size_t COL_MAX_NUM = 32767; - struct SharedBlockHeader { + struct BlockerHeader { /* Offset of the lowest unused byte in the block. */ uint32_t unusedOffset; /* Offset of the first row group. */ @@ -285,7 +287,7 @@ private: uint32_t nextGroupOffset; }; - SharedBlockHeader *mHeader; + BlockerHeader *mHeader; /** * Allocate a portion of the block. Returns the offset of the allocation. @@ -300,7 +302,7 @@ private: int PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type); static int CreateSharedBlock(const std::string &name, size_t size, sptr ashmem, - SharedBlock *&outSharedBlock); + SharedBlocker *&outSharedBlock); uint32_t OffsetFromPtr(void *ptr); @@ -318,13 +320,14 @@ private: /** * Convert utf8 string to utf16. */ - static std::u16string ToUtf16(const std::string& str); + static std::u16string ToUtf16(const std::string &str); /** * Convert utf16 string to utf8. */ - static std::string ToUtf8(const std::u16string& str16); + static std::string ToUtf8(const std::u16string &str16); }; -} // namespace AppDataFwk +using SharedBlock = SharedBlocker; +} // namespace DataShare } // namespace OHOS -#endif +#endif // SHARED_BLOCKER_H diff --git a/data_share/frameworks/native/common/src/datashare_block_writer_impl.cpp b/data_share/frameworks/native/common/src/datashare_block_writer_impl.cpp index 8442cc02f811088b9ada86628644f3576e1098ff..33070de5183597fa387c1c28945d0b1a4a73ada3 100644 --- a/data_share/frameworks/native/common/src/datashare_block_writer_impl.cpp +++ b/data_share/frameworks/native/common/src/datashare_block_writer_impl.cpp @@ -25,7 +25,7 @@ DataShareBlockWriterImpl::DataShareBlockWriterImpl() : shareBlock_(nullptr) DataShareBlockWriterImpl::DataShareBlockWriterImpl(const std::string &name, size_t size) : shareBlock_(nullptr) { - AppDataFwk::SharedBlock::Create(name, size, shareBlock_); + SharedBlock::Create(name, size, shareBlock_); } DataShareBlockWriterImpl::~DataShareBlockWriterImpl() @@ -91,7 +91,7 @@ int DataShareBlockWriterImpl::Write(uint32_t column, const char *value, size_t s return ConvertErrorCode(shareBlock_->PutString(currentRowIndex, column, value, sizeIncludingNull)); } -AppDataFwk::SharedBlock *DataShareBlockWriterImpl::GetBlock() const +SharedBlock *DataShareBlockWriterImpl::GetBlock() const { return shareBlock_; } diff --git a/data_share/frameworks/native/common/src/datashare_result_set.cpp b/data_share/frameworks/native/common/src/datashare_result_set.cpp index 271671ec62711ec32d49a616cdaf63201b2398c7..742c0291da05a42524a90cb52b177a4ee45e0a61 100644 --- a/data_share/frameworks/native/common/src/datashare_result_set.cpp +++ b/data_share/frameworks/native/common/src/datashare_result_set.cpp @@ -94,7 +94,7 @@ bool DataShareResultSet::OnGo(int startRowIndex, int targetRowIndex, int *cached return true; } -void DataShareResultSet::FillBlock(int startRowIndex, AppDataFwk::SharedBlock *block) +void DataShareResultSet::FillBlock(int startRowIndex, SharedBlock *block) { return; } @@ -102,7 +102,7 @@ void DataShareResultSet::FillBlock(int startRowIndex, AppDataFwk::SharedBlock *b /** * Get current shared block */ -AppDataFwk::SharedBlock *DataShareResultSet::GetBlock() const +SharedBlock *DataShareResultSet::GetBlock() const { return sharedBlock_; } @@ -111,7 +111,7 @@ int DataShareResultSet::GetDataType(int columnIndex, DataType &dataType) { int rowCount = 0; GetRowCount(rowCount); - AppDataFwk::SharedBlock::CellUnit *cellUnit = + SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(static_cast(rowPos_) - startRowPos_, static_cast(columnIndex)); if (!cellUnit) { LOG_ERROR("cellUnit is null!"); @@ -168,7 +168,7 @@ int DataShareResultSet::GetBlob(int columnIndex, std::vector &value) return errorCode; } - AppDataFwk::SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); + SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); if (!cellUnit) { LOG_ERROR("cellUnit is null!"); return E_ERROR; @@ -176,8 +176,8 @@ int DataShareResultSet::GetBlob(int columnIndex, std::vector &value) value.resize(0); int type = cellUnit->type; - if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_BLOB - || type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_STRING) { + if (type == SharedBlock::CELL_UNIT_TYPE_BLOB + || type == SharedBlock::CELL_UNIT_TYPE_STRING) { size_t size; const auto *blob = static_cast(sharedBlock_->GetCellUnitValueBlob(cellUnit, &size)); if (size == 0 || blob == nullptr) { @@ -187,11 +187,11 @@ int DataShareResultSet::GetBlob(int columnIndex, std::vector &value) value.assign(blob, blob + size); } return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_INTEGER) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_INTEGER) { return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_NULL) { return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_FLOAT) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_FLOAT) { return E_OK; } else { LOG_ERROR("AppDataFwk::SharedBlock::nothing !"); @@ -205,30 +205,30 @@ int DataShareResultSet::GetString(int columnIndex, std::string &value) LOG_ERROR("sharedBlock is null!"); return E_ERROR; } - AppDataFwk::SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); + SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); if (!cellUnit) { LOG_ERROR("cellUnit is null!"); return E_ERROR; } int type = cellUnit->type; - if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_STRING) { + if (type == SharedBlock::CELL_UNIT_TYPE_STRING) { size_t sizeIncludingNull; value = std::string(sharedBlock_->GetCellUnitValueString(cellUnit, &sizeIncludingNull)); return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_NULL) { return E_ERROR; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_INTEGER) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_INTEGER) { int64_t tempValue = cellUnit->cell.longValue; value = std::to_string(tempValue); return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_FLOAT) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_FLOAT) { double tempValue = cellUnit->cell.doubleValue; std::ostringstream os; if (os << tempValue) { value = os.str(); } return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_BLOB) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_BLOB) { return E_ERROR; } else { LOG_ERROR("GetString is failed!"); @@ -242,7 +242,7 @@ int DataShareResultSet::GetInt(int columnIndex, int &value) LOG_ERROR("sharedBlock is null!"); return E_ERROR; } - AppDataFwk::SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); + SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); if (!cellUnit) { LOG_ERROR("cellUnit is null!"); return E_ERROR; @@ -257,7 +257,7 @@ int DataShareResultSet::GetLong(int columnIndex, int64_t &value) LOG_ERROR("sharedBlock is null!"); return E_ERROR; } - AppDataFwk::SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); + SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); if (!cellUnit) { LOG_ERROR("cellUnit is null!"); return E_ERROR; @@ -265,21 +265,21 @@ int DataShareResultSet::GetLong(int columnIndex, int64_t &value) int type = cellUnit->type; - if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_INTEGER) { + if (type == SharedBlock::CELL_UNIT_TYPE_INTEGER) { value = cellUnit->cell.longValue; return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_STRING) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_STRING) { size_t sizeIncludingNull; const char *tempValue = sharedBlock_->GetCellUnitValueString(cellUnit, &sizeIncludingNull); value = ((sizeIncludingNull > 1) && (tempValue != nullptr)) ? long(strtoll(tempValue, nullptr, 0)) : 0L; return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_FLOAT) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_FLOAT) { value = (int64_t)cellUnit->cell.doubleValue; return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_NULL) { value = 0L; return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_BLOB) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_BLOB) { value = 0L; return E_OK; } else { @@ -294,27 +294,27 @@ int DataShareResultSet::GetDouble(int columnIndex, double &value) if (errorCode != E_OK) { return errorCode; } - AppDataFwk::SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); + SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); if (!cellUnit) { LOG_ERROR("cellUnit is null!"); return E_ERROR; } int type = cellUnit->type; - if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_FLOAT) { + if (type == SharedBlock::CELL_UNIT_TYPE_FLOAT) { value = cellUnit->cell.doubleValue; return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_STRING) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_STRING) { size_t sizeIncludingNull; const char *tempValue = sharedBlock_->GetCellUnitValueString(cellUnit, &sizeIncludingNull); value = ((sizeIncludingNull > 1) && (tempValue != nullptr)) ? strtod(tempValue, nullptr) : 0.0; return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_INTEGER) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_INTEGER) { value = static_cast(cellUnit->cell.longValue); return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_NULL) { value = 0.0; return E_OK; - } else if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_BLOB) { + } else if (type == SharedBlock::CELL_UNIT_TYPE_BLOB) { value = 0.0; return E_OK; } else { @@ -330,12 +330,12 @@ int DataShareResultSet::IsColumnNull(int columnIndex, bool &isNull) if (errorCode != E_OK) { return errorCode; } - AppDataFwk::SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); + SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(rowPos_ - startRowPos_, columnIndex); if (!cellUnit) { LOG_ERROR("cellUnit is null!"); return E_ERROR; } - if (cellUnit->type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_NULL) { + if (cellUnit->type == SharedBlock::CELL_UNIT_TYPE_NULL) { isNull = true; return E_OK; } @@ -355,7 +355,7 @@ int DataShareResultSet::Close() /** * Allocates a new shared block to an {@link DataShareResultSet} */ -void DataShareResultSet::SetBlock(AppDataFwk::SharedBlock *block) +void DataShareResultSet::SetBlock(SharedBlock *block) { if (sharedBlock_ != block) { ClosedBlock(); @@ -421,7 +421,7 @@ bool DataShareResultSet::Unmarshalling(MessageParcel &parcel) if (sharedBlock_ != nullptr) { return false; } - int result = AppDataFwk::SharedBlock::ReadMessageParcel(parcel, sharedBlock_); + int result = SharedBlock::ReadMessageParcel(parcel, sharedBlock_); if (result < 0) { LOG_ERROR("create from parcel error is %{public}d.", result); } diff --git a/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp b/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp index 91e58cc5bf182092ace04712fb011c6f01e480da..2df45f5e7be43f01bdf35d39db0b3a43499ed418 100644 --- a/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp +++ b/data_share/frameworks/native/common/src/ishared_result_set_proxy.cpp @@ -15,7 +15,6 @@ #include "ishared_result_set_proxy.h" -#include "adaptor.h" #include "datashare_errno.h" #include "datashare_log.h" #include "iremote_proxy.h" @@ -74,7 +73,6 @@ int ISharedResultSetProxy::GetAllColumnNames(std::vector &columnNam int ISharedResultSetProxy::GetRowCount(int &count) { - DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); if (rowCount_ >= 0) { count = rowCount_; return E_OK; diff --git a/data_share/frameworks/native/common/src/shared_block.cpp b/data_share/frameworks/native/common/src/shared_blocker.cpp similarity index 77% rename from data_share/frameworks/native/common/src/shared_block.cpp rename to data_share/frameworks/native/common/src/shared_blocker.cpp index bdb418ac89ddddadd040124fb2d8b189b5ff4ad5..52cd0e743103ccc47b647283cc214418f422e323 100644 --- a/data_share/frameworks/native/common/src/shared_block.cpp +++ b/data_share/frameworks/native/common/src/shared_blocker.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "shared_block.h" +#include "shared_blocker.h" #include #include #include @@ -26,93 +26,92 @@ #include "datashare_log.h" namespace OHOS { -namespace AppDataFwk { -using namespace OHOS::DataShare; -SharedBlock::SharedBlock(const std::string &name, sptr ashmem, size_t size, bool readOnly) +namespace DataShare { +SharedBlocker::SharedBlocker(const std::string &name, sptr ashmem, size_t size, bool readOnly) : mName(name), ashmem_(ashmem), mSize(size), mReadOnly(readOnly), mHeader(nullptr) { } -SharedBlock::~SharedBlock() +SharedBlocker::~SharedBlocker() { if (ashmem_ != nullptr) { ashmem_->UnmapAshmem(); ashmem_->CloseAshmem(); - LOG_WARN("SharedBlock: close ashmem"); + LOG_WARN("SharedBlocker: close ashmem"); } } -std::u16string SharedBlock::ToUtf16(const std::string& str) +std::u16string SharedBlocker::ToUtf16(const std::string& str) { return OHOS::Str8ToStr16(str); } -std::string SharedBlock::ToUtf8(const std::u16string& str16) +std::string SharedBlocker::ToUtf8(const std::u16string& str16) { return OHOS::Str16ToStr8(str16); } -bool SharedBlock::Init() +bool SharedBlocker::Init() { - mData = const_cast(ashmem_->ReadFromAshmem(sizeof(SharedBlockHeader), 0)); - mHeader = static_cast(mData); + mData = const_cast(ashmem_->ReadFromAshmem(sizeof(BlockerHeader), 0)); + mHeader = static_cast(mData); if (mHeader == nullptr) { return false; } return true; } -int SharedBlock::CreateSharedBlock(const std::string &name, size_t size, sptr ashmem, - SharedBlock *&outSharedBlock) +int SharedBlocker::CreateSharedBlock(const std::string &name, size_t size, sptr ashmem, + SharedBlocker *&outSharedBlocker) { - outSharedBlock = new SharedBlock(name, ashmem, size, false); - if (outSharedBlock == nullptr) { - LOG_ERROR("CreateSharedBlock: new SharedBlock error."); + outSharedBlocker = new SharedBlocker(name, ashmem, size, false); + if (outSharedBlocker == nullptr) { + LOG_ERROR("CreateSharedBlocker: new SharedBlocker error."); return SHARED_BLOCK_BAD_VALUE; } - if (!outSharedBlock->Init()) { - delete outSharedBlock; - outSharedBlock = nullptr; - LOG_ERROR("CreateSharedBlock: mHeader is null."); + if (!outSharedBlocker->Init()) { + delete outSharedBlocker; + outSharedBlocker = nullptr; + LOG_ERROR("CreateSharedBlocker: mHeader is null."); return SHARED_BLOCK_ASHMEM_ERROR; } return SHARED_BLOCK_OK; } -int SharedBlock::Create(const std::string &name, size_t size, SharedBlock *&outSharedBlock) +int SharedBlocker::Create(const std::string &name, size_t size, SharedBlocker *&outSharedBlocker) { - std::string ashmemName = "SharedBlock:" + name; + std::string ashmemName = "SharedBlocker:" + name; sptr ashmem = Ashmem::CreateAshmem(ashmemName.c_str(), size); if (ashmem == nullptr) { - LOG_ERROR("SharedBlock: CreateAshmem function error."); + LOG_ERROR("SharedBlocker: CreateAshmem function error."); return SHARED_BLOCK_ASHMEM_ERROR; } bool ret = ashmem->MapReadAndWriteAshmem(); if (!ret) { - LOG_ERROR("SharedBlock: MapReadAndWriteAshmem function error."); + LOG_ERROR("SharedBlocker: MapReadAndWriteAshmem function error."); ashmem->CloseAshmem(); return SHARED_BLOCK_SET_PORT_ERROR; } - int result = CreateSharedBlock(name, size, ashmem, outSharedBlock); + int result = CreateSharedBlock(name, size, ashmem, outSharedBlocker); if (result == SHARED_BLOCK_OK) { return SHARED_BLOCK_OK; } ashmem->UnmapAshmem(); ashmem->CloseAshmem(); - outSharedBlock = nullptr; + outSharedBlocker = nullptr; return result; } -int SharedBlock::WriteMessageParcel(MessageParcel &parcel) +int SharedBlocker::WriteMessageParcel(MessageParcel &parcel) { return parcel.WriteString16(ToUtf16(mName)) && parcel.WriteAshmem(ashmem_); } -int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block) +int SharedBlocker::ReadMessageParcel(MessageParcel &parcel, SharedBlocker *&block) { std::string name = ToUtf8(parcel.ReadString16()); sptr ashmem = parcel.ReadAshmem(); @@ -126,9 +125,9 @@ int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block) ashmem->CloseAshmem(); return SHARED_BLOCK_SET_PORT_ERROR; } - block = new (std::nothrow) SharedBlock(name, ashmem, ashmem->GetAshmemSize(), true); + block = new (std::nothrow) SharedBlocker(name, ashmem, ashmem->GetAshmemSize(), true); if (block == nullptr) { - LOG_ERROR("ReadMessageParcel new SharedBlock error."); + LOG_ERROR("ReadMessageParcel new SharedBlocker error."); return SHARED_BLOCK_BAD_VALUE; } if (!block->Init()) { @@ -138,7 +137,7 @@ int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block) return SHARED_BLOCK_ASHMEM_ERROR; } - LOG_DEBUG("Created SharedBlock from parcel: unusedOffset=%{private}" PRIu32 ", " + LOG_DEBUG("Created SharedBlocker from parcel: unusedOffset=%{private}" PRIu32 ", " "rowNums=%{private}" PRIu32 ", columnNums=%{private}" PRIu32 ", mSize=%{private}d", block->mHeader->unusedOffset, block->mHeader->rowNums, block->mHeader->columnNums, static_cast(block->mSize)); @@ -146,14 +145,14 @@ int SharedBlock::ReadMessageParcel(MessageParcel &parcel, SharedBlock *&block) return SHARED_BLOCK_OK; } -int SharedBlock::Clear() +int SharedBlocker::Clear() { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; } - mHeader->unusedOffset = sizeof(SharedBlockHeader) + sizeof(RowGroupHeader); - mHeader->firstRowGroupOffset = sizeof(SharedBlockHeader); + mHeader->unusedOffset = sizeof(BlockerHeader) + sizeof(RowGroupHeader); + mHeader->firstRowGroupOffset = sizeof(BlockerHeader); mHeader->rowNums = 0; mHeader->columnNums = 0; mHeader->startPos_ = 0; @@ -169,7 +168,7 @@ int SharedBlock::Clear() return SHARED_BLOCK_OK; } -int SharedBlock::SetColumnNum(uint32_t numColumns) +int SharedBlocker::SetColumnNum(uint32_t numColumns) { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; @@ -188,7 +187,7 @@ int SharedBlock::SetColumnNum(uint32_t numColumns) return SHARED_BLOCK_OK; } -int SharedBlock::AllocRow() +int SharedBlocker::AllocRow() { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; @@ -225,7 +224,7 @@ int SharedBlock::AllocRow() return SHARED_BLOCK_OK; } -int SharedBlock::FreeLastRow() +int SharedBlocker::FreeLastRow() { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; @@ -238,7 +237,7 @@ int SharedBlock::FreeLastRow() return SHARED_BLOCK_OK; } -uint32_t SharedBlock::Alloc(size_t size, bool aligned) +uint32_t SharedBlocker::Alloc(size_t size, bool aligned) { /* Number of unused offsets in the header */ uint32_t offsetDigit = 3; @@ -247,7 +246,7 @@ uint32_t SharedBlock::Alloc(size_t size, bool aligned) uint32_t nextFreeOffset; if (offset + size > mSize) { - LOG_ERROR("SharedBlock is full: requested allocation %{public}zu bytes," + LOG_ERROR("SharedBlocker is full: requested allocation %{public}zu bytes," " free space %{public}zu bytes, block size %{public}zu bytes", size, mSize - mHeader->unusedOffset, mSize); return 0; @@ -257,7 +256,7 @@ uint32_t SharedBlock::Alloc(size_t size, bool aligned) return offset; } -inline uint32_t *SharedBlock::GetRowOffset(uint32_t row) +inline uint32_t *SharedBlocker::GetRowOffset(uint32_t row) { uint32_t rowPos = row; @@ -279,7 +278,7 @@ inline uint32_t *SharedBlock::GetRowOffset(uint32_t row) return &group->rowOffsets[rowPos]; } -uint32_t *SharedBlock::AllocRowOffset() +uint32_t *SharedBlocker::AllocRowOffset() { uint32_t rowPos = mHeader->rowNums; @@ -318,10 +317,10 @@ uint32_t *SharedBlock::AllocRowOffset() return &group->rowOffsets[rowPos]; } -SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column) +SharedBlocker::CellUnit *SharedBlocker::GetCellUnit(uint32_t row, uint32_t column) { if (row >= mHeader->rowNums || column >= mHeader->columnNums) { - LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlock" + LOG_ERROR("Failed to read row %{public}" PRIu32 ", column %{public}" PRIu32 " from a SharedBlocker" " which has %{public}" PRIu32 " rows, %{public}" PRIu32 " columns.", row, column, mHeader->rowNums, mHeader->columnNums); return nullptr; @@ -342,17 +341,17 @@ SharedBlock::CellUnit *SharedBlock::GetCellUnit(uint32_t row, uint32_t column) return &cellUnit[column]; } -int SharedBlock::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size) +int SharedBlocker::PutBlob(uint32_t row, uint32_t column, const void *value, size_t size) { return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_BLOB); } -int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull) +int SharedBlocker::PutString(uint32_t row, uint32_t column, const char *value, size_t sizeIncludingNull) { return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING); } -int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type) +int SharedBlocker::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type) { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; @@ -386,7 +385,7 @@ int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *valu return SHARED_BLOCK_OK; } -int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value) +int SharedBlocker::PutLong(uint32_t row, uint32_t column, int64_t value) { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; @@ -402,7 +401,7 @@ int SharedBlock::PutLong(uint32_t row, uint32_t column, int64_t value) return SHARED_BLOCK_OK; } -int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value) +int SharedBlocker::PutDouble(uint32_t row, uint32_t column, double value) { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; @@ -418,7 +417,7 @@ int SharedBlock::PutDouble(uint32_t row, uint32_t column, double value) return SHARED_BLOCK_OK; } -int SharedBlock::PutNull(uint32_t row, uint32_t column) +int SharedBlocker::PutNull(uint32_t row, uint32_t column) { if (mReadOnly) { return SHARED_BLOCK_INVALID_OPERATION; @@ -435,14 +434,14 @@ int SharedBlock::PutNull(uint32_t row, uint32_t column) return SHARED_BLOCK_OK; } -size_t SharedBlock::SetRawData(const void *rawData, size_t size) +size_t SharedBlocker::SetRawData(const void *rawData, size_t size) { if (size <= 0) { - LOG_ERROR("SharedBlock rawData is less than or equal to 0M"); + LOG_ERROR("SharedBlocker rawData is less than or equal to 0M"); return SHARED_BLOCK_INVALID_OPERATION; } if (size > mSize) { - LOG_ERROR("SharedBlock size is %{public}zu, current byteArray size is %{public}zu", mSize, size); + LOG_ERROR("SharedBlocker size is %{public}zu, current byteArray size is %{public}zu", mSize, size); return SHARED_BLOCK_NO_MEMORY; } @@ -453,7 +452,7 @@ size_t SharedBlock::SetRawData(const void *rawData, size_t size) return SHARED_BLOCK_OK; } -uint32_t SharedBlock::OffsetFromPtr(void *ptr) +uint32_t SharedBlocker::OffsetFromPtr(void *ptr) { return static_cast(ptr) - static_cast(mData); } diff --git a/data_share/frameworks/native/consumer/include/base_connection.h b/data_share/frameworks/native/consumer/include/base_connection.h index 97fc66e3c437c956d73c5e1a8cc85970acb17649..4a77c746be0993e59dff16958862f453b630a9df 100644 --- a/data_share/frameworks/native/consumer/include/base_connection.h +++ b/data_share/frameworks/native/consumer/include/base_connection.h @@ -32,10 +32,9 @@ enum class ConnectionType { class BaseConnection { public: BaseConnection(ConnectionType type = ConnectionType::NORMAL) : type_(type) {}; - ~BaseConnection()=default; + virtual ~BaseConnection() = default; virtual std::shared_ptr GetDataShareProxy() = 0; - virtual bool ConnectDataShare(const Uri &uri, const sptr token) = 0; - virtual bool IsConnected() = 0; + virtual bool ConnectDataShare(const Uri &uri, const sptr &token) = 0; ConnectionType GetType() { return type_; @@ -43,7 +42,6 @@ public: private: ConnectionType type_ = ConnectionType::NORMAL; }; - }} #endif // DATA_SHARE_BASE_CONNECTION_H diff --git a/data_share/frameworks/native/consumer/include/datashare_connection.h b/data_share/frameworks/native/consumer/include/datashare_connection.h index 02dd75812b6a351a6dfc9f5c83963400ba945cd7..e199328127499b5753fa590c88dfc6170c9b4eb1 100644 --- a/data_share/frameworks/native/consumer/include/datashare_connection.h +++ b/data_share/frameworks/native/consumer/include/datashare_connection.h @@ -57,30 +57,24 @@ public: void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; /** - * @brief connect remote ability of DataShareExtAbility. + * @brief disconnect remote ability of DataShareExtAbility. */ - bool ConnectDataShareExtAbility(const Uri &uri, const sptr token); + void DisconnectDataShareExtAbility(); /** * @brief get the proxy of datashare extension ability. * * @return the proxy of datashare extension ability. */ - + std::shared_ptr GetDataShareProxy() override; + bool ConnectDataShare(const Uri &uri, const sptr &token) override ; +private: struct ConnectCondition { std::condition_variable condition; std::mutex mutex; }; - - std::shared_ptr GetDataShareProxy() override; - bool ConnectDataShare(const Uri &uri, const sptr token) override ; - bool IsConnected() override ; - -private: - void DisconnectDataShareExtAbility(); void SetDataShareProxy(sptr proxy); - bool IsExtAbilityConnected(); - + bool ConnectDataShareExtAbility(const Uri &uri, const sptr &token); std::mutex mutex_; std::shared_ptr dataShareProxy_; ConnectCondition condition_; diff --git a/data_share/frameworks/native/consumer/src/connection_factory.cpp b/data_share/frameworks/native/consumer/src/connection_factory.cpp index 4aaca9064c88661f24392e7305d4798a4accde09..2576f1a42cc789f071aeb78dabcaf47a9d491857 100644 --- a/data_share/frameworks/native/consumer/src/connection_factory.cpp +++ b/data_share/frameworks/native/consumer/src/connection_factory.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + #include "connection_factory.h" #include @@ -34,8 +34,9 @@ std::shared_ptr ConnectionFactory::GetConnection(Uri &uri, cons LOG_ERROR("Factory Create DataShareConnection failed."); return nullptr; } - return std::shared_ptr( - connection.GetRefPtr(), [holder = connection](const auto *) {}); + return std::shared_ptr(connection.GetRefPtr(), [holder = connection](const auto *) { + holder->DisconnectDataShareExtAbility(); + }); } ConnectionFactory& ConnectionFactory::GetInstance() diff --git a/data_share/frameworks/native/consumer/src/datashare_connection.cpp b/data_share/frameworks/native/consumer/src/datashare_connection.cpp index aa0e323bc59b8ff87a7199cc6c5668a55d47dd7d..58e11e2d992f4e6d92839288ca15cbd9c40b5e2c 100644 --- a/data_share/frameworks/native/consumer/src/datashare_connection.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_connection.cpp @@ -22,8 +22,7 @@ namespace OHOS { namespace DataShare { using namespace AppExecFwk; -constexpr int WAIT_TIME = 3; - +constexpr int WAIT_TIME = 1; /** * @brief This method is called back to receive the connection result after an ability calls the * ConnectAbility method to connect it to an extension ability. @@ -36,6 +35,7 @@ constexpr int WAIT_TIME = 3; void DataShareConnection::OnAbilityConnectDone( const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) { + LOG_INFO("on connect done, uri:%{public}s, ret=%{public}d", uri_.ToString().c_str(), resultCode); if (remoteObject == nullptr) { LOG_ERROR("remote is nullptr"); return; @@ -56,13 +56,13 @@ void DataShareConnection::OnAbilityConnectDone( */ void DataShareConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) { + LOG_INFO("on disconnect done, uri:%{public}s, ret:%{public}d", uri_.ToString().c_str(), resultCode); { std::unique_lock lock(condition_.mutex); SetDataShareProxy(nullptr); condition_.condition.notify_all(); } if (!uri_.ToString().empty()) { - LOG_INFO("uri : %{public}s disconnect,start reconnect", uri_.ToString().c_str()); ConnectDataShareExtAbility(uri_, token_); } } @@ -70,7 +70,7 @@ void DataShareConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName /** * @brief connect remote ability of DataShareExtAbility. */ -bool DataShareConnection::ConnectDataShareExtAbility(const Uri &uri, const sptr token) +bool DataShareConnection::ConnectDataShareExtAbility(const Uri &uri, const sptr &token) { if (dataShareProxy_ != nullptr) { return true; @@ -82,17 +82,16 @@ bool DataShareConnection::ConnectDataShareExtAbility(const Uri &uri, const sptr< } else { want.SetUri(uri_); } - std::unique_lock lock(condition_.mutex); ErrCode ret = AAFwk::AbilityManagerClient::GetInstance()->ConnectAbility(want, this, token); if (ret != ERR_OK) { LOG_ERROR("connect ability failed, ret = %{public}d", ret); return false; } + std::unique_lock lock(condition_.mutex); if (condition_.condition.wait_for(lock, std::chrono::seconds(WAIT_TIME), [this] { return dataShareProxy_ != nullptr; })) { LOG_INFO("connect ability ended successfully"); } - LOG_INFO("called end, ret=%{public}d", ret); return dataShareProxy_ != nullptr; } @@ -101,30 +100,22 @@ bool DataShareConnection::ConnectDataShareExtAbility(const Uri &uri, const sptr< */ void DataShareConnection::DisconnectDataShareExtAbility() { + uri_ = Uri(""); if (dataShareProxy_ == nullptr) { return; } - std::unique_lock lock(condition_.mutex); ErrCode ret = AAFwk::AbilityManagerClient::GetInstance()->DisconnectAbility(this); if (ret != ERR_OK) { LOG_ERROR("disconnect ability failed, ret = %{public}d", ret); return; } + std::unique_lock lock(condition_.mutex); if (condition_.condition.wait_for(lock, std::chrono::seconds(WAIT_TIME), [this] { return dataShareProxy_ == nullptr; })) { - LOG_INFO("disconnect ability ended successfully"); + LOG_INFO("disconnect ability successfully"); + } else { + LOG_INFO("disconnect timeout"); } - LOG_INFO("called end, ret=%{public}d", ret); -} - -/** - * @brief check whether connected to remote extension ability. - * - * @return bool true if connected, otherwise false. - */ -bool DataShareConnection::IsExtAbilityConnected() -{ - return dataShareProxy_ != nullptr; } void DataShareConnection::SetDataShareProxy(sptr proxy) @@ -140,22 +131,16 @@ void DataShareConnection::SetDataShareProxy(sptr proxy) DataShareConnection::~DataShareConnection() { - uri_ = Uri(""); - DisconnectDataShareExtAbility(); } + std::shared_ptr DataShareConnection::GetDataShareProxy() { return dataShareProxy_; } -bool DataShareConnection::ConnectDataShare(const Uri & uri, const sptr token) +bool DataShareConnection::ConnectDataShare(const Uri & uri, const sptr &token) { return ConnectDataShareExtAbility(uri, token); } - -bool DataShareConnection::IsConnected() -{ - return dataShareProxy_ != nullptr; -} } // namespace DataShare } // namespace OHOS \ No newline at end of file diff --git a/data_share/frameworks/native/consumer/src/datashare_helper.cpp b/data_share/frameworks/native/consumer/src/datashare_helper.cpp index 312e4e9e75623f5f457da82c2bec9077da5e2cb9..829b1c36cf7086914f5fec786c9d01d2f660c82e 100644 --- a/data_share/frameworks/native/consumer/src/datashare_helper.cpp +++ b/data_share/frameworks/native/consumer/src/datashare_helper.cpp @@ -45,7 +45,6 @@ private: DataShareHelper::DataShareHelper(const sptr &token, const Uri &uri, std::shared_ptr dataShareConnection) { - LOG_INFO("DataShareHelper::DataShareHelper start"); token_ = token; uri_ = uri; isDataShareService_ = (uri_.GetQuery().find("Proxy=true") != std::string::npos); @@ -54,11 +53,9 @@ DataShareHelper::DataShareHelper(const sptr &token, const Uri &ur DataShareHelper::DataShareHelper(const sptr &token, const Uri &uri) { - LOG_INFO("DataShareHelper::DataShareHelper start"); token_ = token; uri_ = uri; isDataShareService_ = (uri_.GetQuery().find("Proxy=true") != std::string::npos); - LOG_INFO("DataShareHelper::DataShareHelper end"); } DataShareHelper::~DataShareHelper() @@ -136,7 +133,7 @@ std::shared_ptr DataShareHelper::Creator(const sptrSendRequest(CMD_BATCH_INSERT, data, reply, option); if (err != DATA_SHARE_NO_ERROR) { - LOG_ERROR("GetFileTypes fail to SendRequest. err: %{public}d", err); + LOG_ERROR("fail to SendRequest. err: %{public}d", err); return err == PERMISSION_ERR ? PERMISSION_ERR_CODE : ret; } diff --git a/data_share/frameworks/native/provider/include/datashare_ext_ability.h b/data_share/frameworks/native/provider/include/datashare_ext_ability.h index e4a57eff9c7f5e3405bf8f75de88a7d39f20760a..dcafee55072271e1d02e082b01ea05812a7b8f3f 100644 --- a/data_share/frameworks/native/provider/include/datashare_ext_ability.h +++ b/data_share/frameworks/native/provider/include/datashare_ext_ability.h @@ -18,6 +18,7 @@ #include #include "extension_base.h" +#include "datashare_business_error.h" #include "datashare_values_bucket.h" #include "datashare_predicates.h" #include "datashare_result_set.h" @@ -138,11 +139,12 @@ public: * @param uri Indicates the path of data to query. * @param predicates Indicates filter criteria. You should define the processing logic when this parameter is null. * @param columns Indicates the columns to query. If this parameter is null, all columns are queried. + * @param businessError Indicates the error by query. * * @return Returns the query result. */ - virtual std::shared_ptr Query( - const Uri &uri, const DataSharePredicates &predicates, std::vector &columns); + virtual std::shared_ptr Query(const Uri &uri, const DataSharePredicates &predicates, + std::vector &columns, DatashareBusinessError &businessError); /** * @brief Obtains the MIME type matching the data specified by the URI of the Data ability. This method should be diff --git a/data_share/frameworks/native/provider/include/datashare_stub.h b/data_share/frameworks/native/provider/include/datashare_stub.h index a1c0597833b86b6ceb4aec4f1f318f9ae567621d..668e86d7e2eb4a1199506c4a53010f5526251be9 100644 --- a/data_share/frameworks/native/provider/include/datashare_stub.h +++ b/data_share/frameworks/native/provider/include/datashare_stub.h @@ -47,6 +47,7 @@ private: using RequestFuncType = int (DataShareStub::*)(MessageParcel &data, MessageParcel &reply); std::map stubFuncMap_; + static constexpr int VALUEBUCKET_MAX_COUNT = 3000; }; } // namespace DataShare } // namespace OHOS diff --git a/data_share/frameworks/native/provider/include/js_datashare_ext_ability.h b/data_share/frameworks/native/provider/include/js_datashare_ext_ability.h index 51de22dade934a608468a42cbbbbb829044aafaa..41a61e333d60743ddc2e2210c9030dcd4b2a2c5d 100644 --- a/data_share/frameworks/native/provider/include/js_datashare_ext_ability.h +++ b/data_share/frameworks/native/provider/include/js_datashare_ext_ability.h @@ -158,7 +158,7 @@ public: * @return Returns the query result. */ std::shared_ptr Query(const Uri &uri, const DataSharePredicates &predicates, - std::vector &columns) override; + std::vector &columns, DatashareBusinessError &businessError) override; /** * @brief Obtains the MIME type matching the data specified by the URI of the Data ability. This method should be diff --git a/data_share/frameworks/native/provider/src/datashare_ext_ability.cpp b/data_share/frameworks/native/provider/src/datashare_ext_ability.cpp index d4a51eb534672a82b82aa7b28f57972c0d241acd..66e6fafff0d9be6037f2c492a0b1913f54219295 100644 --- a/data_share/frameworks/native/provider/src/datashare_ext_ability.cpp +++ b/data_share/frameworks/native/provider/src/datashare_ext_ability.cpp @@ -95,7 +95,7 @@ int DataShareExtAbility::Delete(const Uri &uri, const DataSharePredicates &predi } std::shared_ptr DataShareExtAbility::Query(const Uri &uri, - const DataSharePredicates &predicates, std::vector &columns) + const DataSharePredicates &predicates, std::vector &columns, DatashareBusinessError &businessError) { return nullptr; } diff --git a/data_share/frameworks/native/provider/src/datashare_stub.cpp b/data_share/frameworks/native/provider/src/datashare_stub.cpp index 7b5682e082fc752a8f0cb83ae65f8e8fc21ef3f1..459ee9ec977302635dab866e3c953d15d3022ac3 100644 --- a/data_share/frameworks/native/provider/src/datashare_stub.cpp +++ b/data_share/frameworks/native/provider/src/datashare_stub.cpp @@ -20,6 +20,7 @@ #include "ipc_types.h" #include "ishared_result_set.h" #include "itypes_utils.h" +#include "unistd.h" namespace OHOS { namespace DataShare { @@ -114,8 +115,10 @@ ErrCode DataShareStub::CmdOpenFile(MessageParcel &data, MessageParcel &reply) } if (!reply.WriteFileDescriptor(fd)) { LOG_ERROR("fail to WriteFileDescriptor fd"); + close(fd); return ERR_INVALID_VALUE; } + close(fd); return DATA_SHARE_NO_ERROR; } @@ -277,8 +280,12 @@ ErrCode DataShareStub::CmdBatchInsert(MessageParcel &data, MessageParcel &reply) LOG_ERROR("fail to ReadInt32 index"); return ERR_INVALID_VALUE; } + if (count > VALUEBUCKET_MAX_COUNT) { + return ERR_INVALID_VALUE; + } std::vector values; + values.reserve(static_cast(count)); for (int i = 0; i < count; i++) { DataShareValuesBucket value; if (!ITypesUtils::Unmarshalling(data, value)) { diff --git a/data_share/frameworks/native/provider/src/datashare_stub_impl.cpp b/data_share/frameworks/native/provider/src/datashare_stub_impl.cpp index 106faf0c28d137371579091b9352a64263b7c2c6..811ce0ba12f94c336e86aa7c1d88844759ca2e91 100644 --- a/data_share/frameworks/native/provider/src/datashare_stub_impl.cpp +++ b/data_share/frameworks/native/provider/src/datashare_stub_impl.cpp @@ -130,6 +130,7 @@ int DataShareStubImpl::Insert(const Uri &uri, const DataShareValuesBucket &value extension->GetResult(ret); return (ret != DEFAULT_NUMBER); }; + std::lock_guard lock(mutex_); uvQueue_->SyncCall(syncTaskFunc, getRetFunc); return ret; } @@ -164,6 +165,7 @@ int DataShareStubImpl::Update(const Uri &uri, const DataSharePredicates &predica extension->GetResult(ret); return (ret != DEFAULT_NUMBER); }; + std::lock_guard lock(mutex_); uvQueue_->SyncCall(syncTaskFunc, getRetFunc); return ret; } @@ -197,6 +199,7 @@ int DataShareStubImpl::Delete(const Uri &uri, const DataSharePredicates &predica extension->GetResult(ret); return (ret != DEFAULT_NUMBER); }; + std::lock_guard lock(mutex_); uvQueue_->SyncCall(syncTaskFunc, getRetFunc); return ret; } @@ -218,8 +221,8 @@ std::shared_ptr DataShareStubImpl::Query(const Uri &uri, return resultSet; } - std::function syncTaskFunc = [=, &columns, &resultSet, &extension]() { - resultSet = extension->Query(uri, predicates, columns); + std::function syncTaskFunc = [=, &columns, &resultSet, &businessError, &extension]() { + resultSet = extension->Query(uri, predicates, columns, businessError); }; std::function getRetFunc = [=, &resultSet, &businessError, client = sptr(this)]() -> bool { @@ -288,6 +291,7 @@ int DataShareStubImpl::BatchInsert(const Uri &uri, const std::vectorGetResult(ret); return (ret != DEFAULT_NUMBER); }; + std::lock_guard lock(mutex_); uvQueue_->SyncCall(syncTaskFunc, getRetFunc); return ret; } diff --git a/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp b/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp index 71374a5e3cfa3bbf0790b0c17137ef09eefc96de..579620c65831f78bda1a95b1e93150da1fd96a8c 100644 --- a/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp +++ b/data_share/frameworks/native/provider/src/datashare_uv_queue.cpp @@ -91,7 +91,7 @@ void DataShareUvQueue::Purge(uv_work_t* work) LOG_ERROR("invalid work"); return; } - if(work->data == nullptr) { + if (work->data == nullptr) { LOG_ERROR("invalid work->data"); delete work; return; diff --git a/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp b/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp index c7bd388dffe8c79764a0f076ebcb6e429261887f..2c6c5072e5955bc9d7c0a4a634f88a254f3bef92 100644 --- a/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp +++ b/data_share/frameworks/native/provider/src/js_datashare_ext_ability.cpp @@ -71,7 +71,8 @@ void JsDataShareExtAbility::Init(const std::shared_ptr &reco HandleScope handleScope(jsRuntime_); auto& engine = jsRuntime_.GetNativeEngine(); - jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath); + jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath, + abilityInfo_->compileMode == CompileMode::ES_MODULE); if (jsObj_ == nullptr) { LOG_ERROR("Failed to get jsObj_"); return; @@ -103,9 +104,7 @@ void JsDataShareExtAbility::Init(const std::shared_ptr &reco LOG_ERROR("Failed to get datashare extension ability native object"); return; } - LOG_INFO("Set datashare extension ability context pointer is nullptr: %{public}d", context.get() == nullptr); - nativeObj->SetNativePointer(new std::weak_ptr(context), [](NativeEngine*, void* data, void*) { LOG_INFO("Finalizer for weak_ptr datashare extension ability context is called"); @@ -236,7 +235,11 @@ NativeValue* JsDataShareExtAbility::CallObjectMethod(const char* name, NativeVal } size_t count = argc + 1; - NativeValue **args = new NativeValue *[count]; + NativeValue **args = new (std::nothrow) NativeValue *[count]; + if (args == nullptr) { + LOG_ERROR("JsDataShareExtAbility::CallObjectMethod new NativeValue error."); + return nullptr; + } for (size_t i = 0; i < argc; i++) { args[i] = argv[i]; } @@ -485,10 +488,10 @@ int JsDataShareExtAbility::Delete(const Uri &uri, const DataSharePredicates &pre } std::shared_ptr JsDataShareExtAbility::Query(const Uri &uri, - const DataSharePredicates &predicates, std::vector &columns) + const DataSharePredicates &predicates, std::vector &columns, DatashareBusinessError &businessError) { std::shared_ptr ret; - ret = DataShareExtAbility::Query(uri, predicates, columns); + ret = DataShareExtAbility::Query(uri, predicates, columns, businessError); HandleScope handleScope(jsRuntime_); napi_env env = reinterpret_cast(&jsRuntime_.GetNativeEngine()); diff --git a/data_share/frameworks/native/provider/src/js_datashare_ext_ability_context.cpp b/data_share/frameworks/native/provider/src/js_datashare_ext_ability_context.cpp index aaf10bbde11300a9acba1988d038d99e81c977ee..96c367f3b22fe70d8447f83d7dfdf9806bdb983a 100644 --- a/data_share/frameworks/native/provider/src/js_datashare_ext_ability_context.cpp +++ b/data_share/frameworks/native/provider/src/js_datashare_ext_ability_context.cpp @@ -60,4 +60,4 @@ NativeValue* CreateJsDataShareExtAbilityContext(NativeEngine& engine, return objValue; } } // namespace DataShare -} // namespace OHOS +} // namespace OHOS \ No newline at end of file diff --git a/data_share/frameworks/native/proxy/include/data_share_manager_impl.h b/data_share/frameworks/native/proxy/include/data_share_manager_impl.h index 9ab3b44cca90bdaf8af6cd09f8a2ecfb5bf4f265..6a1d35368c43432742ff3e1a4d4c204d7db348d4 100644 --- a/data_share/frameworks/native/proxy/include/data_share_manager_impl.h +++ b/data_share/frameworks/native/proxy/include/data_share_manager_impl.h @@ -37,8 +37,7 @@ public: virtual ~DataShareManagerImpl(); void OnRemoteDied(); std::shared_ptr GetDataShareProxy() override; - bool ConnectDataShare(const Uri &uri, const sptr token) override; - bool IsConnected() override; + bool ConnectDataShare(const Uri &uri, const sptr &token) override; class ServiceDeathRecipient : public IRemoteObject::DeathRecipient { public: diff --git a/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp b/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp index e27ec5496de730f47f905c760ccad934dbbbc87c..d545fd29583660ef089e6b4475183213f94bdf36 100644 --- a/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp +++ b/data_share/frameworks/native/proxy/src/data_share_manager_impl.cpp @@ -53,6 +53,10 @@ void DataShareManagerImpl::LinkToDeath(const sptr remote) { sptr deathRecipient = new (std::nothrow) DataShareManagerImpl::ServiceDeathRecipient(this); + if (deathRecipient == nullptr) { + LOG_ERROR("DataShareManagerImpl::LinkToDeath new ServiceDeathRecipient error."); + return; + } if (!remote->AddDeathRecipient(deathRecipient)) { LOG_ERROR("add death recipient failed"); } @@ -103,7 +107,7 @@ DataShareManagerImpl::~DataShareManagerImpl() LOG_INFO("destroy"); } -bool DataShareManagerImpl::ConnectDataShare(const Uri &uri, const sptr token) +bool DataShareManagerImpl::ConnectDataShare(const Uri &uri, const sptr &token) { if (dataShareService_ != nullptr) { return true; @@ -121,11 +125,6 @@ bool DataShareManagerImpl::ConnectDataShare(const Uri &uri, const sptr DataShareManagerImpl::GetDataShareProxy() { return dataShareService_; diff --git a/data_share/interfaces/inner_api/BUILD.gn b/data_share/interfaces/inner_api/BUILD.gn index b0074329cc43771c6f28d67c99f88d4bdbb82743..464a8ae321e65ef527e5235403a5ad2bff315434 100644 --- a/data_share/interfaces/inner_api/BUILD.gn +++ b/data_share/interfaces/inner_api/BUILD.gn @@ -76,8 +76,9 @@ ohos_shared_library("datashare_consumer") { "ability_runtime:app_context", "ability_runtime:dataobs_manager", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", - "ipc:ipc_core", + "ipc:ipc_single", "ipc_js:rpc", "napi:ace_napi", "samgr:samgr_proxy", @@ -117,8 +118,9 @@ ohos_shared_library("datashare_provider") { "ability_runtime:runtime", "access_token:libaccesstoken_sdk", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", - "ipc:ipc_core", + "ipc:ipc_single", "ipc_js:rpc", "napi:ace_napi", ] @@ -144,6 +146,7 @@ ohos_shared_library("datashare_ext_ability_module") { "ability_base:want", "ability_runtime:runtime", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", ] diff --git a/data_share/interfaces/inner_api/common/include/datashare_predicates.h b/data_share/interfaces/inner_api/common/include/datashare_predicates.h index 7b24e1a9295e2251fe696437c5d08f5c3fdced76..df8b5edac58c0c9a9ef24139949eb52fc99eb5cc 100644 --- a/data_share/interfaces/inner_api/common/include/datashare_predicates.h +++ b/data_share/interfaces/inner_api/common/include/datashare_predicates.h @@ -126,7 +126,7 @@ public: } /** - * @brief The LessThanOrEqualTo of the predicate. + * @brief The In of the predicate. * * @param field Indicates the target field. * @param value Indicates the queried value. diff --git a/data_share/interfaces/inner_api/consumer/include/datashare_result_set.h b/data_share/interfaces/inner_api/consumer/include/datashare_result_set.h index 69a8adeb93a4aa7e71b957fcebc017a84c11eb37..f4b29e48df5d0caee0980a4149d2ab08af631854 100644 --- a/data_share/interfaces/inner_api/consumer/include/datashare_result_set.h +++ b/data_share/interfaces/inner_api/consumer/include/datashare_result_set.h @@ -27,7 +27,7 @@ #include "message_parcel.h" #include "parcel.h" #include "result_set_bridge.h" -#include "shared_block.h" +#include "shared_blocker.h" namespace OHOS { namespace DataShare { @@ -135,7 +135,7 @@ public: /** * Obtains a block from the SharedResultSet. */ - AppDataFwk::SharedBlock *GetBlock() const override; + SharedBlock *GetBlock() const override; /** * Called when the position of the result set changes. @@ -145,12 +145,12 @@ public: /** * Adds the data of a SharedResultSet to a SharedBlock. */ - void FillBlock(int startRowIndex, AppDataFwk::SharedBlock *block) override; + void FillBlock(int startRowIndex, SharedBlock *block) override; /** * SetBlock. */ - virtual void SetBlock(AppDataFwk::SharedBlock *block); + virtual void SetBlock(SharedBlock *block); /** * Closes the result set, releasing all of its resources and making it completely invalid. @@ -179,7 +179,7 @@ private: // The actual position of the last row of data in the shareblock int endRowPos_ = -1; // The SharedBlock owned by this DataShareResultSet - AppDataFwk::SharedBlock *sharedBlock_ = nullptr; + SharedBlock *sharedBlock_ = nullptr; std::shared_ptr blockWriter_ = nullptr; std::shared_ptr bridge_ = nullptr; }; diff --git a/data_share/test/native/BUILD.gn b/data_share/test/native/BUILD.gn index 41b9a93703e19e6fff30398017a7401436c4d4d1..8c5ee15a76ff78cfe30a6e0909fc5f1b10127024 100644 --- a/data_share/test/native/BUILD.gn +++ b/data_share/test/native/BUILD.gn @@ -146,7 +146,7 @@ ohos_unittest("ErrorCodeTest") { "data_share:datashare_common", "data_share:datashare_consumer", "hilog_native:libhilog", - "ipc:ipc_core", + "ipc:ipc_single", "safwk:system_ability_fwk", "samgr:samgr_proxy", ] diff --git a/data_share/test/native/unittest/mediadatashare_test/src/mediadatashare_unit_test.cpp b/data_share/test/native/unittest/mediadatashare_test/src/mediadatashare_unit_test.cpp index ad447fde8e5e8f9b75be068a8043e276988b3dfa..223438515e08f266939ffc9d197ea800fca35e90 100644 --- a/data_share/test/native/unittest/mediadatashare_test/src/mediadatashare_unit_test.cpp +++ b/data_share/test/native/unittest/mediadatashare_test/src/mediadatashare_unit_test.cpp @@ -300,7 +300,7 @@ HWTEST_F(MediaDataShareUnitTest, MediaDataShare_Predicates_Test_006, TestSize.Le vector columns; Uri uri(MEDIALIBRARY_DATA_URI); auto resultSet = helper->Query(uri, predicates, columns); - int result = 0; + int result = -1; if (resultSet != nullptr) { resultSet->GetRowCount(result); } diff --git a/datamgr_service/conf/config.json b/datamgr_service/conf/config.json index 91ca003bbdfef4b4bd57c1f761faafd67e6c6e49..1b4ffabc12235e694b491ca6c4f33b5fa2674083 100644 --- a/datamgr_service/conf/config.json +++ b/datamgr_service/conf/config.json @@ -15,7 +15,7 @@ } }, { - "lib": "libconfigdemo2.z.so" + "lib": "libudmf_server.z.so" } ], "bundleChecker": { diff --git a/datamgr_service/services/distributeddataservice/adapter/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/BUILD.gn index 8f2232af1d99411ce4c7ab4a22f6c5a2ad6b9891..c1e309f1a58b5b3c4669f5fcb84baa069d8b45df 100644 --- a/datamgr_service/services/distributeddataservice/adapter/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/BUILD.gn @@ -20,10 +20,11 @@ config("distributeddata_adapter_private_config") { cflags = [ "-Wno-multichar" ] cflags_cc = [ "-fvisibility=hidden" ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } config("distributeddata_adapter_public_config") { - visibility = [ "//foundation/distributeddatamgr/datamgr_service:*" ] + visibility = [ ":*" ] include_dirs = [ "include/log", diff --git a/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn index bf53ea528fdf748fba97f0283d2e7260fd926976..11a205585e6477f465c39fe44434c7c911ab5f81 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/account/BUILD.gn @@ -59,4 +59,5 @@ ohos_static_library("distributeddata_account_static") { } subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn index f0540307dcbd2788774a2056eb9daa574955be95..fa8c3d6edc219124ea89d6af7383eaf84476a4bd 100644 --- a/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/account/test/BUILD.gn @@ -41,6 +41,7 @@ ohos_unittest("AccountDelegateTest") { "hiviewdfx_hilog_native:libhilog", "ipc:ipc_core", ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ############################################################################### diff --git a/datamgr_service/services/distributeddataservice/adapter/autils/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/autils/BUILD.gn index bb40ed87a5d68ce39d119e9aaec521b7e2403001..ad0f6ebe0e50c69b1f43435873f9963bcd51e0b8 100644 --- a/datamgr_service/services/distributeddataservice/adapter/autils/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/autils/BUILD.gn @@ -39,4 +39,5 @@ ohos_static_library("distributeddata_autils_static") { ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/autils/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/autils/test/BUILD.gn index 283d74b86d3c61332dd29429c7086f2827f2551c..afd7c605f06a0a922cca3a0f89de40e46883e680 100644 --- a/datamgr_service/services/distributeddataservice/adapter/autils/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/autils/test/BUILD.gn @@ -22,6 +22,7 @@ config("module_private_config") { "../../include/autils/", "//foundation/distributeddatamgr/kv_store/frameworks/common", ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ohos_unittest("KvStoreThreadPoolTest") { diff --git a/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn index 387aae137dcac07bd5d1169b30a2c8586bf6e3a4..78c9885b9e1a96950c9e2238d7d7c7eaabd78250 100644 --- a/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/broadcaster/BUILD.gn @@ -41,4 +41,5 @@ ohos_static_library("distributeddata_broadcaster_static") { ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn index 05670990c580fc1061610d352a111d6c6d8f2d7a..c3e9a4a7d4d045e294fff79e04f71e2c38df29aa 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/BUILD.gn @@ -63,4 +63,5 @@ ohos_static_library("distributeddata_communicator_static") { subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/data_buffer.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/data_buffer.cpp index 7f4060c89d6f03d21df4b4715dcf003cb42b0881..84d2f95a7314a7a84eb01ced8ae6b0eaca0c9049 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/data_buffer.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/data_buffer.cpp @@ -40,7 +40,7 @@ DataBuffer::~DataBuffer() bool DataBuffer::Init(size_t size) { - if (buf_ != nullptr) { + if (buf_ != nullptr || size == 0) { return false; } size_ = std::min(size, MAX_DATA_LEN); diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp b/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp index 5862e35dfb33cd014f8126839e54ce9acbd9a44f..d2cafb1f70bc0a7ee4cc59fb98ed64897627e36b 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/src/device_manager_adapter.cpp @@ -311,7 +311,7 @@ void DeviceManagerAdapter::SaveDeviceInfo(const DeviceInfo &dvInfo, const Device DeviceInfo DeviceManagerAdapter::GetLocalDevice() { std::lock_guard lock(devInfoMutex_); - if (!localInfo_.uuid.empty()) { + if (!localInfo_.uuid.empty() && !localInfo_.udid.empty()) { return localInfo_; } @@ -324,7 +324,7 @@ DeviceInfo DeviceManagerAdapter::GetLocalDevice() auto networkId = std::string(info.networkId); auto uuid = GetUuidByNetworkId(networkId); auto udid = GetUdidByNetworkId(networkId); - if (uuid.empty() || udid.empty()) { + if (uuid.empty()) { return {}; } ZLOGI("[LocalDevice] uuid:%{public}s, name:%{public}s, type:%{public}d", @@ -467,4 +467,18 @@ std::string DeviceManagerAdapter::ToNetworkID(const std::string &id) { return GetDeviceInfoFromCache(id).networkId; } + +std::string DeviceManagerAdapter::CalcClientUuid(const std::string &appId, const std::string &uuid) +{ + if (uuid.empty()) { + return ""; + } + std::string encryptedUuid; + auto ret = DeviceManager::GetInstance().GenerateEncryptedUuid(PKG_NAME, uuid, appId, encryptedUuid); + if (ret != DM_OK) { + ZLOGE("failed, result:%{public}d", ret); + return ""; + } + return encryptedUuid; +} } // namespace OHOS::DistributedData diff --git a/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn index 318f219206bb5514c5b59120910febd72617f74d..a3fa43ac1ad48518221acd752132beaee2811fdc 100644 --- a/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/communicator/test/BUILD.gn @@ -37,6 +37,7 @@ ohos_unittest("CommunicationProviderTest") { "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/communicator:distributeddata_communicator_static", "//third_party/googletest:gtest_main", ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ohos_unittest("DeviceManagerAdapterTest") { @@ -62,6 +63,7 @@ ohos_unittest("DeviceManagerAdapterTest") { "//foundation/distributedhardware/device_manager/interfaces/inner_kits/native_cpp:devicemanagersdk", "//third_party/googletest:gtest_main", ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ############################################################################### diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn index 97d2ebde61560fdbe4169fa92fa1e12b8fd53b6e..bbffd1ac0d1b610d74bb79ec32ddf1262c0ea6f2 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/BUILD.gn @@ -54,4 +54,5 @@ ohos_static_library("distributeddata_dfx_static") { ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn index 3ae42016400871f89577dc63ed7f74e4a5938fe2..0c2a6050e2ff40412796f1feadcbf24eb5d2a6de 100644 --- a/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/dfx/test/BUILD.gn @@ -52,6 +52,7 @@ ohos_unittest("DistributeddataDfxMSTTest") { "//third_party/googletest:gtest_main", "//third_party/openssl:libcrypto_shared", ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ############################################################################### @@ -109,6 +110,7 @@ ohos_unittest("DistributeddataDfxUTTest") { "//third_party/googletest:gtest_main", "//third_party/openssl:libcrypto_shared", ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ############################################################################### diff --git a/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h b/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h index 0fc8a548848a8650b7f04a1c617ea941fa8d7caf..d4a72a197212def4a1e3a39c8c5d23870bcad6a9 100644 --- a/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h +++ b/datamgr_service/services/distributeddataservice/adapter/include/communicator/device_manager_adapter.h @@ -39,6 +39,7 @@ public: using AppDeviceChangeListener = OHOS::AppDistributedKv::AppDeviceChangeListener; using Status = OHOS::DistributedKv::Status; static DeviceManagerAdapter &GetInstance(); + void Init(); Status StartWatchDeviceChange(const AppDeviceChangeListener *observer, const PipeInfo &pipeInfo); Status StopWatchDeviceChange(const AppDeviceChangeListener *observer, const PipeInfo &pipeInfo); @@ -47,6 +48,7 @@ public: DeviceInfo GetDeviceInfo(const std::string &id); std::string GetUuidByNetworkId(const std::string &networkId); std::string GetUdidByNetworkId(const std::string &networkId); + std::string CalcClientUuid(const std::string &appId, const std::string &uuid); std::string ToUUID(const std::string &id); std::string ToUDID(const std::string &id); static std::vector ToUUID(const std::vector &devices); diff --git a/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn index c6f96a2a26c774efe3eb8b9baa45fb999324f415..9d63f4012bb12db9970b112c433bc0a770e312bc 100644 --- a/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/permission/BUILD.gn @@ -39,4 +39,5 @@ ohos_static_library("distributeddata_permission_static") { ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn index 0c85975857949bd32f76f42254cc53f70f598a70..a19f4c30fdd885df876c31c845aa60eb9a77ed61 100644 --- a/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/permission/test/BUILD.gn @@ -43,6 +43,7 @@ ohos_unittest("PermissionValidatorTest") { ] external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } group("unittest") { diff --git a/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn b/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn index cd85ee93a104f2e9706674414c9692263d4a7c33..6539b7ab9b80cf4471e0ef1138200118e1cae852 100644 --- a/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/adapter/utils/BUILD.gn @@ -39,4 +39,5 @@ ohos_static_library("distributeddata_utils_static") { ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/app/BUILD.gn b/datamgr_service/services/distributeddataservice/app/BUILD.gn index 3e962580716483315106e657518b752ad80687f4..48797a85e7d4abdc2b5eae980d587b64bdbd083c 100644 --- a/datamgr_service/services/distributeddataservice/app/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/BUILD.gn @@ -140,4 +140,5 @@ ohos_shared_library("distributeddataservice") { subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/app/distributed_data.cfg b/datamgr_service/services/distributeddataservice/app/distributed_data.cfg index 494bc79bf2a42f71ed981de3fae6f6cead270de6..a42d9dc441e2487fb04cb680903ae1817664aed7 100644 --- a/datamgr_service/services/distributeddataservice/app/distributed_data.cfg +++ b/datamgr_service/services/distributeddataservice/app/distributed_data.cfg @@ -30,7 +30,8 @@ "apl" : "system_basic", "permission" : [ "ohos.permission.DISTRIBUTED_DATASYNC", - "ohos.permission.MANAGE_LOCAL_ACCOUNTS" + "ohos.permission.MANAGE_LOCAL_ACCOUNTS", + "ohos.permission.ACCESS_SERVICE_DM" ] } ] diff --git a/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn index 6bf706d95da71caa6b0f016da027437aa0e1cc68..48afce56307e96b5467cd7a38bfd807855ade962 100644 --- a/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/checker/BUILD.gn @@ -46,4 +46,5 @@ ohos_static_library("distributeddata_checker_static") { ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn index cf921d03ed7e640eaaaca32fc2b3215b0b5d9ee4..c17ecd1ef9e25e12098d369c58f353ec09df5353 100644 --- a/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager/BUILD.gn @@ -31,4 +31,5 @@ ohos_static_library("distributeddata_flowctrl_static") { subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp b/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp index c9138c6573d3880450b758c02c67015ab4cfe65d..50bef791e6b7f4c3d6077b8aa712c9eedbf67216 100644 --- a/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/kvstore_data_service.cpp @@ -35,6 +35,7 @@ #include "iservice_registry.h" #include "kvstore_account_observer.h" #include "log_print.h" +#include "metadata/appid_meta_data.h" #include "metadata/meta_data_manager.h" #include "metadata/secret_key_meta_data.h" #include "permission_validator.h" @@ -49,6 +50,7 @@ #include "user_delegate.h" #include "utils/block_integer.h" #include "utils/crypto.h" +#include "upgrade.h" namespace OHOS::DistributedKv { using namespace std::chrono; @@ -57,6 +59,7 @@ using namespace OHOS::DistributedDataDfx; using KvStoreDelegateManager = DistributedDB::KvStoreDelegateManager; using SecretKeyMeta = DistributedData::SecretKeyMetaData; using DmAdapter = DistributedData::DeviceManagerAdapter; +using DBConfig = DistributedDB::RuntimeConfig; REGISTER_SYSTEM_ABILITY_BY_ID(KvStoreDataService, DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID, true); @@ -97,6 +100,18 @@ void KvStoreDataService::Initialize() AccountDelegate::GetInstance()->Subscribe(accountEventObserver_); deviceInnerListener_ = std::make_unique(*this); DmAdapter::GetInstance().StartWatchDeviceChange(deviceInnerListener_.get(), { "innerListener" }); + auto translateCall = [](const std::string &oriDevId, const DistributedDB::StoreInfo &info) { + StoreMetaData meta; + AppIDMetaData appIdMeta; + MetaDataManager::GetInstance().LoadMeta(info.appId, appIdMeta, true); + meta.bundleName = appIdMeta.bundleName; + meta.storeId = info.storeId; + meta.user = info.userId; + meta.deviceId = oriDevId; + MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), meta); + return Upgrade::GetInstance().GetEncryptedUuidByMeta(meta); + }; + DBConfig::SetTranslateToDeviceIdCallback(translateCall); } sptr KvStoreDataService::GetFeatureInterface(const std::string &name) diff --git a/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.cpp b/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.cpp index 6550e72a49f5261bfe7baecdd79716ccb4adaca9..c3a77e4300aadb8c78a21b9d7814eb4b8ef1fd17 100644 --- a/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.cpp @@ -51,8 +51,9 @@ void UpgradeManager::Init() CapMetaData UpgradeManager::GetCapability(const std::string &deviceId, bool &status) { status = true; - if (capabilityMap_.Contains(deviceId)) { - return capabilityMap_.Find(deviceId).second; + auto cap = capabilities_.Find(deviceId); + if (cap.first) { + return cap.second; } ZLOGI("load capability from meta"); CapMetaData capMetaData; @@ -60,7 +61,7 @@ CapMetaData UpgradeManager::GetCapability(const std::string &deviceId, bool &sta ZLOGD("cap key:%{public}s", Anonymous::Change(std::string(dbKey.begin(), dbKey.end())).c_str()); status = MetaDataManager::GetInstance().LoadMeta(std::string(dbKey.begin(), dbKey.end()), capMetaData); if (status) { - capabilityMap_.Insert(deviceId, capMetaData); + capabilities_.Insert(deviceId, capMetaData); } ZLOGI("device:%{public}s, version:%{public}d, insert:%{public}d", Anonymous::Change(deviceId).c_str(), capMetaData.version, status); @@ -75,7 +76,7 @@ bool UpgradeManager::InitLocalCapability() auto dbKey = CapMetaRow::GetKeyFor(localDeviceId); bool status = MetaDataManager::GetInstance().SaveMeta({ dbKey.begin(), dbKey.end() }, capMetaData); if (status) { - capabilityMap_.Insert(localDeviceId, capMetaData); + capabilities_.Insert(localDeviceId, capMetaData); } ZLOGI("put capability meta data ret %{public}d", status); return status; diff --git a/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.h b/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.h index 533aea257cc6c2277a1b887bb4e653f99c4df3e9..6bb07ea2e3df26064914867d62378d9203ae259f 100644 --- a/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.h +++ b/datamgr_service/services/distributeddataservice/app/src/session_manager/upgrade_manager.h @@ -37,7 +37,7 @@ public: private: bool InitLocalCapability(); - ConcurrentMap capabilityMap_ {}; + ConcurrentMap capabilities_ {}; }; } // namespace OHOS::DistributedData #endif // DISTRIBUTEDDATAMGR_UPGRADE_MANAGER_H diff --git a/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn b/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn index 030cda89a76abec363b9e40757d5e86b7cc49a00..85a133f20f9a5a038ee248b6bdb18733f329e40c 100644 --- a/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/src/uninstaller/BUILD.gn @@ -56,4 +56,5 @@ ohos_static_library("distributeddata_uninstaller_static") { ] subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/app/src/uninstaller/uninstaller_impl.cpp b/datamgr_service/services/distributeddataservice/app/src/uninstaller/uninstaller_impl.cpp index 2ab4cb2246dcb50413469aeaebe92c6a4a41c9e5..36f24cafb6eef21e923a9e8083f4a6c8d82759bb 100644 --- a/datamgr_service/services/distributeddataservice/app/src/uninstaller/uninstaller_impl.cpp +++ b/datamgr_service/services/distributeddataservice/app/src/uninstaller/uninstaller_impl.cpp @@ -18,6 +18,7 @@ #include "uninstaller_impl.h" #include #include +#include "bundle_common_event.h" #include "common_event_manager.h" #include "common_event_support.h" #include "device_manager_adapter.h" @@ -46,7 +47,7 @@ void UninstallEventSubscriber::OnReceiveEvent(const CommonEventData &event) Want want = event.GetWant(); std::string action = want.GetAction(); if (action != CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED && - action != CommonEventSupport::COMMON_EVENT_SANDBOX_PACKAGE_REMOVED) { + action != OHOS::AppExecFwk::COMMON_EVENT_SANDBOX_PACKAGE_REMOVED) { return; } @@ -82,7 +83,7 @@ Status UninstallerImpl::Init(KvStoreDataService *kvStoreDataService) } MatchingSkills matchingSkills; matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); - matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_SANDBOX_PACKAGE_REMOVED); + matchingSkills.AddEvent(OHOS::AppExecFwk::COMMON_EVENT_SANDBOX_PACKAGE_REMOVED); CommonEventSubscribeInfo info(matchingSkills); auto callback = [kvStoreDataService](const std::string &bundleName, int32_t userId, int32_t appIndex) { kvStoreDataService->OnUninstall(bundleName, userId, appIndex, IPCSkeleton::GetCallingTokenID()); diff --git a/datamgr_service/services/distributeddataservice/app/test/BUILD.gn b/datamgr_service/services/distributeddataservice/app/test/BUILD.gn index d081b35ac99da79979be0f5984db1bb35998a4ba..628ff74138cc07fd6dce1c4a031fc4ce64a5b6d5 100644 --- a/datamgr_service/services/distributeddataservice/app/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/app/test/BUILD.gn @@ -58,6 +58,7 @@ config("module_private_config") { [ "//base/powermgr/power_manager/interfaces/innerkits/native/include" ] } ldflags = [ "-Wl,--whole-archive" ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ohos_unittest("KvStoreDataServiceTest") { @@ -198,64 +199,6 @@ ohos_unittest("KvStoreFlowCtrlManagerTest") { part_name = "datamgr_service" } -ohos_unittest("KvStoreUninstallerTest") { - module_out_path = module_output_path - sources = [ - "../src/dump_helper.cpp", - "../src/feature_stub_impl.cpp", - "../src/kvstore_account_observer.cpp", - "../src/kvstore_data_service.cpp", - "../src/kvstore_device_listener.cpp", - "../src/kvstore_meta_manager.cpp", - "../src/security/security.cpp", - "../src/security/sensitive.cpp", - "../src/session_manager/route_head_handler_impl.cpp", - "../src/session_manager/session_manager.cpp", - "../src/session_manager/upgrade_manager.cpp", - "unittest/uninstaller_test.cpp", - ] - - configs = [ ":module_private_config" ] - - deps = [ - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter:distributeddata_adapter", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/broadcaster:distributeddata_broadcaster_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/adapter/utils:distributeddata_utils_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/app/src/checker:distributeddata_checker_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/app/src/flowctrl_manager:distributeddata_flowctrl_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/app/src/uninstaller:distributeddata_uninstaller_static", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/framework:distributeddatasvcfwk", - "//foundation/distributeddatamgr/datamgr_service/services/distributeddataservice/service:distributeddatasvc", - "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb:distributeddb", - "//foundation/distributeddatamgr/kv_store/interfaces/innerkits/distributeddata:distributeddata_inner", - "//third_party/googletest:gtest_main", - ] - - external_deps = [ - "ability_base:base", - "ability_base:want", - "access_token:libaccesstoken_sdk", - "c_utils:utils", - "dataclassification:data_transit_mgr", - "device_auth:deviceauth_sdk", - "hisysevent_native:libhisysevent", - "hitrace_native:hitrace_meter", - "hitrace_native:libhitracechain", - "hiviewdfx_hilog_native:libhilog", - "ipc:ipc_core", - "safwk:system_ability_fwk", - "samgr:samgr_proxy", - ] - - if (datamgr_service_power) { - external_deps += [ - "battery_manager:batterysrv_client", - "power_manager:powermgr_client", - ] - } - part_name = "datamgr_service" -} - ############################################################################### group("unittest") { @@ -265,7 +208,6 @@ group("unittest") { deps += [ ":KvStoreDataServiceTest", ":KvStoreFlowCtrlManagerTest", - ":KvStoreUninstallerTest", ":SessionManagerTest", ] } diff --git a/datamgr_service/services/distributeddataservice/app/test/unittest/session_manager_test.cpp b/datamgr_service/services/distributeddataservice/app/test/unittest/session_manager_test.cpp index 32c003019142b3797fbd3c4468befaf872d27591..0945544aa81eab3a34dc79712106d313f2878008 100644 --- a/datamgr_service/services/distributeddataservice/app/test/unittest/session_manager_test.cpp +++ b/datamgr_service/services/distributeddataservice/app/test/unittest/session_manager_test.cpp @@ -121,7 +121,7 @@ HWTEST_F(SessionManagerTest, PackAndUnPack01, TestSize.Level2) std::vector users; auto recvHandler = RouteHeadHandlerImpl::Create({}); ASSERT_NE(recvHandler, nullptr); - uint32_t parseSize = 0; + uint32_t parseSize = 1; recvHandler->ParseHeadData(data.get(), routeHeadSize, parseSize, users); EXPECT_EQ(routeHeadSize, parseSize); ASSERT_EQ(users.size(), 1); diff --git a/datamgr_service/services/distributeddataservice/framework/BUILD.gn b/datamgr_service/services/distributeddataservice/framework/BUILD.gn index 20b957baabe16544b0e4b6df21080de8ee297d08..ea3b510f8a0605c2367548137262c3e174b3d171 100644 --- a/datamgr_service/services/distributeddataservice/framework/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/framework/BUILD.gn @@ -34,6 +34,12 @@ ohos_shared_library("distributeddatasvcfwk") { sources = [ "backuprule/backup_rule_manager.cpp", "checker/checker_manager.cpp", + "cloud/asset_loader.cpp", + "cloud/cloud_db.cpp", + "cloud/cloud_event.cpp", + "cloud/cloud_info.cpp", + "cloud/cloud_server.cpp", + "cloud/schema_meta.cpp", "eventcenter/event.cpp", "eventcenter/event_center.cpp", "feature/feature_system.cpp", @@ -50,6 +56,7 @@ ohos_shared_library("distributeddatasvcfwk") { "metadata/strategy_meta_data.cpp", "metadata/user_meta_data.cpp", "serializable/serializable.cpp", + "store/auto_cache.cpp", "utils/anonymous.cpp", "utils/block_integer.cpp", "utils/constant.cpp", @@ -68,4 +75,5 @@ ohos_shared_library("distributeddatasvcfwk") { subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt b/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt index 85c38e69be5bce14bed9bf115e3fe8595b3e7fce..3c76dea5bb0edfe739b182bb15bbfa6b2b9e8bb1 100644 --- a/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt +++ b/datamgr_service/services/distributeddataservice/framework/CMakeLists.txt @@ -12,10 +12,12 @@ set(MOCK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../mock") set(KV_STORE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../kv_store") aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/backuprule svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/checker svcFwkSrc) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/metadata svcFwkSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/cloud svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/eventcenter svcFwkSrc) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/serializable svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/feature svcFwkSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/metadata svcFwkSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/serializable svcFwkSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/store svcFwkSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/utils svcFwkSrc) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include) diff --git a/datamgr_service/services/distributeddataservice/framework/backuprule/backup_rule_manager.cpp b/datamgr_service/services/distributeddataservice/framework/backuprule/backup_rule_manager.cpp index 2fe059135ada0491a9815c2d12d9638cfca95434..d967ad2f158bbc04c26b186822a613ddd4b7973f 100644 --- a/datamgr_service/services/distributeddataservice/framework/backuprule/backup_rule_manager.cpp +++ b/datamgr_service/services/distributeddataservice/framework/backuprule/backup_rule_manager.cpp @@ -37,11 +37,9 @@ void BackupRuleManager::LoadBackupRules(const std::vector &backupRu void BackupRuleManager::RegisterPlugin(const std::string &backupRule, std::function getter) { - auto it = getters_.Find(backupRule); - if (it.first) { - return; - } - getters_[backupRule] = getter; + getters_.ComputeIfAbsent(backupRule, [&getter](const auto &) mutable { + return std::move(getter); + }); } bool BackupRuleManager::CanBackup() diff --git a/datamgr_service/services/distributeddataservice/framework/checker/checker_manager.cpp b/datamgr_service/services/distributeddataservice/framework/checker/checker_manager.cpp index b7213f3c229c99b10612b7946d77dd47aa8ee94f..8dbc1bb39650f35574872abef279e293cf6a9e91 100644 --- a/datamgr_service/services/distributeddataservice/framework/checker/checker_manager.cpp +++ b/datamgr_service/services/distributeddataservice/framework/checker/checker_manager.cpp @@ -42,11 +42,9 @@ void CheckerManager::LoadCheckers(std::vector &checkers) void CheckerManager::RegisterPlugin(const std::string &checker, std::function getter) { - auto it = getters_.Find(checker); - if (it.first) { - return; - } - getters_[checker] = getter; + getters_.ComputeIfAbsent(checker, [&getter](const auto &) mutable { + return std::move(getter); + }); } std::string CheckerManager::GetAppId(const StoreInfo &info) diff --git a/relational_store/frameworks/native/rdb/src/rdb_manager.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/asset_loader.cpp similarity index 64% rename from relational_store/frameworks/native/rdb/src/rdb_manager.cpp rename to datamgr_service/services/distributeddataservice/framework/cloud/asset_loader.cpp index 76bddfc3e5ad5be2be08b70fd5494be98d97f2e4..cef89e7db8642219fb9793838a9f64c1eb574e78 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_manager.cpp +++ b/datamgr_service/services/distributeddataservice/framework/cloud/asset_loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * 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 @@ -13,12 +13,15 @@ * limitations under the License. */ -#include "rdb_manager.h" -#include "rdb_manager_impl.h" +#include "cloud/asset_loader.h" +namespace OHOS::DistributedData { +int32_t AssetLoader::Upload(const std::vector &assets) +{ + return E_NOT_SUPPORT; +} -namespace OHOS::DistributedRdb { -std::shared_ptr RdbManager::GetRdbService(const RdbSyncerParam& param) +int32_t AssetLoader::Download(std::vector &assets) { - return RdbManagerImpl::GetInstance().GetRdbService(param); + return E_NOT_SUPPORT; +} } -} // namespace OHOS::DistributedRdb diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_db.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_db.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ea4d041d2f2f5277dd4d4adf9905b6a036a0a928 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_db.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "cloud/cloud_db.h" +namespace OHOS::DistributedData { +int32_t CloudDB::Close() +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::Execute(const std::string &table, const std::string &sql) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::BatchInsert(const std::string &table, VBuckets &&values) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::BatchUpdate(const std::string &table, const std::string &sql, VBuckets &&values) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::Delete(const std::string &table, const std::string &sql, Values &&args) +{ + return E_NOT_SUPPORT; +} + +std::shared_ptr CloudDB::Query(const std::string &table, const std::string &sql, Values &&args) +{ + return nullptr; +} + +std::shared_ptr CloudDB::Query(const std::string &table, const GenQuery &query) +{ + return nullptr; +} + +int32_t CloudDB::Sync(const Devices &devices, int32_t mode, const GenQuery &query, Async async, int32_t wait) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::Watch(int32_t origin, Watcher &watcher) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::Unwatch(int32_t origin, Watcher &watcher) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::Execute(const std::string &table, const std::string &sql, const VBucket &extend) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::BatchInsert(const std::string &table, VBuckets &&values, VBuckets &extends) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::BatchUpdate(const std::string &table, VBuckets &&values, const VBuckets &extends) +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::BatchDelete(const std::string &table, const VBuckets &extends) +{ + return E_NOT_SUPPORT; +} + +std::shared_ptr CloudDB::Query(const std::string &table, const VBucket &extend) +{ + return nullptr; +} + +int32_t CloudDB::Lock() +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::Heartbeat() +{ + return E_NOT_SUPPORT; +} + +int32_t CloudDB::Unlock() +{ + return E_NOT_SUPPORT; +} +} // namespace OHOS::DistributedData diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_event.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_event.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0212fcc73edc89a35441af7eb30264369c2ea78e --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_event.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "cloud/cloud_event.h" + +namespace OHOS::DistributedData { +CloudEvent::CloudEvent(int32_t evtId, uint32_t tokenId, const std::string &storeName, const std::string &bundleName, + const std::string &featureName, const std::string &schemaKey) + : Event(evtId), featureName_(featureName), tokenId_(tokenId), storeName_(storeName), bundleName_(bundleName), + schemaKey_(schemaKey) +{ +} +CloudEvent::CloudEvent(int32_t evtId, const CloudEvent &cloudEvent) + : Event(evtId), featureName_(cloudEvent.GetFeatureName()), tokenId_(cloudEvent.GetTokenId()), + storeName_(cloudEvent.GetStoreName()), bundleName_(cloudEvent.GetBundleName()) +{ +} + +std::string CloudEvent::GetFeatureName() const +{ + return featureName_; +} + +void CloudEvent::SetSchemaKey(std::string schemaKey) +{ + schemaKey_ = schemaKey; +} + +std::string CloudEvent::GetSchemaKey() const +{ + return schemaKey_; +} + +std::string CloudEvent::GetBundleName() const +{ + return bundleName_; +} + +std::string CloudEvent::GetStoreName() const +{ + return storeName_; +} + +bool CloudEvent::Equals(const Event &event) const +{ + return false; +} + +uint32_t CloudEvent::GetTokenId() const +{ + return tokenId_; +} +} \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_info.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3f141ebf041cbf67732bc3eae3692aa6bfa6d01 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_info.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "cloud/cloud_info.h" +#include "utils/constant.h" + +namespace OHOS::DistributedData { +bool CloudInfo::Marshal(Serializable::json &node) const +{ + SetValue(node[GET_NAME(user)], user); + SetValue(node[GET_NAME(id)], id); + SetValue(node[GET_NAME(totalSpace)], totalSpace); + SetValue(node[GET_NAME(remainSpace)], remainSpace); + SetValue(node[GET_NAME(enableCloud)], enableCloud); + SetValue(node[GET_NAME(apps)], apps); + return true; +} + +bool CloudInfo::Unmarshal(const Serializable::json &node) +{ + GetValue(node, GET_NAME(user), user); + GetValue(node, GET_NAME(id), id); + GetValue(node, GET_NAME(totalSpace), totalSpace); + GetValue(node, GET_NAME(remainSpace), remainSpace); + GetValue(node, GET_NAME(enableCloud), enableCloud); + GetValue(node, GET_NAME(apps), apps); + return true; +} + +bool CloudInfo::AppInfo::Marshal(Serializable::json &node) const +{ + SetValue(node[GET_NAME(bundleName)], bundleName); + SetValue(node[GET_NAME(appId)], appId); + SetValue(node[GET_NAME(version)], version); + SetValue(node[GET_NAME(cloudSwitch)], cloudSwitch); + return true; +} + +bool CloudInfo::AppInfo::Unmarshal(const Serializable::json &node) +{ + GetValue(node, GET_NAME(bundleName), bundleName); + GetValue(node, GET_NAME(appId), appId); + GetValue(node, GET_NAME(version), version); + GetValue(node, GET_NAME(cloudSwitch), cloudSwitch); + return true; +} + +std::string CloudInfo::GetKey() const +{ + return GetKey(INFO_PREFIX, { std::to_string(user), id }); +} + +std::map CloudInfo::GetSchemaKey() const +{ + std::map keys; + for (const auto &app : apps) { + const auto key = GetKey(SCHEMA_PREFIX, { std::to_string(user), id, app.bundleName }); + keys.insert_or_assign(app.bundleName, key); + } + return keys; +} + +std::string CloudInfo::GetSchemaKey(std::string bundleName) const +{ + return GetKey(SCHEMA_PREFIX, { std::to_string(user), id, bundleName }); +} + +bool CloudInfo::IsValid() const +{ + return !id.empty(); +} + +bool CloudInfo::IsExist(const std::string &bundleName) const +{ + for (const auto &app : apps) { + if (app.bundleName == bundleName) { + return true; + } + } + return false; +} + +std::string CloudInfo::GetPrefix(const std::initializer_list &fields) +{ + return GetKey(INFO_PREFIX, fields).append(Constant::KEY_SEPARATOR); +} + +std::string CloudInfo::GetKey(const std::string &prefix, const std::initializer_list &fields) +{ + return Constant::Join(prefix, Constant::KEY_SEPARATOR, fields); +} +} // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/cloud_server.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2e0f7164cc131142c04e71d11a601d7156c3760 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/cloud/cloud_server.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "cloud/cloud_server.h" +namespace OHOS::DistributedData { +CloudServer *CloudServer::instance_ = nullptr; +CloudServer *CloudServer::GetInstance() +{ + return instance_; +} + +bool CloudServer::RegisterCloudInstance(CloudServer *instance) +{ + if (instance_ != nullptr) { + return false; + } + instance_ = instance; + return true; +} + +CloudInfo CloudServer::GetServerInfo(int32_t userId) +{ + return CloudInfo(); +} + +SchemaMeta CloudServer::GetAppSchema(int32_t userId, const std::string &bundleName) +{ + return SchemaMeta(); +} + +std::shared_ptr CloudServer::ConnectAssetLoader(uint32_t tokenId, const CloudServer::Database &dbMeta) +{ + return nullptr; +} + +std::shared_ptr CloudServer::ConnectCloudDB(uint32_t tokenId, const CloudServer::Database &dbMeta) +{ + return nullptr; +} +} // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/cloud/schema_meta.cpp b/datamgr_service/services/distributeddataservice/framework/cloud/schema_meta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b6a8cd4b35ecd9d701651340a40aea9b698e867d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/cloud/schema_meta.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "cloud/schema_meta.h" +namespace OHOS::DistributedData { +bool SchemaMeta::Marshal(Serializable::json &node) const +{ + SetValue(node[GET_NAME(version)], version); + SetValue(node[GET_NAME(databases)], databases); + return true; +} + +bool SchemaMeta::Unmarshal(const Serializable::json &node) +{ + GetValue(node, GET_NAME(version), version); + GetValue(node, GET_NAME(databases), databases); + return true; +} + +bool SchemaMeta::Database::Marshal(Serializable::json &node) const +{ + SetValue(node[GET_NAME(name)], name); + SetValue(node[GET_NAME(alias)], alias); + SetValue(node[GET_NAME(tables)], tables); + return true; +} + +bool SchemaMeta::Database::Unmarshal(const Serializable::json &node) +{ + GetValue(node, GET_NAME(name), name); + GetValue(node, GET_NAME(alias), alias); + GetValue(node, GET_NAME(tables), tables); + return true; +} + +bool SchemaMeta::Table::Marshal(Serializable::json &node) const +{ + SetValue(node[GET_NAME(name)], name); + SetValue(node[GET_NAME(alias)], alias); + SetValue(node[GET_NAME(fields)], fields); + return true; +} + +bool SchemaMeta::Table::Unmarshal(const Serializable::json &node) +{ + GetValue(node, GET_NAME(name), name); + GetValue(node, GET_NAME(alias), alias); + GetValue(node, GET_NAME(fields), fields); + return true; +} + +bool SchemaMeta::Field::Marshal(Serializable::json &node) const +{ + SetValue(node[GET_NAME(colName)], colName); + SetValue(node[GET_NAME(alias)], alias); + SetValue(node[GET_NAME(type)], type); + SetValue(node[GET_NAME(primary)], primary); + SetValue(node[GET_NAME(nullable)], nullable); + return true; +} + +bool SchemaMeta::Field::Unmarshal(const Serializable::json &node) +{ + GetValue(node, GET_NAME(colName), colName); + GetValue(node, GET_NAME(alias), alias); + GetValue(node, GET_NAME(type), type); + GetValue(node, GET_NAME(primary), primary); + GetValue(node, GET_NAME(nullable), nullable); + return true; +} + +SchemaMeta::Database SchemaMeta::GetDataBase(const std::string &storeId) +{ + for (const auto &database : databases) { + if (database.name == storeId) { + return database; + } + } + return {}; +} +} // namespace OHOS::DistributedData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/asset_loader.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/asset_loader.h new file mode 100644 index 0000000000000000000000000000000000000000..0df69eb0a415c5bdb72de379d5658e3c04e75289 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/asset_loader.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_ASSET_LOADER_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_ASSET_LOADER_H +#include +#include "store/general_value.h" +#include "visibility.h" +namespace OHOS::DistributedData { +class API_EXPORT AssetLoader { +public: + virtual ~AssetLoader() = default; + virtual int32_t Upload(const std::vector &assets); + virtual int32_t Download(std::vector &assets); +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_ASSET_LOADER_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_db.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_db.h new file mode 100644 index 0000000000000000000000000000000000000000..9b67c9a4be455f81e56d4cbbed8cd44755c017b9 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_db.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_DB_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_DB_H +#include "store/general_store.h" +#include "visibility.h" +namespace OHOS::DistributedData { +class API_EXPORT CloudDB : public GeneralStore { +public: + int32_t Close() override; + int32_t Execute(const std::string &table, const std::string &sql) override; + int32_t BatchInsert(const std::string &table, VBuckets &&values) override; + int32_t BatchUpdate(const std::string &table, const std::string &sql, VBuckets &&values) override; + int32_t Delete(const std::string &table, const std::string &sql, Values &&args) override; + std::shared_ptr Query(const std::string &table, const std::string &sql, Values &&args) override; + std::shared_ptr Query(const std::string &table, const GenQuery &query) override; + int32_t Sync(const Devices &devices, int32_t mode, const GenQuery &query, Async async, int32_t wait) override; + int32_t Watch(int32_t origin, Watcher &watcher) override; + int32_t Unwatch(int32_t origin, Watcher &watcher) override; + + virtual int32_t Execute(const std::string &table, const std::string &sql, const VBucket &extend); + + virtual int32_t BatchInsert(const std::string &table, VBuckets &&values, VBuckets &extends); + + virtual int32_t BatchUpdate(const std::string &table, VBuckets &&values, const VBuckets &extends); + + virtual int32_t BatchDelete(const std::string &table, const VBuckets &extends); + + virtual std::shared_ptr Query(const std::string &table, const VBucket &extend); + + virtual int32_t Lock(); + + virtual int32_t Heartbeat(); + + virtual int32_t Unlock(); +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_DB_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_event.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_event.h new file mode 100644 index 0000000000000000000000000000000000000000..469e50fc0b3f6a819a698b040e1f18136e44962d --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_event.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_EVENT_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_EVENT_H + +#include +#include "eventcenter/event.h" + +namespace OHOS::DistributedData { +class API_EXPORT CloudEvent : public Event { +public: + enum : int32_t { + FEATURE_INIT = EVT_CLOUD, + GET_SCHEMA, + NEED_CREATE, + CLOUD_BUTT + }; + + CloudEvent(int32_t evtId, uint32_t tokenId = 0, const std::string &storeName = "", + const std::string &bundleName = "", const std::string &featureName = "relational_store", + const std::string &schemaKey = ""); + CloudEvent(int32_t evtId, const CloudEvent &cloudEvent); + ~CloudEvent() = default; + std::string GetFeatureName() const; + void SetSchemaKey(std::string bundleName); + std::string GetSchemaKey() const; + std::string GetBundleName() const; + std::string GetStoreName() const; + uint32_t GetTokenId() const; + bool Equals(const DistributedData::Event &event) const override; + +private: + std::string featureName_; + uint32_t tokenId_; + std::string storeName_; + std::string bundleName_; + std::string schemaKey_; + +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_EVENT_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_info.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_info.h new file mode 100644 index 0000000000000000000000000000000000000000..5576bca8a4d6b433951e1c3ff6b3eb4000afd72b --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_info.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_INFO_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_INFO_H +#include "serializable/serializable.h" +namespace OHOS::DistributedData { +class API_EXPORT CloudInfo final : public Serializable { +public: + struct API_EXPORT AppInfo final : public Serializable { + std::string bundleName = ""; + std::string appId = ""; + uint64_t version = 0; + bool cloudSwitch = false; + + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + }; + int32_t user = 0; + std::string id = ""; + uint64_t totalSpace = 0; + uint64_t remainSpace = 0; + bool enableCloud = false; + std::vector apps; + + std::string GetKey() const; + std::map GetSchemaKey() const; + std::string GetSchemaKey(std::string bundleName) const; + bool IsValid() const; + bool IsExist(const std::string &bundleName) const; + static std::string GetPrefix(const std::initializer_list &field); + + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + +private: + static constexpr const char *INFO_PREFIX = "CLOUD_INFO"; + static constexpr const char *SCHEMA_PREFIX = "CLOUD_SCHEMA"; + + static std::string GetKey(const std::string &prefix, const std::initializer_list &fields); +}; +} +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_INFO_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_server.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_server.h new file mode 100644 index 0000000000000000000000000000000000000000..eee93713e30b9facf7d7672c5cdaf20572b92316 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/cloud_server.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_SERVER_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_SERVER_H +#include "cloud/asset_loader.h" +#include "cloud/cloud_db.h" +#include "cloud/cloud_info.h" +#include "cloud/schema_meta.h" +#include "visibility.h" +namespace OHOS::DistributedData { +class API_EXPORT CloudServer { +public: + using Database = SchemaMeta::Database; + API_EXPORT static CloudServer *GetInstance(); + API_EXPORT static bool RegisterCloudInstance(CloudServer *instance); + + virtual CloudInfo GetServerInfo(int32_t userId); + virtual SchemaMeta GetAppSchema(int32_t userId, const std::string &bundleName); + virtual std::shared_ptr ConnectAssetLoader(uint32_t tokenId, const Database &dbMeta); + virtual std::shared_ptr ConnectCloudDB(uint32_t tokenId, const Database &dbMeta); + +private: + static CloudServer *instance_; +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_CLOUD_SERVER_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/cloud/schema_meta.h b/datamgr_service/services/distributeddataservice/framework/include/cloud/schema_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..188a013262b4877511a88c20d2499811dc9484d4 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/cloud/schema_meta.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_SCHEMA_META_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_SCHEMA_META_H +#include "serializable/serializable.h" +namespace OHOS::DistributedData { +class API_EXPORT SchemaMeta final : public Serializable { +public: + static constexpr const char *DELETE_FIELD = "#_deleted"; + static constexpr const char *GID_FIELD = "#_gid"; + static constexpr const char *CREATE_FIELD = "#_createTime"; + static constexpr const char *MODIFY_FIELD = "#_modifyTime"; + static constexpr const char *CURSOR_FIELD = "#_cursor"; + struct API_EXPORT Field final : public Serializable { + std::string colName; + std::string alias; + int32_t type = 0; + bool primary = false; + bool nullable = true; + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + }; + + struct API_EXPORT Table final : public Serializable { + std::string name; + std::string alias; + std::vector fields; + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + }; + + struct API_EXPORT Database final : public Serializable { + std::string name = ""; + std::string alias; + std::vector tables; + + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + }; + int32_t version = 0; + std::vector databases; + + bool Marshal(json &node) const override; + bool Unmarshal(const json &node) override; + Database GetDataBase(const std::string &storeId); +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_CLOUD_SCHEMA_META_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/error/general_error.h b/datamgr_service/services/distributeddataservice/framework/include/error/general_error.h new file mode 100644 index 0000000000000000000000000000000000000000..8c60a916290acf7404633630ba9c36d17e213aa8 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/error/general_error.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_ERROR_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_ERROR_H +namespace OHOS::DistributedData { +enum GeneralError : int32_t { + E_OK = 0, + E_ERROR, + E_BUSY, + E_INVALID_ARGS, + E_NOT_INIT, + E_NOT_SUPPORT, + E_ALREADY_CONSUMED, + E_ALREADY_CLOSED, + E_BUTT, +}; +} +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_ERROR_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/eventcenter/event.h b/datamgr_service/services/distributeddataservice/framework/include/eventcenter/event.h index d574e0f5b6fe55345666cbcc8d36a9f949e1e91e..27bf9df2e6c2daaf3d77ba2084b8cd16e97fb94e 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/eventcenter/event.h +++ b/datamgr_service/services/distributeddataservice/framework/include/eventcenter/event.h @@ -27,7 +27,8 @@ public: EVT_INVALID, EVT_INITED, EVT_UPDATE, - EVT_CUSTOM = 0x1000 + EVT_CUSTOM = 0x1000, + EVT_CLOUD = 0x2000 }; API_EXPORT Event(int32_t evtId); API_EXPORT Event(Event &&) noexcept = delete; diff --git a/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h b/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h index 2a2fcc5f0fe46666113422dbfdfc371982378141..bb134e354f0670a4b87bd253ba57db7def0af182 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h +++ b/datamgr_service/services/distributeddataservice/framework/include/metadata/store_meta_data.h @@ -22,9 +22,10 @@ namespace OHOS::DistributedData { struct API_EXPORT StoreMetaData final : public Serializable { // record meta version for compatible, should update when modify store meta data structure. - static constexpr uint32_t CURRENT_VERSION = 0x03000003; + static constexpr uint32_t CURRENT_VERSION = 0x03000004; // UID -> uid, deviceAccountId -> userId, userId -> user static constexpr uint32_t FIELD_CHANGED_TAG = 0x03000003; + static constexpr uint32_t UUID_CHANGED_TAG = 0x03000004; uint32_t version = CURRENT_VERSION; bool isAutoSync = false; bool isBackup = false; diff --git a/datamgr_service/services/distributeddataservice/framework/include/serializable/serializable.h b/datamgr_service/services/distributeddataservice/framework/include/serializable/serializable.h index dc2337c9ece26fea414941c3c9dc44f96ed12530..4b16f8dd3b817fdac6b2e0f8ff14d34f245cbb71 100644 --- a/datamgr_service/services/distributeddataservice/framework/include/serializable/serializable.h +++ b/datamgr_service/services/distributeddataservice/framework/include/serializable/serializable.h @@ -55,6 +55,7 @@ public: API_EXPORT static bool GetValue(const json &node, const std::string &name, uint32_t &value); API_EXPORT static bool GetValue(const json &node, const std::string &name, int32_t &value); API_EXPORT static bool GetValue(const json &node, const std::string &name, int64_t &value); + API_EXPORT static bool GetValue(const json &node, const std::string &name, uint64_t &value); API_EXPORT static bool GetValue(const json &node, const std::string &name, bool &value); API_EXPORT static bool GetValue(const json &node, const std::string &name, std::vector &value); API_EXPORT static bool GetValue(const json &node, const std::string &name, Serializable &value); @@ -62,6 +63,7 @@ public: API_EXPORT static bool SetValue(json &node, const uint32_t &value); API_EXPORT static bool SetValue(json &node, const int32_t &value); API_EXPORT static bool SetValue(json &node, const int64_t &value); + API_EXPORT static bool SetValue(json &node, const uint64_t &value); API_EXPORT static bool SetValue(json &node, const bool &value); API_EXPORT static bool SetValue(json &node, const std::vector &value); API_EXPORT static bool SetValue(json &node, const Serializable &value); diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/auto_cache.h b/datamgr_service/services/distributeddataservice/framework/include/store/auto_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..ffed302f3d4ea9f816666c59847acec357ef4666 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/store/auto_cache.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_STORE_AUTO_CACHE_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_STORE_AUTO_CACHE_H +#include +#include + +#include "concurrent_map.h" +#include "error/general_error.h" +#include "executor_pool.h" +#include "metadata/store_meta_data.h" +#include "store/general_store.h" +#include "store/general_value.h" +#include "store/general_watcher.h" +#include "visibility.h" +namespace OHOS::DistributedData { +class AutoCache { +public: + using Error = GeneralError; + using Store = std::shared_ptr; + using Watcher = GeneralWatcher; + using Watchers = std::set>; + using Time = std::chrono::steady_clock::time_point; + using Executor = ExecutorPool; + using TaskId = ExecutorPool::TaskId; + using Creator = std::function; + API_EXPORT static AutoCache &GetInstance(); + + API_EXPORT int32_t RegCreator(int32_t type, Creator creator); + + API_EXPORT void Bind(std::shared_ptr executor); + + API_EXPORT Store GetStore(const StoreMetaData &meta, const Watchers &watchers); + + API_EXPORT void CloseStore(uint32_t tokenId, const std::string &storeId); + + API_EXPORT void CloseExcept(const std::set &users); + + API_EXPORT void SetObserver(uint32_t tokenId, const std::string &storeId, const Watchers &watchers); + +private: + AutoCache(); + ~AutoCache(); + void GarbageCollect(bool isForce); + struct Delegate : public GeneralWatcher { + Delegate(GeneralStore *delegate, const Watchers &watchers, int32_t user); + ~Delegate(); + operator Store(); + bool operator<(const Time &time) const; + bool Close(); + int32_t GetUser() const; + void SetObservers(const Watchers &watchers); + int32_t OnChange(Origin origin, const std::string &id) override; + int32_t OnChange(Origin origin, const std::string &id, const std::vector &values) override; + + private: + mutable Time time_; + GeneralStore *store_ = nullptr; + Watchers watchers_; + int32_t user_; + std::shared_mutex mutex_; + }; + + static constexpr int64_t INTERVAL = 1; + static constexpr int32_t MAX_CREATOR_NUM = 30; + + std::shared_ptr executor_; + TaskId taskId_ = Executor::INVALID_TASK_ID; + ConcurrentMap> stores_; + Creator creators_[MAX_CREATOR_NUM]; +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_STORE_AUTO_CACHE_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/cursor.h b/datamgr_service/services/distributeddataservice/framework/include/store/cursor.h new file mode 100644 index 0000000000000000000000000000000000000000..e588c5fd65e4633671dcc911a283f9a79aed7b41 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/store/cursor.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_CURSOR_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_CURSOR_H +#include +#include +#include + +#include "store/general_value.h" +namespace OHOS::DistributedData { +class Cursor { +public: + virtual ~Cursor() = default; + + virtual int32_t GetColumnNames(std::vector &names) const = 0; + + virtual int32_t GetColumnName(int32_t col, std::string &name) const = 0; + + virtual int32_t GetColumnType(int32_t col) const = 0; + + virtual int32_t GetCount() const = 0; + + virtual int32_t MoveToFirst() = 0; + + virtual int32_t MoveToNext() = 0; + + virtual int32_t GetEntry(VBucket &entry) = 0; + + virtual int32_t GetRow(VBucket &data) = 0; + + virtual int32_t Get(int32_t col, Value &value) = 0; + + virtual int32_t Get(const std::string &col, Value &value) = 0; + + virtual int32_t Close() = 0; +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_CURSOR_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h new file mode 100644 index 0000000000000000000000000000000000000000..3b88c4f4a94882dbc58f505b1f6df7384e6a1e80 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_store.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_STORE_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_STORE_H +#include +#include +#include "store/cursor.h" +#include "store/general_value.h" +#include "store/general_watcher.h" +namespace OHOS::DistributedData { +class GeneralStore { +public: + using Watcher = GeneralWatcher; + using Async = std::function>)>; + using Devices = std::vector; + + virtual ~GeneralStore() = default; + + virtual int32_t Close() = 0; + + virtual int32_t Execute(const std::string &table, const std::string &sql) = 0; + + virtual int32_t BatchInsert(const std::string &table, VBuckets &&values) = 0; + + virtual int32_t BatchUpdate(const std::string &table, const std::string &sql, VBuckets &&values) = 0; + + virtual int32_t Delete(const std::string &table, const std::string &sql, Values &&args) = 0; + + virtual std::shared_ptr Query(const std::string &table, const std::string &sql, Values &&args) = 0; + + virtual std::shared_ptr Query(const std::string &table, const GenQuery &query) = 0; + + virtual int32_t Sync(const Devices &devices, int32_t mode, const GenQuery &query, Async async, int32_t wait) = 0; + + virtual int32_t Watch(int32_t origin, Watcher &watcher) = 0; + + virtual int32_t Unwatch(int32_t origin, Watcher &watcher) = 0; +}; +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_STORE_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h new file mode 100644 index 0000000000000000000000000000000000000000..eca104b1a1478bfdf032ac9dc86cbd218d1202f1 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_value.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_VALUE_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_VALUE_H +#include +#include +#include +#include +#include +#include "traits.h" +#include "error/general_error.h" +namespace OHOS::DistributedData { +struct Asset { + uint32_t version; + std::string name; + std::string uri; + std::string createTime; + std::string modifyTime; + std::string size; + std::string hash; +}; + +struct GenQuery { + virtual ~GenQuery() = default; + virtual int32_t GetInterfaceId() = 0; +}; + +using Assets = std::vector; +using Bytes = std::vector; +using Value = std::variant; +using Values = std::vector; +using VBucket = std::map; +using VBuckets = std::vector; + +template +inline constexpr size_t TYPE_INDEX = Traits::variant_index_of_v; + +inline constexpr size_t TYPE_MAX = Traits::variant_size_of_v; + +template +bool GetItem(T &&input, O &output) +{ + return false; +} + +template +bool GetItem(T &&input, O &output) +{ + auto val = Traits::get_if(&input); + if (val != nullptr) { + output = std::move(*val); + return true; + } + return GetItem(std::move(input), output); +} + +template +bool Convert(T &&input, std::variant &output) +{ + return GetItem(std::move(input), output); +} +} // namespace OHOS::DistributedData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_VALUE_H diff --git a/datamgr_service/services/distributeddataservice/framework/include/store/general_watcher.h b/datamgr_service/services/distributeddataservice/framework/include/store/general_watcher.h new file mode 100644 index 0000000000000000000000000000000000000000..52130eab7005077596a473d6a4e2346895dae712 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/include/store/general_watcher.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_WATCHER_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_WATCHER_H +#include +#include "store/general_value.h" +#include "visibility.h" +namespace OHOS::DistributedData { +class GeneralWatcher { +public: + enum Origin : int32_t { + ORIGIN_CLOUD, + ORIGIN_LOCAL, + ORIGIN_REMOTE, + ORIGIN_ALL, + ORIGIN_BUTT, + }; + + enum ChangeOp : int32_t { + OP_INSERT, + OP_UPDATE, + OP_DELETE, + OP_BUTT, + }; + + virtual ~GeneralWatcher() = default; + virtual int32_t OnChange(Origin origin, const std::string &id) = 0; + virtual int32_t OnChange(Origin origin, const std::string &id, const std::vector &values) = 0; +}; +} +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_FRAMEWORK_STORE_GENERAL_WATCHER_H diff --git a/datamgr_service/services/distributeddataservice/framework/serializable/serializable.cpp b/datamgr_service/services/distributeddataservice/framework/serializable/serializable.cpp index 9622af95f1f4aa8dcde243b769b5c3c3983e231c..509880a851e84c2958e43ab2078b3d1ab8943266 100644 --- a/datamgr_service/services/distributeddataservice/framework/serializable/serializable.cpp +++ b/datamgr_service/services/distributeddataservice/framework/serializable/serializable.cpp @@ -103,6 +103,16 @@ bool Serializable::GetValue(const json &node, const std::string &name, int64_t & return true; } +bool Serializable::GetValue(const json &node, const std::string &name, uint64_t &value) +{ + auto &subNode = GetSubNode(node, name); + if (subNode.is_null() || !subNode.is_number_unsigned()) { + return false; + } + subNode.get_to(value); + return true; +} + bool Serializable::GetValue(const json &node, const std::string &name, bool &value) { auto &subNode = GetSubNode(node, name); @@ -156,6 +166,12 @@ bool Serializable::SetValue(json &node, const int64_t &value) return true; } +bool Serializable::SetValue(json &node, const uint64_t &value) +{ + node = value; + return true; +} + bool Serializable::SetValue(json &node, const bool &value) { node = value; diff --git a/datamgr_service/services/distributeddataservice/framework/store/auto_cache.cpp b/datamgr_service/services/distributeddataservice/framework/store/auto_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..212f6c1b33310677575e68a54f9680932a1e6212 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/framework/store/auto_cache.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ +#define LOG_TAG "AutoCache" +#include "store/auto_cache.h" + +#include +namespace OHOS::DistributedData { +AutoCache &AutoCache::GetInstance() +{ + static AutoCache cache; + return cache; +} + +int32_t AutoCache::RegCreator(int32_t type, Creator creator) +{ + if (type >= MAX_CREATOR_NUM) { + return E_ERROR; + } + creators_[type] = creator; + return 0; +} + +void AutoCache::Bind(std::shared_ptr executor) +{ + if (executor == nullptr || taskId_ != Executor::INVALID_TASK_ID) { + return; + } + executor_ = executor; + taskId_ = executor_->Schedule(std::bind(&AutoCache::GarbageCollect, this, false), std::chrono::minutes(INTERVAL), + std::chrono::minutes(INTERVAL)); +} + +AutoCache::AutoCache() {} + +AutoCache::~AutoCache() +{ + GarbageCollect(true); + if (executor_ != nullptr) { + executor_->Remove(taskId_, true); + } +} + +AutoCache::Store AutoCache::GetStore(const StoreMetaData &meta, const Watchers &watchers) +{ + Store store; + if (meta.storeType >= MAX_CREATOR_NUM || !creators_[meta.storeType]) { + return store; + } + + stores_.Compute(meta.tokenId, + [this, &meta, &watchers, &store](auto &, std::map &stores) -> bool { + auto it = stores.find(meta.storeId); + if (it != stores.end()) { + it->second.SetObservers(watchers); + store = it->second; + return !stores.empty(); + } + auto *dbStore = creators_[meta.storeType](meta); + if (dbStore == nullptr) { + return !stores.empty(); + } + auto result = stores.emplace(std::piecewise_construct, std::forward_as_tuple(meta.storeId), + std::forward_as_tuple(dbStore, watchers, atoi(meta.user.c_str()))); + store = result.first->second; + return !stores.empty(); + }); + return store; +} + +void AutoCache::CloseStore(uint32_t tokenId, const std::string &storeId) +{ + stores_.ComputeIfPresent(tokenId, [&storeId](auto &key, std::map &delegates) { + auto it = delegates.find(storeId); + if (it != delegates.end()) { + it->second.Close(); + delegates.erase(it); + } + return !delegates.empty(); + }); +} + +void AutoCache::CloseExcept(const std::set &users) +{ + stores_.EraseIf([&users](const auto &tokenId, std::map &delegates) { + if (delegates.empty() || users.count(delegates.begin()->second.GetUser()) != 0) { + return delegates.empty(); + } + + for (auto it = delegates.begin(); it != delegates.end();) { + // if the kv store is BUSY we wait more INTERVAL minutes again + if (!it->second.Close()) { + ++it; + } else { + it = delegates.erase(it); + } + } + return delegates.empty(); + }); +} + +void AutoCache::SetObserver(uint32_t tokenId, const std::string &storeId, const AutoCache::Watchers &watchers) +{ + stores_.ComputeIfPresent(tokenId, [&storeId, &watchers](auto &key, auto &stores) { + ZLOGD("tokenId:0x%{public}x storeId:%{public}s observers:%{public}zu", key, storeId.c_str(), watchers.size()); + auto it = stores.find(storeId); + if (it != stores.end()) { + it->second.SetObservers(watchers); + } + return true; + }); +} + +void AutoCache::GarbageCollect(bool isForce) +{ + auto current = std::chrono::steady_clock::now(); + stores_.EraseIf([¤t, isForce](auto &key, std::map &delegates) { + for (auto it = delegates.begin(); it != delegates.end();) { + // if the kv store is BUSY we wait more INTERVAL minutes again + if ((isForce || it->second < current) && it->second.Close()) { + it = delegates.erase(it); + } else { + ++it; + } + } + return delegates.empty(); + }); +} + +AutoCache::Delegate::Delegate(GeneralStore *delegate, const Watchers &watchers, int32_t user) + : store_(delegate), watchers_(watchers), user_(user) +{ + time_ = std::chrono::steady_clock::now() + std::chrono::minutes(INTERVAL); + if (store_ != nullptr) { + store_->Watch(ORIGIN_ALL, *this); + } +} + +AutoCache::Delegate::~Delegate() +{ + if (store_ != nullptr) { + store_->Unwatch(ORIGIN_ALL, *this); + store_->Close(); + store_ = nullptr; + } +} + +AutoCache::Delegate::operator Store() +{ + time_ = std::chrono::steady_clock::now() + std::chrono::minutes(INTERVAL); + return Store(store_, [](GeneralStore *) {}); +} + +bool AutoCache::Delegate::operator<(const AutoCache::Time &time) const +{ + return time_ < time; +} + +bool AutoCache::Delegate::Close() +{ + std::unique_lock lock(mutex_); + if (store_ != nullptr) { + store_->Unwatch(ORIGIN_ALL, *this); + } + + auto status = store_->Close(); + if (status == Error::E_BUSY) { + return false; + } + store_ = nullptr; + return true; +} + +void AutoCache::Delegate::SetObservers(const AutoCache::Watchers &watchers) +{ + std::unique_lock lock(mutex_); + watchers_ = watchers; +} + +int32_t AutoCache::Delegate::GetUser() const +{ + return user_; +} + +int32_t AutoCache::Delegate::OnChange(Origin origin, const std::string &id) +{ + Watchers watchers; + { + std::unique_lock lock(mutex_); + watchers = watchers_; + } + for (auto watcher : watchers) { + if (watcher == nullptr) { + continue; + } + watcher->OnChange(origin, id); + } + return Error::E_OK; +} + +int32_t AutoCache::Delegate::OnChange(Origin origin, const std::string &id, const std::vector &values) +{ + Watchers watchers; + { + std::unique_lock lock(mutex_); + watchers = watchers_; + } + for (auto watcher : watchers) { + if (watcher == nullptr) { + continue; + } + watcher->OnChange(origin, id, values); + } + return Error::E_OK; +} +} // namespace OHOS::DistributedData diff --git a/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn b/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn index 006e0bd0682a50ffd189890279305c2d620da2b8..1e2ccfa56878f30e7d2cf6cbccd3e45f39836add 100644 --- a/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/framework/test/BUILD.gn @@ -24,6 +24,7 @@ config("module_private_config") { "../../service/bootstrap/include/", ] ldflags = [ "-Wl,--whole-archive" ] + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } ohos_unittest("CheckerManagerTest") { diff --git a/datamgr_service/services/distributeddataservice/framework/test/serializable_test.cpp b/datamgr_service/services/distributeddataservice/framework/test/serializable_test.cpp index 55364fd9c0b861995a77f39e5c0fd02f0f242001..95c0154b447b485fbe04080e012199b58ce0f6ce 100644 --- a/datamgr_service/services/distributeddataservice/framework/test/serializable_test.cpp +++ b/datamgr_service/services/distributeddataservice/framework/test/serializable_test.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ #define LOG_TAG "SerializableTest" +#include #include "log_print.h" #include "serializable/serializable.h" #include "gtest/gtest.h" @@ -112,7 +113,7 @@ public: */ HWTEST_F(SerializableTest, GetNormalVal, TestSize.Level2) { - ZLOGI("SerializableSuite GetVal begin."); + ZLOGI("SerializableSuite GetNormalVal begin."); Normal normal; normal.name = "normal"; normal.count = -1; @@ -135,9 +136,9 @@ HWTEST_F(SerializableTest, GetNormalVal, TestSize.Level2) */ HWTEST_F(SerializableTest, DeleteSerializable, TestSize.Level2) { - ZLOGI("SerializableSuite GetVal begin."); - NormalEx *normalEx = new NormalEx(); - delete normalEx; + ZLOGI("SerializableSuite DeleteSerializable begin."); + ASSERT_FALSE(std::is_destructible::value); + ASSERT_TRUE(std::is_destructible::value); } /** @@ -149,7 +150,7 @@ HWTEST_F(SerializableTest, DeleteSerializable, TestSize.Level2) */ HWTEST_F(SerializableTest, GetMutilVal, TestSize.Level2) { - ZLOGI("SerializableSuite GetVal begin."); + ZLOGI("SerializableSuite GetMutilVal begin."); NormalEx normalEx; normalEx.normals = {Normal()}; normalEx.name = "normalEx"; diff --git a/datamgr_service/services/distributeddataservice/service/BUILD.gn b/datamgr_service/services/distributeddataservice/service/BUILD.gn index 6adf404a342fb6b0818da7143688be7629148b4c..17f18018993503800755c91755c0329afb2bdf67 100644 --- a/datamgr_service/services/distributeddataservice/service/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/BUILD.gn @@ -21,6 +21,7 @@ config("module_public_config") { include_dirs = [ "backup/include", "bootstrap/include", + "cloud", "config/include", "crypto/include", "datashare", @@ -52,11 +53,15 @@ ohos_shared_library("distributeddatasvc") { include_dirs = [ "../../../../data_object/frameworks/innerkitsimpl/include", "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb/include", + "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/cloud_data/include", "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/include/distributeddb", ] sources = [ "backup/src/backup_manager.cpp", "bootstrap/src/bootstrap.cpp", + "cloud/cloud_service_impl.cpp", + "cloud/cloud_service_stub.cpp", + "cloud/cloud_syncer.cpp", "config/src/config_factory.cpp", "config/src/model/backup_config.cpp", "config/src/model/checker_config.cpp", @@ -94,6 +99,7 @@ ohos_shared_library("distributeddatasvc") { "object/object_service_impl.cpp", "object/object_service_stub.cpp", "permission/src/permit_delegate.cpp", + "rdb/rdb_general_store.cpp", "rdb/rdb_notifier_proxy.cpp", "rdb/rdb_result_set_impl.cpp", "rdb/rdb_result_set_stub.cpp", @@ -130,6 +136,7 @@ ohos_shared_library("distributeddatasvc") { "huks:libhukssdk", "ipc:ipc_core", "relational_store:native_rdb", + "relational_store:cloud_data", "relational_store:rdb_data_share_adapter", "resource_management:global_resmgr", "samgr:samgr_proxy", @@ -137,4 +144,5 @@ ohos_shared_library("distributeddatasvc") { subsystem_name = "distributeddatamgr" part_name = "datamgr_service" + defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] } diff --git a/datamgr_service/services/distributeddataservice/service/CMakeLists.txt b/datamgr_service/services/distributeddataservice/service/CMakeLists.txt index a90fab7b223e75ea8417a95181b4ffbee5cf975f..942ded1199a6b6778500344f1dae7f82f92d38f9 100644 --- a/datamgr_service/services/distributeddataservice/service/CMakeLists.txt +++ b/datamgr_service/services/distributeddataservice/service/CMakeLists.txt @@ -12,6 +12,7 @@ set(MOCK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../mock") set(KV_STORE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../kv_store") aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/backup/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/bootstrap/src serviceSrc) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/cloud serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/config/src serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/config/src/model serviceSrc) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/directory/src serviceSrc) @@ -30,6 +31,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/bootstrap/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/directory/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/permission/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/matrix/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/cloud) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/rdb) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/kvdb) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../framework/include) @@ -45,6 +47,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include/permission) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include/security) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../adapter/include/utils) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../app/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/appdatafwk/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/cloud_data/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/rdb/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../relational_store/interfaces/inner_api/rdb_data_share_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../../data_share/interfaces/inner_api/common/include) diff --git a/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp b/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp index 7d39b94f828c12b853f1815677093c2867c583c7..741f18b989de6314b09458af6f8350372405b4b1 100644 --- a/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp +++ b/datamgr_service/services/distributeddataservice/service/bootstrap/src/bootstrap.cpp @@ -58,7 +58,6 @@ void Bootstrap::LoadComponents() if (comp.lib.empty()) { continue; } - // no need to close the component, so we don't keep the handles auto handle = dlopen(comp.lib.c_str(), RTLD_LAZY); if (handle == nullptr) { diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f51ad400fdae5f1b371ac0645ed210cfb77cca3 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ + +#define LOG_TAG "CloudServiceImpl" + +#include "cloud_service_impl.h" + +#include "account/account_delegate.h" +#include "checker/checker_manager.h" +#include "cloud/cloud_event.h" +#include "cloud/cloud_server.h" +#include "cloud_syncer.h" +#include "eventcenter/event_center.h" +#include "feature/feature_system.h" +#include "ipc_skeleton.h" +#include "log_print.h" +#include "metadata/meta_data_manager.h" +#include "utils/anonymous.h" + +namespace OHOS::CloudData { +using namespace DistributedData; +__attribute__((used)) CloudServiceImpl::Factory CloudServiceImpl::factory_; +CloudServiceImpl::Factory::Factory() +{ + FeatureSystem::GetInstance().RegisterCreator(CloudServiceImpl::SERVICE_NAME, [this]() { + if (product_ == nullptr) { + product_ = std::make_shared(); + } + return product_; + }); +} + +CloudServiceImpl::Factory::~Factory() {} + +CloudServiceImpl::CloudServiceImpl() +{ + EventCenter::GetInstance().Subscribe(CloudEvent::FEATURE_INIT, [this](const Event &event) { + auto &rdbEvent = static_cast(event); + CloudInfo cloudInfo; + cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(rdbEvent.GetTokenId()); + if (GetServerInfo(cloudInfo) != SUCCESS) { + ZLOGE("failed, user:%{public}d", cloudInfo.user); + return; + } + UpdateCloudInfo(cloudInfo); + AddSchema(cloudInfo); + // TODO: Clear Task + }); + + EventCenter::GetInstance().Subscribe(CloudEvent::GET_SCHEMA, [this](const Event &event) { + auto &rdbEvent = static_cast(event); + CloudInfo cloudInfo; + cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(rdbEvent.GetTokenId()); + if (GetServerInfo(cloudInfo) != SUCCESS) { + ZLOGE("failed, user:%{public}d", cloudInfo.user); + return; + } + auto instance = CloudServer::GetInstance(); + if (instance == nullptr) { + return; + } + SchemaMeta schemaMeta; + std::string schemaKey = cloudInfo.GetSchemaKey(rdbEvent.GetBundleName()); + if (!MetaDataManager::GetInstance().LoadMeta(schemaKey, schemaMeta, true)) { + schemaMeta = instance->GetAppSchema(cloudInfo.user, rdbEvent.GetBundleName()); + MetaDataManager::GetInstance().SaveMeta(schemaKey, schemaMeta, true); + auto finishedEvent = std::make_unique(CloudEvent::NEED_CREATE, rdbEvent); + finishedEvent->SetSchemaKey(schemaKey); + EventCenter::GetInstance().PostEvent(move(finishedEvent)); + } + + for (auto &database : schemaMeta.databases) { + if (database.name != rdbEvent.GetStoreName() /* ||TODO:不需要同步*/) { + continue; + } + auto cloudDB = instance->ConnectCloudDB(rdbEvent.GetTokenId(), database); + //TODO:同步 + } + }); +} + +int32_t CloudServiceImpl::EnableCloud(const std::string &id, const std::map &switches) +{ + std::lock_guard lg(mutex_); + CloudInfo cloudInfo; + cloudInfo.id = id; + if (GetCloudInfo(cloudInfo) != SUCCESS && GetServerInfo(cloudInfo) != SUCCESS) { + return INVALID_ARGUMENT; + } + cloudInfo.enableCloud = true; + for (const auto &item : switches) { + // cloudInfo.GetApp(item.first).cloudSwitch = item.second; + } + if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) { + return ERROR; + } + return SUCCESS; +} + +int32_t CloudServiceImpl::DisableCloud(const std::string &id) +{ + std::lock_guard lg(mutex_); + CloudInfo cloudInfo; + cloudInfo.id = id; + if (GetCloudInfo(cloudInfo) != SUCCESS && GetServerInfo(cloudInfo) != SUCCESS) { + return INVALID_ARGUMENT; + } + cloudInfo.enableCloud = false; + if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) { + return ERROR; + } + return SUCCESS; +} + +int32_t CloudServiceImpl::ChangeAppSwitch(const std::string &id, const std::string &bundleName, int32_t appSwitch) +{ + std::lock_guard lg(mutex_); + CloudInfo cloudInfo; + cloudInfo.id = id; + if (GetCloudInfo(cloudInfo) != SUCCESS && GetServerInfo(cloudInfo) != SUCCESS) { + return INVALID_ARGUMENT; + } + auto it = std::find_if(cloudInfo.apps.begin(), cloudInfo.apps.end(), + [&bundleName](const CloudInfo::AppInfo &appInfo) -> bool { + return appInfo.bundleName == bundleName; + }); + if (it == cloudInfo.apps.end()) { + ZLOGE("bundleName:%{public}s", bundleName.c_str()); + return INVALID_ARGUMENT; + } + (*it).cloudSwitch = appSwitch; + if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) { + return ERROR; + } + return SUCCESS; +} + +int32_t CloudServiceImpl::Clean(const std::string &id, const std::map &actions) +{ + CloudInfo cloudInfo; + cloudInfo.id = id; + if (GetCloudInfo(cloudInfo) != SUCCESS && GetServerInfo(cloudInfo) != SUCCESS) { + ZLOGE("id:%{public}s", Anonymous::Change(id).c_str()); + return INVALID_ARGUMENT; + } + auto keys = cloudInfo.GetSchemaKey(); + for (const auto &action : actions) { + if (!cloudInfo.IsExist(action.first)) { + continue; + } + SchemaMeta schemaMeta; + if (MetaDataManager::GetInstance().LoadMeta(keys[action.first], schemaMeta, true)) { + // TODO action + } + } + return SUCCESS; +} + +int32_t CloudServiceImpl::NotifyDataChange(const std::string &id, const std::string &bundleName) +{ + return 0; +} + +int32_t CloudServiceImpl::GetCloudInfo(CloudInfo &cloudInfo) +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(tokenId); + if (!MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetKey(), cloudInfo, true)) { + ZLOGE("invalid argument id:%{public}s, user:%{public}d", Anonymous::Change(cloudInfo.id).c_str(), + cloudInfo.user); + return ERROR; + } + return SUCCESS; +} + +int32_t CloudServiceImpl::GetServerInfo(CloudInfo &cloudInfo) +{ + auto instance = CloudServer::GetInstance(); + if (instance == nullptr) { + return SERVER_UNAVAILABLE; + } + cloudInfo = instance->GetServerInfo(cloudInfo.user); + if (!cloudInfo.IsValid()) { + return ERROR; + } + return SUCCESS; +} + +std::string CloudServiceImpl::GetAppId(const std::string &bundleName) +{ + CheckerManager::StoreInfo storeInfo; + storeInfo.uid = IPCSkeleton::GetCallingUid(); + storeInfo.tokenId = IPCSkeleton::GetCallingTokenID(); + storeInfo.bundleName = bundleName; + return CheckerManager::GetInstance().GetAppId(storeInfo); +} + +bool CloudServiceImpl::CheckAccess(const std::string &bundleName) +{ + CheckerManager::StoreInfo storeInfo; + storeInfo.uid = IPCSkeleton::GetCallingUid(); + storeInfo.tokenId = IPCSkeleton::GetCallingTokenID(); + storeInfo.bundleName = bundleName; + return CheckerManager::GetInstance().IsValid(storeInfo); +} + +void CloudServiceImpl::UpdateCloudInfo(CloudInfo &cloudInfo) +{ + CloudInfo oldInfo; + if (!MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetKey(), oldInfo, true)) { + MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true); + return; + } + oldInfo.totalSpace = cloudInfo.totalSpace; + oldInfo.remainSpace = cloudInfo.remainSpace; + oldInfo.apps = std::move(cloudInfo.apps); + cloudInfo = oldInfo; + MetaDataManager::GetInstance().SaveMeta(oldInfo.GetKey(), oldInfo, true); +} + +void CloudServiceImpl::AddSchema(CloudInfo &cloudInfo) +{ + auto keys = cloudInfo.GetSchemaKey(); + for (const auto &key : keys) { + SchemaMeta schemaMeta; + if (MetaDataManager::GetInstance().LoadMeta(key.second, schemaMeta, true)) { + continue; + } + if (GetAppSchema(cloudInfo.user, key.first, schemaMeta) != SUCCESS) { + continue; + } + MetaDataManager::GetInstance().SaveMeta(key.second, schemaMeta, true); + } +} + +int32_t CloudServiceImpl::GetAppSchema(int32_t user, const std::string &bundleName, SchemaMeta &schemaMeta) +{ + auto instance = CloudServer::GetInstance(); + if (instance == nullptr) { + return SERVER_UNAVAILABLE; + } + schemaMeta = instance->GetAppSchema(user, bundleName); + return SUCCESS; +} +} // namespace OHOS::CloudData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..80aa5100110b5deabddbbf55a04257e06a576757 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_impl.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SERVICE_IMPL_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SERVICE_IMPL_H + +#include +#include "cloud_service_stub.h" +#include "cloud/cloud_info.h" +#include "cloud/schema_meta.h" + +namespace OHOS::CloudData { +class CloudServiceImpl : public CloudServiceStub { +public: + CloudServiceImpl(); + ~CloudServiceImpl() = default; + int32_t EnableCloud(const std::string &id, const std::map &switches) override; + int32_t DisableCloud(const std::string &id) override; + int32_t ChangeAppSwitch(const std::string &id, const std::string &bundleName, int32_t appSwitch) override; + int32_t Clean(const std::string &id, const std::map &actions) override; + int32_t NotifyDataChange(const std::string &id, const std::string &bundleName) override; + +private: + class Factory { + public: + Factory(); + ~Factory(); + private: + std::shared_ptr product_; + }; + static Factory factory_; + + using CloudInfo = DistributedData::CloudInfo; + using SchemaMeta = DistributedData::SchemaMeta; + + void UpdateCloudInfo(CloudInfo &cloudInfo); + void AddSchema(CloudInfo &cloudInfo); + int32_t GetCloudInfo(CloudInfo &cloudInfo); + int32_t GetServerInfo(CloudInfo &cloudInfo); + int32_t GetAppSchema(int32_t user, const std::string &bundleName, SchemaMeta &schemaMeta); + std::string GetAppId(const std::string &bundleName); + bool CheckAccess(const std::string &bundleName); + std::mutex mutex_; + ConcurrentMap cloudInfos_; +}; +} // namespace OHOS::DistributedData + +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SERVICE_IMPL_H diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bdf8b5fbe732893a5161b0db368f8fad50df9773 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ +#define LOG_TAG "CloudServiceStub" +#include "cloud_service_stub.h" + +#include + +#include "ipc_skeleton.h" +#include "itypes_util.h" +#include "log_print.h" +#include "utils/anonymous.h" +namespace OHOS::CloudData { +using namespace DistributedData; +const CloudServiceStub::Handler CloudServiceStub::HANDLERS[TRANS_BUTT] = { + &CloudServiceStub::OnEnableCloud, + &CloudServiceStub::OnDisableCloud, + &CloudServiceStub::OnChangeAppSwitch, + &CloudServiceStub::OnClean, + &CloudServiceStub::OnNotifyDataChange, +}; + +int CloudServiceStub::OnRemoteRequest(uint32_t code, OHOS::MessageParcel &data, OHOS::MessageParcel &reply) +{ + ZLOGI("code:%{public}u callingPid:%{public}u", code, IPCSkeleton::GetCallingPid()); + std::u16string local = CloudServiceStub::GetDescriptor(); + std::u16string remote = data.ReadInterfaceToken(); + if (local != remote) { + ZLOGE("local is not equal to remote"); + return -1; + } + + if (TRANS_HEAD > code || code >= TRANS_BUTT || HANDLERS[code] == nullptr) { + ZLOGE("not support code:%{public}u, BUTT:%{public}d", code, TRANS_BUTT); + return -1; + } + std::string id; + if (!ITypesUtil::Unmarshal(data, id)) { + ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + return (this->*HANDLERS[code])(id, data, reply); +} + +int32_t CloudServiceStub::OnEnableCloud(const std::string &id, MessageParcel &data, MessageParcel &reply) +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } + std::map switches; + if (!ITypesUtil::Unmarshal(data, switches)) { + ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + auto result = EnableCloud(id, switches); + return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; +} + +int32_t CloudServiceStub::OnDisableCloud(const std::string &id, MessageParcel &data, MessageParcel &reply) +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } + auto result = DisableCloud(id); + return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; +} + +int32_t CloudServiceStub::OnChangeAppSwitch(const std::string &id, MessageParcel &data, MessageParcel &reply) +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } + std::string bundleName; + int32_t appSwitch = SWITCH_OFF; + if (!ITypesUtil::Unmarshal(data, bundleName, appSwitch)) { + ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + auto result = ChangeAppSwitch(id, bundleName, appSwitch); + return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; +} + +int32_t CloudServiceStub::OnClean(const std::string &id, MessageParcel &data, MessageParcel &reply) +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } + std::map actions; + if (!ITypesUtil::Unmarshal(data, actions)) { + ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + auto result = Clean(id, actions); + return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; +} + +int32_t CloudServiceStub::OnNotifyDataChange(const std::string &id, MessageParcel &data, MessageParcel &reply) +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } + std::string bundleName; + if (!ITypesUtil::Unmarshal(data, bundleName)) { + ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + auto result = NotifyDataChange(id, bundleName); + return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; +} +} // namespace OHOS::CloudData diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.h b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..4175015d2731ca380b02874ab4af692502cd22d9 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SERVICE_STUB_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SERVICE_STUB_H +#include "cloud_service.h" +#include "feature/feature_system.h" +#include "iremote_broker.h" +namespace OHOS::CloudData { +class CloudServiceStub : public CloudService, public DistributedData::FeatureSystem::Feature { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CloudData.CloudServer"); + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) override; + +private: + using Handler = int32_t (CloudServiceStub::*)(const std::string &id, MessageParcel &data, MessageParcel &reply); + int32_t OnEnableCloud(const std::string &id, MessageParcel &data, MessageParcel &reply); + int32_t OnDisableCloud(const std::string &id, MessageParcel &data, MessageParcel &reply); + int32_t OnChangeAppSwitch(const std::string &id, MessageParcel &data, MessageParcel &reply); + int32_t OnClean(const std::string &id, MessageParcel &data, MessageParcel &reply); + int32_t OnNotifyDataChange(const std::string &id, MessageParcel &data, MessageParcel &reply); + static const Handler HANDLERS[TRANS_BUTT]; +}; +} // namespace OHOS::CloudData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SERVICE_STUB_H diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_syncer.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_syncer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f920c5ec5798f8535de32db03ac6551ce898e4d0 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_syncer.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "cloud_syncer.h" + +namespace OHOS::CloudData { +CloudSyncer &CloudSyncer::GetInstance() +{ + static CloudSyncer instance; + return instance; +} + +void CloudSyncer::Sync(const DistributedData::CloudInfo &cloudInfo) +{ +} +} // namespace OHOS::CloudData \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_syncer.h b/datamgr_service/services/distributeddataservice/service/cloud/cloud_syncer.h new file mode 100644 index 0000000000000000000000000000000000000000..c9dd79717460746661490e3cd867af603bff33e9 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_syncer.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SYNCER_H +#define OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SYNCER_H + +#include "cloud/cloud_info.h" + +namespace OHOS::CloudData { +class CloudSyncer { +public: + static CloudSyncer &GetInstance(); + void Sync(const DistributedData::CloudInfo &cloudInfo); + +private: +}; +} // namespace OHOS::CloudData +#endif // OHOS_DISTRIBUTED_DATA_SERVICES_CLOUD_CLOUD_SYNCER_H diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.cpp index 329b9499858320981a904531decca0e44b47a89e..da563ec8b18a2e7b44396a2f98878156321ce72c 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + #define LOG_TAG "DataShareProfileInfo" #include "data_share_profile_info.h" @@ -57,9 +57,7 @@ bool ProfileInfo::Marshal(json &node) const bool ProfileInfo::Unmarshal(const json &node) { - bool ret = true; - ret = GetValue(node, GET_NAME(tableConfig), tableConfig) && ret; - return ret; + return GetValue(node, GET_NAME(tableConfig), tableConfig); } bool DataShareProfileInfo::GetProfileInfoFromExtension(const AppExecFwk::BundleInfo &bundleInfo, @@ -71,15 +69,14 @@ bool DataShareProfileInfo::GetProfileInfoFromExtension(const AppExecFwk::BundleI return true; } - for (auto &item : bundleInfo.extensionInfos) { + for (auto const &item : bundleInfo.extensionInfos) { if (item.type == AppExecFwk::ExtensionAbilityType::DATASHARE) { - std::vector infos; bool isCompressed = !item.hapPath.empty(); std::string resourcePath = isCompressed ? item.hapPath : item.resourcePath; - if (!GetResProfileByMetadata(item.metadata, resourcePath, isCompressed, infos) || infos.empty()) { - ZLOGE("failed, bundleName is %{public}s, resourcePath is %{public}s, metadata.size is %{public}zu," - "infos.size is %{public}zu", bundleInfo.name.c_str(), resourcePath.c_str(), item.metadata.size(), - infos.size()); + std::vector infos = GetResProfileByMetadata(item.metadata, resourcePath, isCompressed); + if (infos.empty()) { + ZLOGE("failed, bundleName is %{public}s, resourcePath is %{public}s, metadata.size is %{public}zu,", + bundleInfo.name.c_str(), resourcePath.c_str(), item.metadata.size()); return false; } return profileInfo.Unmarshall(infos[0]); @@ -89,23 +86,24 @@ bool DataShareProfileInfo::GetProfileInfoFromExtension(const AppExecFwk::BundleI return false; } -bool DataShareProfileInfo::GetResProfileByMetadata(const std::vector &metadata, - const std::string &resourcePath, bool isCompressed, std::vector &profileInfos) const +std::vector DataShareProfileInfo::GetResProfileByMetadata( + const std::vector &metadata, const std::string &resourcePath, bool isCompressed) const { + std::vector profileInfos; if (metadata.empty() || resourcePath.empty()) { - return false; + return profileInfos; } std::shared_ptr resMgr = InitResMgr(resourcePath); if (resMgr == nullptr) { - return false; + return profileInfos; } - for (auto &meta : metadata) { - if (meta.name.compare(DATA_SHARE_PROFILE_META) == 0) { - return GetResFromResMgr(meta.resource, *resMgr, isCompressed, profileInfos); + for (auto const &meta : metadata) { + if (meta.name == DATA_SHARE_PROFILE_META) { + return GetResFromResMgr(meta.resource, *resMgr, isCompressed); } } - return false; + return profileInfos; } std::shared_ptr DataShareProfileInfo::InitResMgr(const std::string &resourcePath) const @@ -128,17 +126,18 @@ std::shared_ptr DataShareProfileInfo::InitResMgr(const std::str return resMgr; } -bool DataShareProfileInfo::GetResFromResMgr(const std::string &resName, ResourceManager &resMgr, - bool isCompressed, std::vector &profileInfos) const +std::vector DataShareProfileInfo::GetResFromResMgr(const std::string &resName, ResourceManager &resMgr, + bool isCompressed) const { + std::vector profileInfos; if (resName.empty()) { - return false; + return profileInfos; } size_t pos = resName.rfind(PROFILE_FILE_PREFIX); if ((pos == std::string::npos) || (pos == resName.length() - PROFILE_PREFIX_LEN)) { ZLOGE("res name invalid, resName is %{public}s", resName.c_str()); - return false; + return profileInfos; } std::string profileName = resName.substr(pos + PROFILE_PREFIX_LEN); // hap is compressed status, get file content. @@ -150,34 +149,34 @@ bool DataShareProfileInfo::GetResFromResMgr(const std::string &resName, Resource if (ret != SUCCESS || fileContent == nullptr) { ZLOGE("failed, ret is %{public}d, profileName is %{public}s", ret, profileName.c_str()); - return false; + return profileInfos; } if (len == 0) { ZLOGE("fileContent is empty, profileName is %{public}s", profileName.c_str()); - return false; + return profileInfos; } std::string rawData(fileContent.get(), fileContent.get() + len); if (!Config::IsJson(rawData)) { ZLOGE("rawData is not json, profileName is %{public}s", profileName.c_str()); - return false; + return profileInfos; } profileInfos.push_back(std::move(rawData)); - return true; + return profileInfos; } // hap is decompressed status, get file path then read file. std::string resPath; RState ret = resMgr.GetProfileByName(profileName.c_str(), resPath); if (ret != SUCCESS) { ZLOGE("profileName not found, ret is %{public}d, profileName is %{public}s", ret, profileName.c_str()); - return false; + return profileInfos; } std::string profile = ReadProfile(resPath); if (profile.empty()) { ZLOGE("Read profile failed, resPath is %{public}s", resPath.c_str()); - return false; + return profileInfos; } profileInfos.push_back(std::move(profile)); - return true; + return profileInfos; } bool DataShareProfileInfo::IsFileExisted(const std::string &filePath) const diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.h b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.h index 9dac5236f18ff97902976f82cb3639da46e05aa4..b943aaf15f67ca7343116f43dd9510c5cf98c3a4 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_profile_info.h @@ -45,11 +45,11 @@ public: ProfileInfo &profileInfo, bool &isSingleApp); private: - bool GetResProfileByMetadata(const std::vector &metadata, const std::string &resourcePath, - bool isCompressed, std::vector &profileInfos) const; + std::vector GetResProfileByMetadata(const std::vector &metadata, + const std::string &resourcePath, bool isCompressed) const; std::shared_ptr InitResMgr(const std::string &basicString) const; - bool GetResFromResMgr(const std::string &resName, ResourceManager &resMgr, bool isCompressed, - std::vector &profileInfos) const; + std::vector GetResFromResMgr(const std::string &resName, ResourceManager &resMgr, + bool isCompressed) const; std::string ReadProfile(const std::string &resPath) const; bool IsFileExisted(const std::string &filePath) const; }; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp index 63c9fd3ff2c1247aa41dda32c75bba015706f590..4fc2ca94e9edab4330926dc2383d68f65ca29caf 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_impl.cpp @@ -212,13 +212,12 @@ std::string DataShareServiceImpl::GetRealityTableName(uint32_t tokenId, const Ap PermissionProxy::PermissionState DataShareServiceImpl::VerifyPermission(uint32_t tokenID, DataShareServiceImpl::PermissionType permissionType, const AppExecFwk::BundleInfo &bundleInfo) { - std::string permission; switch (permissionType) { case PermissionType::READ_PERMISSION: { - return PermissionProxy::QueryReadPermission(tokenID, permission, bundleInfo); + return PermissionProxy::QueryReadPermission(tokenID, bundleInfo); } case PermissionType::WRITE_PERMISSION: { - return PermissionProxy::QueryWritePermission(tokenID, permission, bundleInfo); + return PermissionProxy::QueryWritePermission(tokenID, bundleInfo); } } return PermissionProxy::PermissionState::NOT_FIND; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp index ba7fe7c77c0d444e21b87f268f06eedd746e9cbf..a388f8cce52437bf8f02b1788ee53068a07fb7e8 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/data_share_service_stub.cpp @@ -21,6 +21,7 @@ #include "ishared_result_set.h" #include "itypes_util.h" #include "log_print.h" +#include "utils/anonymous.h" namespace OHOS { namespace DataShare { @@ -40,13 +41,14 @@ int32_t DataShareServiceStub::OnRemoteInsert(MessageParcel &data, MessageParcel std::string uri; DataShareValuesBucket bucket; if (!ITypesUtil::Unmarshal(data, uri, bucket.valuesMap)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal uri:%{public}s bucket size:%{public}zu", DistributedData::Anonymous::Change(uri).c_str(), + bucket.valuesMap.size()); + return IPC_STUB_INVALID_DATA_ERR; } int32_t status = Insert(uri, bucket); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("OnRemoteInsert fail %{public}d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } @@ -57,13 +59,14 @@ int32_t DataShareServiceStub::OnRemoteUpdate(MessageParcel &data, MessageParcel DataSharePredicates predicate; DataShareValuesBucket bucket; if (!ITypesUtil::Unmarshal(data, uri, predicate, bucket.valuesMap)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal uri:%{public}s bucket size:%{public}zu", DistributedData::Anonymous::Change(uri).c_str(), + bucket.valuesMap.size()); + return IPC_STUB_INVALID_DATA_ERR; } int32_t status = Update(uri, predicate, bucket); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("OnRemoteUpdate fail %d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } @@ -73,13 +76,13 @@ int32_t DataShareServiceStub::OnRemoteDelete(MessageParcel &data, MessageParcel std::string uri; DataSharePredicates predicate; if (!ITypesUtil::Unmarshal(data, uri, predicate)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal uri:%{public}s", DistributedData::Anonymous::Change(uri).c_str()); + return IPC_STUB_INVALID_DATA_ERR; } int32_t status = Delete(uri, predicate); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("OnRemoteDelete fail %d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } @@ -90,15 +93,15 @@ int32_t DataShareServiceStub::OnRemoteQuery(MessageParcel &data, MessageParcel & DataSharePredicates predicate; std::vector columns; if (!ITypesUtil::Unmarshal(data, uri, predicate, columns)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal uri:%{public}s columns size:%{public}zu", DistributedData::Anonymous::Change(uri).c_str(), + columns.size()); + return IPC_STUB_INVALID_DATA_ERR; } - int errCode = 0; - auto result = ISharedResultSet::WriteToParcel(Query(uri, predicate, columns, errCode), reply); - reply.WriteInt32(errCode); - if (result == nullptr) { - ZLOGW("!resultSet->Marshalling(reply)"); - return -1; + int status = 0; + auto result = ISharedResultSet::WriteToParcel(Query(uri, predicate, columns, status), reply); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.cpp b/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.cpp index 0403006b7c07d5f79ca8f3c8a0c628dc91aeb8ce..ab68c1df1d60a5b04210341690b72dd7a10f6f02 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.cpp @@ -38,17 +38,16 @@ bool PermissionProxy::GetBundleInfo(const std::string &bundleName, uint32_t toke } PermissionProxy::PermissionState PermissionProxy::QueryWritePermission(uint32_t tokenId, - std::string &permission, const AppExecFwk::BundleInfo &bundleInfo) + const AppExecFwk::BundleInfo &bundleInfo) { - for (auto &item : bundleInfo.extensionInfos) { + for (auto const &item : bundleInfo.extensionInfos) { if (item.type == AppExecFwk::ExtensionAbilityType::DATASHARE) { - permission = item.writePermission; - if (permission.empty()) { + if (item.writePermission.empty()) { ZLOGW("WritePermission is empty! BundleName is %{public}s, tokenId is %{public}x", bundleInfo.name.c_str(), tokenId); return PermissionState::NOT_FIND; } - int status = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, permission); + int status = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, item.writePermission); if (status != Security::AccessToken::PermissionState::PERMISSION_GRANTED) { ZLOGE("Verify write permission denied!"); return PermissionState::DENIED; @@ -60,16 +59,16 @@ PermissionProxy::PermissionState PermissionProxy::QueryWritePermission(uint32_t } PermissionProxy::PermissionState PermissionProxy::QueryReadPermission(uint32_t tokenId, - std::string &permission, const AppExecFwk::BundleInfo &bundleInfo) + const AppExecFwk::BundleInfo &bundleInfo) { - for (auto &item : bundleInfo.extensionInfos) { + for (auto const &item : bundleInfo.extensionInfos) { if (item.type == AppExecFwk::ExtensionAbilityType::DATASHARE) { if (item.readPermission.empty()) { ZLOGW("ReadPermission is empty! BundleName is %{public}s, tokenId is %{public}x", bundleInfo.name.c_str(), tokenId); return PermissionState::NOT_FIND; } - int status = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, permission); + int status = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, item.readPermission); if (status != Security::AccessToken::PermissionState::PERMISSION_GRANTED) { ZLOGE("Verify Read permission denied!"); return PermissionState::DENIED; diff --git a/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.h b/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.h index afc4be366277dde2c853057e72e0127593fd7644..69b6ae0a5b4c1eb9694a078dec2137259a2f0466 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/permission_proxy.h @@ -39,10 +39,8 @@ public: }; static bool GetBundleInfo(const std::string &bundleName, uint32_t tokenId, AppExecFwk::BundleInfo &bundleInfo); - static PermissionState QueryWritePermission(uint32_t tokenId, - std::string &permission, const AppExecFwk::BundleInfo &bundleInfo); - static PermissionState QueryReadPermission(uint32_t tokenId, - std::string &permission, const AppExecFwk::BundleInfo &bundleInfo); + static PermissionState QueryWritePermission(uint32_t tokenId, const AppExecFwk::BundleInfo &bundleInfo); + static PermissionState QueryReadPermission(uint32_t tokenId, const AppExecFwk::BundleInfo &bundleInfo); static bool QueryMetaData(const std::string &bundleName, const std::string &storeName, DistributedData::StoreMetaData &metaData, int32_t userId); static std::string GetTableNameByCrossUserMode(const ProfileInfo &profileInfo, diff --git a/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.cpp b/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.cpp index 31e452fc1cc2ec580846c41d11af3494b72957d6..d9916ea62f9ed714ea5e1acc4c6ea3306f352b19 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.cpp @@ -77,7 +77,7 @@ RdbDelegate::RdbDelegate(const StoreMetaData &meta, int &errCode) RdbDelegate::~RdbDelegate() { - ZLOGI("destroy"); + ZLOGD("destroy"); } int64_t RdbDelegate::Insert(const std::string &tableName, const DataShareValuesBucket &valuesBucket) diff --git a/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.h b/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.h index 143d7ae805c50f93b2cd4800cfd7dd5ff77f3875..f26436acb186966ab83ee2613253bfcc13cc10fa 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/rdb_adaptor.h @@ -34,7 +34,7 @@ using StoreMetaData = OHOS::DistributedData::StoreMetaData; using namespace OHOS::NativeRdb; class RdbDelegate { public: - RdbDelegate(const StoreMetaData &data, int &errCode); + RdbDelegate(const StoreMetaData &meta, int &errCode); virtual ~RdbDelegate(); int64_t Insert(const std::string &tableName, const DataShareValuesBucket &valuesBucket); int64_t Update(const std::string &tableName, const DataSharePredicates &predicate, diff --git a/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.cpp b/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.cpp index 96b41176c30420bcc6a9cbf10c7b35fc9025958b..b88ae0ace3047381bd5908cd3d6c29c390e18ccb 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.cpp +++ b/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.cpp @@ -31,32 +31,32 @@ bool URIUtils::GetInfoFromURI(const std::string &uri, UriInfo &uriInfo, bool tab return false; } - uriInfo.bundleName = splitUri[URI_INDEX_BUNLDENAME]; - uriInfo.moduleName = splitUri[URI_INDEX_MODULENAME]; - uriInfo.storeName = splitUri[URI_INDEX_STORENAME]; - if (splitUri.size() > URI_INDEX_MIN) { - uriInfo.tableName = splitUri[URI_INDEX_TABLENAME]; + uriInfo.bundleName = splitUri[BUNDLE_NAME]; + uriInfo.moduleName = splitUri[MODULE_NAME]; + uriInfo.storeName = splitUri[STORE_NAME]; + if (splitUri.size() > OPTIONAL_BEGIN) { + uriInfo.tableName = splitUri[TABLE_NAME]; } return true; } bool URIUtils::IsValidPath(const std::vector &splitUri, bool tableNameEmpty) { - if (splitUri.size() < URI_INDEX_MIN) { + if (splitUri.size() < OPTIONAL_BEGIN) { return false; } - if (splitUri[URI_INDEX_BUNLDENAME].empty() || splitUri[URI_INDEX_MODULENAME].empty() || - splitUri[URI_INDEX_STORENAME].empty()) { + if (splitUri[BUNDLE_NAME].empty() || splitUri[MODULE_NAME].empty() || + splitUri[STORE_NAME].empty()) { ZLOGE("Uri has empty field!"); return false; } if (!tableNameEmpty) { - if (splitUri.size() < URI_INDEX_MAX) { + if (splitUri.size() < PARAM_BUTT) { ZLOGE("Uri need contains tableName"); return false; } - if (splitUri[URI_INDEX_TABLENAME].empty()) { + if (splitUri[TABLE_NAME].empty()) { ZLOGE("Uri tableName can't be empty!"); return false; } diff --git a/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.h b/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.h index 625c45a9056457cb0fbfb21258d4c915dfc275bc..659773b2e71b2b97496e2c15f029836980badb4f 100644 --- a/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.h +++ b/datamgr_service/services/distributeddataservice/service/data_share/uri_utils.h @@ -38,12 +38,14 @@ public: private: static bool IsValidPath(const std::vector &splitUri, bool tableNameEmpty); - static constexpr size_t URI_INDEX_BUNLDENAME = 0; - static constexpr size_t URI_INDEX_MODULENAME = 1; - static constexpr size_t URI_INDEX_STORENAME = 2; - static constexpr size_t URI_INDEX_TABLENAME = 3; - static constexpr size_t URI_INDEX_MIN = 3; - static constexpr size_t URI_INDEX_MAX = 4; + enum PATH_PARAM : int32_t { + BUNDLE_NAME = 0, + MODULE_NAME, + STORE_NAME, + OPTIONAL_BEGIN, + TABLE_NAME = OPTIONAL_BEGIN, + PARAM_BUTT + }; }; } // namespace OHOS::DataShare #endif // DATASHARESERVICE_URI_UTILS_H diff --git a/datamgr_service/services/distributeddataservice/service/directory/src/directory_manager.cpp b/datamgr_service/services/distributeddataservice/service/directory/src/directory_manager.cpp index eba3ef8959f5e574a921e40b9eb9395a716ef18b..bba79049e25fd98a4fab5c5f06464d95d9d9433f 100644 --- a/datamgr_service/services/distributeddataservice/service/directory/src/directory_manager.cpp +++ b/datamgr_service/services/distributeddataservice/service/directory/src/directory_manager.cpp @@ -208,7 +208,7 @@ std::vector DirectoryManager::GetVersions() { std::vector versions; for (size_t i = 0; i < strategies_.size(); ++i) { - versions[i] = strategies_[i].version; + versions.push_back(strategies_[i].version); } return versions; } diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp index 6e19c96a6d5fea542814a9f10e500afaedeaa2b0..a19acff4d936cfaf246114b0b2b5048e6ee193df 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.cpp @@ -39,7 +39,6 @@ #include "utils/anonymous.h" #include "utils/constant.h" #include "utils/converter.h" -#include "utils/crypto.h" namespace OHOS::DistributedKv { using namespace OHOS::DistributedData; using namespace OHOS::AppDistributedKv; @@ -351,36 +350,6 @@ Status KVDBServiceImpl::GetBackupPassword(const AppId &appId, const StoreId &sto return (BackupManager::GetInstance().GetPassWord(metaData, password)) ? SUCCESS : ERROR; } -KVDBService::DevBrief KVDBServiceImpl::GetLocalDevice() -{ - DevBrief brief; - CheckerManager::StoreInfo storeInfo; - storeInfo.tokenId = IPCSkeleton::GetCallingTokenID(); - storeInfo.uid = IPCSkeleton::GetCallingPid(); - auto appId = CheckerManager::GetInstance().GetAppId(storeInfo); - auto device = DMAdapter::GetInstance().GetLocalDevice(); - brief.networkId = std::move(device.networkId); - brief.uuid = Crypto::Sha256(appId + "_" + device.uuid); - return brief; -} - -std::vector KVDBServiceImpl::GetRemoteDevices() -{ - std::vector briefs; - CheckerManager::StoreInfo storeInfo; - storeInfo.tokenId = IPCSkeleton::GetCallingTokenID(); - storeInfo.uid = IPCSkeleton::GetCallingPid(); - auto appId = CheckerManager::GetInstance().GetAppId(storeInfo); - auto devices = DMAdapter::GetInstance().GetRemoteDevices(); - for (const auto &device : devices) { - DevBrief brief; - brief.networkId = std::move(device.networkId); - brief.uuid = Crypto::Sha256(appId + "_" + device.uuid); - briefs.push_back(std::move(brief)); - } - return briefs; -} - Status KVDBServiceImpl::BeforeCreate(const AppId &appId, const StoreId &storeId, const Options &options) { ZLOGD("appId:%{public}s storeId:%{public}s to export data", appId.appId.c_str(), storeId.storeId.c_str()); diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h index 72dddfc472b4dbe3ee883f840d90ae1ad62fbeeb..3cee4848a96b766f2510ed1ff2f5a0e379c31e4a 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_impl.h @@ -53,9 +53,7 @@ public: Status Subscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; Status Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; Status GetBackupPassword(const AppId &appId, const StoreId &storeId, std::vector &password) override; - DevBrief GetLocalDevice() override; - std::vector GetRemoteDevices() override; - + int32_t OnAppExit(pid_t uid, pid_t pid, uint32_t tokenId, const std::string &appId) override; int32_t ResolveAutoLaunch(const std::string &identifier, DBLaunchParam ¶m) override; int32_t OnUserChange(uint32_t code, const std::string &user, const std::string &account) override; diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp index 95e333dc2fd5dae97b6e19c61d104d7b6e689624..61fdde59d2b3d0c3df0b738173138307d6a6a7ec 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.cpp @@ -40,8 +40,6 @@ const KVDBServiceStub::Handler KVDBServiceStub::HANDLERS[TRANS_BUTT] = { &KVDBServiceStub::OnSubscribe, &KVDBServiceStub::OnUnsubscribe, &KVDBServiceStub::OnGetBackupPassword, - &KVDBServiceStub::OnGetLocalDevice, - &KVDBServiceStub::OnGetRemoteDevices, }; int KVDBServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) @@ -61,9 +59,6 @@ int KVDBServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, Message AppId appId; StoreId storeId; - if (TRANS_NO_APPID_BEGIN <= code && code <= TRANS_NO_APPID_END) { - return (this->*HANDLERS[code])(appId, storeId, data, reply); - } if (!ITypesUtil::Unmarshal(data, appId, storeId)) { ZLOGE("Unmarshal appId:%{public}s storeId:%{public}s", appId.appId.c_str(), storeId.storeId.c_str()); return IPC_STUB_INVALID_DATA_ERR; @@ -225,34 +220,6 @@ int32_t KVDBServiceStub::OnGetSyncParam( return ERR_NONE; } -int32_t KVDBServiceStub::OnGetLocalDevice( - const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply) -{ - (void)appId; - (void)storeId; - int32_t status = SUCCESS; - auto brief = GetLocalDevice(); - if (!ITypesUtil::Marshal(reply, status, brief)) { - ZLOGE("Marshal device brief:{%{public}u, %{public}u}", brief.networkId.empty(), brief.uuid.empty()); - return IPC_STUB_WRITE_PARCEL_ERR; - } - return ERR_NONE; -} - -int32_t KVDBServiceStub::OnGetRemoteDevices( - const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply) -{ - (void)appId; - (void)storeId; - int32_t status = SUCCESS; - auto briefs = GetRemoteDevices(); - if (!ITypesUtil::Marshal(reply, status, briefs)) { - ZLOGE("Marshal device brief:%{public}zu", briefs.size()); - return IPC_STUB_WRITE_PARCEL_ERR; - } - return ERR_NONE; -} - int32_t KVDBServiceStub::OnEnableCap( const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply) { diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h index 8b5f8b9003c52b4b4aaa896e5b32d57808e1ef0c..ab0bacc494d2e6df8019b6a077d2e563102f7c99 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/kvdb_service_stub.h @@ -43,8 +43,6 @@ private: int32_t OnSubscribe(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); int32_t OnUnsubscribe(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); int32_t OnGetBackupPassword(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); - int32_t OnGetLocalDevice(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); - int32_t OnGetRemoteDevices(const AppId &appId, const StoreId &storeId, MessageParcel &data, MessageParcel &reply); static const Handler HANDLERS[TRANS_BUTT]; }; } // namespace OHOS::DistributedKv diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.cpp index 8220ef8392ddaf2539a68fadb704301786e3024b..4b662aca45620457c4d08b38704f35ee927f8b3e 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.cpp @@ -20,12 +20,18 @@ #include "crypto_manager.h" #include "metadata/secret_key_meta_data.h" +#include "device_manager_adapter.h" +#include "log_print.h" #include "metadata/meta_data_manager.h" #include "store_cache.h" +#include "accesstoken_kit.h" #include "directory_manager.h" namespace OHOS::DistributedKv { using namespace OHOS::DistributedData; using system_clock = std::chrono::system_clock; +using DMAdapter = DistributedData::DeviceManagerAdapter; +using DBKey = DistributedDB::Key; + Upgrade &Upgrade::GetInstance() { static Upgrade upgrade; @@ -34,6 +40,13 @@ Upgrade &Upgrade::GetInstance() Upgrade::DBStatus Upgrade::UpdateStore(const StoreMeta &old, const StoreMeta &meta, const std::vector &pwd) { + if (old.version < StoreMeta::UUID_CHANGED_TAG && old.storeType == DEVICE_COLLABORATION) { + auto upStatus = Upgrade::GetInstance().UpdateUuid(old, meta, pwd); + if (upStatus != DBStatus::OK) { + return DBStatus::DB_ERROR; + } + } + if (old.dataDir == meta.dataDir) { return DBStatus::OK; } @@ -89,6 +102,28 @@ void Upgrade::UpdatePassword(const StoreMeta &meta, const std::vector & MetaDataManager::GetInstance().SaveMeta(meta.GetSecretKey(), secretKey, true); } +Upgrade::DBStatus Upgrade::UpdateUuid(const StoreMeta &old, const StoreMeta &meta, const std::vector &pwd) +{ + auto kvStore = GetDBStore(meta, pwd); + if (kvStore == nullptr) { + return DBStatus::DB_ERROR; + } + kvStore->RemoveDeviceData(); + auto uuid = GetEncryptedUuidByMeta(meta); + auto dbStatus = kvStore->UpdateKey([uuid](const DBKey &originKey, DBKey &newKey) { + newKey = originKey; + errno_t err = EOK; + err = memcpy_s(newKey.data(), newKey.size(), uuid.data(), uuid.size()); + if (err != EOK) { + ZLOGE("memcpy_s failed, err:%{public}d", err); + } + }); + if (dbStatus != DBStatus::OK) { + ZLOGE("fail to update Uuid, status:%{public}d", dbStatus); + } + return dbStatus; +} + bool Upgrade::RegisterExporter(uint32_t version, Exporter exporter) { (void)version; @@ -117,4 +152,22 @@ Upgrade::AutoStore Upgrade::GetDBStore(const StoreMeta &meta, const std::vector< }); return dbStore; } + +std::string Upgrade::GetEncryptedUuidByMeta(const StoreMeta &meta) +{ + std::string keyUuid = meta.appId + meta.storeId; + if (calcUuid_.Contains(keyUuid)) { + return calcUuid_[keyUuid]; + } + std::string uuid; + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(meta.tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + uuid = DMAdapter::GetInstance().CalcClientUuid(meta.appId, meta.deviceId); + calcUuid_.Insert(keyUuid, uuid); + return uuid; + } + uuid = DMAdapter::GetInstance().CalcClientUuid(" ", meta.deviceId); + calcUuid_.Insert(keyUuid, uuid); + return uuid; +} } \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.h b/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.h index 62644591a6610542ed11e731202490339e9e8d20..b6d83b02d7fcc8b1b20e66c31d15f559f8cd24c0 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/upgrade.h @@ -17,10 +17,13 @@ #define OHOS_DISTRIBUTED_DATA_SERVICE_KVDB_UPGRADE_H #include #include + #include "kv_store_delegate_manager.h" #include "kv_store_nb_delegate.h" #include "metadata/store_meta_data.h" #include "types.h" +#include "concurrent_map.h" + namespace OHOS::DistributedKv { class Upgrade { public: @@ -31,6 +34,7 @@ public: using DBManager = DistributedDB::KvStoreDelegateManager; using Exporter = std::function; using Cleaner = std::function; + API_EXPORT static Upgrade &GetInstance(); API_EXPORT bool RegisterExporter(uint32_t version, Exporter exporter); API_EXPORT bool RegisterCleaner(uint32_t version, Cleaner cleaner); @@ -38,10 +42,14 @@ public: DBStatus UpdateStore(const StoreMeta &old, const StoreMeta &metaData, const std::vector &pwd); DBStatus ExportStore(const StoreMeta &old, const StoreMeta &meta); void UpdatePassword(const StoreMeta &meta, const std::vector &password); + DBStatus UpdateUuid(const StoreMeta &old, const StoreMeta &meta, const std::vector &pwd); + API_EXPORT std::string GetEncryptedUuidByMeta(const StoreMeta &meta); private: using AutoStore = std::unique_ptr>; AutoStore GetDBStore(const StoreMeta &meta, const std::vector &pwd); + ConcurrentMap calcUuid_; + Exporter exporter_; Cleaner cleaner_; }; diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp index 5fbd181433602db4a06f619b54ae46b2abe5151b..ee66bb38c0471c16cc9f2c1ffe26fe40d432caee 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp +++ b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.cpp @@ -53,12 +53,16 @@ std::set UserDelegate::GetLocalUsers() ZLOGE("failed to get local device id"); return {}; } - if (!deviceUserMap_.Contains(deviceId)) { - LoadFromMeta(deviceId); - } std::set users; - deviceUserMap_.ComputeIfPresent(deviceId, [&users](auto&, std::map &value) { - for (auto [user, active] : value) { + deviceUser_.Compute(deviceId, [&users](const auto &key, auto &value) { + if (value.empty()) { + UserMetaData userMetaData; + MetaDataManager::GetInstance().LoadMeta(UserMetaRow::GetKeyFor(key), userMetaData); + for (const auto &user : userMetaData.users) { + value[user.id] = user.isActive; + } + } + for (const auto [user, active] : value) { users.emplace(std::to_string(user)); } return !value.empty(); @@ -78,12 +82,19 @@ std::vector UserDelegate::GetRemoteUserStatus(const std::vector UserDelegate::GetUsers(const std::string &deviceId) { std::vector userStatus; - if (!deviceUserMap_.Contains(deviceId)) { - LoadFromMeta(deviceId); - } - for (const auto &entry : deviceUserMap_[deviceId]) { - userStatus.emplace_back(entry.first, entry.second); - } + deviceUser_.Compute(deviceId, [&userStatus](const auto &key, auto &users) { + if (users.empty()) { + UserMetaData userMetaData; + MetaDataManager::GetInstance().LoadMeta(UserMetaRow::GetKeyFor(key), userMetaData); + for (const auto &user : userMetaData.users) { + users[user.id] = user.isActive; + } + } + for (const auto [key, value] : users) { + userStatus.emplace_back(key, value); + } + return !users.empty(); + }); ZLOGI("device:%{public}s, users:%{public}s", Anonymous::Change(deviceId).c_str(), Serializable::Marshall(userStatus).c_str()); return userStatus; @@ -91,22 +102,20 @@ std::vector UserDelegate::GetUsers(const std::string &deviceId) void UserDelegate::DeleteUsers(const std::string &deviceId) { - deviceUserMap_.Erase(deviceId); + deviceUser_.Erase(deviceId); } void UserDelegate::UpdateUsers(const std::string &deviceId, const std::vector &userStatus) { - ZLOGI("begin, device:%{public}.10s, users:%{public}zu", Anonymous::Change(deviceId).c_str(), userStatus.size()); - deviceUserMap_.Compute(deviceId, [&userStatus](const auto &key, std::map &userMap) { - userMap = {}; - for (auto &user : userStatus) { - userMap[user.id] = user.isActive; + ZLOGI("begin, device:%{public}s, users:%{public}zu", Anonymous::Change(deviceId).c_str(), userStatus.size()); + deviceUser_.Compute(deviceId, [&userStatus](const auto &key, std::map &users) { + users = {}; + for (const auto &user : userStatus) { + users[user.id] = user.isActive; } + ZLOGI("end, device:%{public}s, users:%{public}zu", Anonymous::Change(key).c_str(), users.size()); return true; }); - - ZLOGI("end, device:%{public}s, users:%{public}zu", Anonymous::Change(deviceId).c_str(), - deviceUserMap_[deviceId].size()); } bool UserDelegate::InitLocalUserMeta() @@ -124,25 +133,16 @@ bool UserDelegate::InitLocalUserMeta() UserMetaData userMetaData; userMetaData.deviceId = GetLocalDeviceId(); UpdateUsers(userMetaData.deviceId, userStatus); - for (auto &pair : deviceUserMap_[userMetaData.deviceId]) { - userMetaData.users.emplace_back(pair.first, pair.second); - } - + deviceUser_.ComputeIfPresent(userMetaData.deviceId, [&userMetaData](const auto &, std::map &users) { + for (const auto &[key, value] : users) { + userMetaData.users.emplace_back(key, value); + } + return true; + }); ZLOGI("put user meta data save meta data"); return MetaDataManager::GetInstance().SaveMeta(UserMetaRow::GetKeyFor(userMetaData.deviceId), userMetaData); } -void UserDelegate::LoadFromMeta(const std::string &deviceId) -{ - UserMetaData userMetaData; - MetaDataManager::GetInstance().LoadMeta(UserMetaRow::GetKeyFor(deviceId), userMetaData); - std::map userMap; - for (const auto &user : userMetaData.users) { - userMap[user.id] = user.isActive; - } - deviceUserMap_[deviceId] = userMap; -} - UserDelegate &UserDelegate::GetInstance() { static UserDelegate instance; diff --git a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h index fb3797d63837635d51dff7132e45e5672d0130c9..56dec6c167998f9165c5890868733144bf1ed51f 100644 --- a/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h +++ b/datamgr_service/services/distributeddataservice/service/kvdb/user_delegate.h @@ -56,13 +56,12 @@ private: UserDelegate &userDelegate_; }; std::vector GetUsers(const std::string &deviceId); - void LoadFromMeta(const std::string &deviceId); void UpdateUsers(const std::string &deviceId, const std::vector &userStatus); void DeleteUsers(const std::string &deviceId); bool NotifyUserEvent(const UserEvent &userEvent); // device : { user : isActive } - ConcurrentMap> deviceUserMap_; + ConcurrentMap> deviceUser_; }; } // namespace OHOS::DistributedData diff --git a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp index cf142a29218a95a7e0520839c1a48d98d141feca..9a5281bfed6fb4a1598df12a124a81cf61514e7c 100644 --- a/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/object/object_service_stub.cpp @@ -21,6 +21,7 @@ #include "itypes_util.h" #include "log_print.h" +#include "utils/anonymous.h" namespace OHOS::DistributedObject { using namespace DistributedKv; @@ -32,17 +33,19 @@ int32_t ObjectServiceStub::ObjectStoreSaveOnRemote(MessageParcel &data, MessageP std::map> objectData; sptr obj; if (!ITypesUtil::Unmarshal(data, bundleName, sessionId, deviceId, objectData, obj)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal sessionId:%{public}s bundleName:%{public}s deviceId:%{public}s objectData size:%{public}zu", + DistributedData::Anonymous::Change(sessionId).c_str(), bundleName.c_str(), + DistributedData::Anonymous::Change(deviceId).c_str(), objectData.size()); + return IPC_STUB_INVALID_DATA_ERR; } if (obj == nullptr) { ZLOGW("callback null"); return -1; } int32_t status = ObjectStoreSave(bundleName, sessionId, deviceId, objectData, obj); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("ObjectStoreSaveOnRemote fail %{public}d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } @@ -53,17 +56,18 @@ int32_t ObjectServiceStub::ObjectStoreRevokeSaveOnRemote(MessageParcel &data, Me std::string bundleName; sptr obj; if (!ITypesUtil::Unmarshal(data, bundleName, sessionId, obj)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal sessionId:%{public}s bundleName:%{public}s", + DistributedData::Anonymous::Change(sessionId).c_str(), bundleName.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } if (obj == nullptr) { ZLOGW("callback null"); return -1; } int32_t status = ObjectStoreRevokeSave(bundleName, sessionId, obj); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("ObjectStoreRevokeSaveOnRemote fail %{public}d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } @@ -74,17 +78,18 @@ int32_t ObjectServiceStub::ObjectStoreRetrieveOnRemote(MessageParcel &data, Mess std::string bundleName; sptr obj; if (!ITypesUtil::Unmarshal(data, bundleName, sessionId, obj)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal sessionId:%{public}s bundleName:%{public}s", + DistributedData::Anonymous::Change(sessionId).c_str(), bundleName.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } if (obj == nullptr) { ZLOGW("callback null"); return -1; } int32_t status = ObjectStoreRetrieve(bundleName, sessionId, obj); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("ObjectStoreRetrieveOnRemote fail %{public}d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } @@ -95,17 +100,18 @@ int32_t ObjectServiceStub::OnSubscribeRequest(MessageParcel &data, MessageParcel std::string bundleName; sptr obj; if (!ITypesUtil::Unmarshal(data, bundleName, sessionId, obj)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal sessionId:%{public}s bundleName:%{public}s", + DistributedData::Anonymous::Change(sessionId).c_str(), bundleName.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } if (obj == nullptr) { ZLOGW("callback null"); return -1; } int32_t status = RegisterDataObserver(bundleName, sessionId, obj); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("OnSubscribeRequest fail %{public}d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } @@ -115,13 +121,14 @@ int32_t ObjectServiceStub::OnUnsubscribeRequest(MessageParcel &data, MessageParc std::string sessionId; std::string bundleName; if (!ITypesUtil::Unmarshal(data, bundleName, sessionId)) { - ZLOGW("read device list failed."); - return -1; + ZLOGE("Unmarshal sessionId:%{public}s bundleName:%{public}s", + DistributedData::Anonymous::Change(sessionId).c_str(), bundleName.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } int32_t status = UnregisterDataChangeObserver(bundleName, sessionId); - if (!reply.WriteInt32(static_cast(status))) { - ZLOGE("OnSubscribeRequest fail %{public}d", static_cast(status)); - return -1; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } return 0; } diff --git a/datamgr_service/services/distributeddataservice/service/rdb/irdb_result_set.h b/datamgr_service/services/distributeddataservice/service/rdb/irdb_result_set.h index c2e81993a4759d5f4db8699f8ac24c4095080110..5926784ca349d00e3617fc7f94068dfb254db5e8 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/irdb_result_set.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/irdb_result_set.h @@ -17,10 +17,10 @@ #define DISTRIBUTED_RDB_IRDB_RESULT_SET_H #include "iremote_broker.h" -#include "result_set.h" +#include "remote_result_set.h" namespace OHOS::DistributedRdb { -class IRdbResultSet : public NativeRdb::ResultSet, public IRemoteBroker { +class IRdbResultSet : public NativeRdb::RemoteResultSet, public IRemoteBroker { public: using ColumnType = NativeRdb::ColumnType; virtual ~IRdbResultSet() = default; diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce64900b2ebfbdabfc85119bcae2e88c987db85a --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ +#define LOG_TAG "RdbGeneralStore" +#include "rdb_general_store.h" + +#include "crypto_manager.h" +#include "log_print.h" +#include "metadata/meta_data_manager.h" +#include "metadata/secret_key_meta_data.h" +#include "rdb_helper.h" +#include "relational_store_manager.h" +namespace OHOS::DistributedRdb { +using namespace DistributedData; +using namespace OHOS::NativeRdb; +class RdbOpenCallbackImpl : public RdbOpenCallback { +public: + int OnCreate(RdbStore &rdbStore) override + { + return NativeRdb::E_OK; + } + int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override + { + return NativeRdb::E_OK; + } +}; +RdbGeneralStore::RdbGeneralStore(const StoreMetaData &meta) : manager_(meta.appId, meta.user, meta.instanceId) +{ + DistributedDB::RelationalStoreDelegate::Option option; + if (meta.isEncrypt) { + std::string key = meta.GetSecretKey(); + SecretKeyMetaData secretKeyMeta; + MetaDataManager::GetInstance().LoadMeta(key, secretKeyMeta, true); + std::vector decryptKey; + CryptoManager::GetInstance().Decrypt(secretKeyMeta.sKey, decryptKey); + if (option.passwd.SetValue(decryptKey.data(), decryptKey.size()) != DistributedDB::CipherPassword::OK) { + std::fill(decryptKey.begin(), decryptKey.end(), 0); + } + std::fill(decryptKey.begin(), decryptKey.end(), 0); + option.isEncryptedDb = meta.isEncrypt; + option.iterateTimes = 10000; + option.cipher = DistributedDB::CipherType::AES_256_GCM; + } + option.observer = nullptr; + manager_.OpenStore(meta.dataDir, meta.storeId, option, delegate_); + RdbStoreConfig config(meta.dataDir); + config.SetCreateNecessary(false); + RdbOpenCallbackImpl callback; + int32_t errCode = NativeRdb::E_OK; + store_ = RdbHelper::GetRdbStore(config, meta.version, callback, errCode); + if (errCode != NativeRdb::E_OK) { + ZLOGE("GetRdbStore failed, errCode is %{public}d, storeId is %{public}s", errCode, meta.storeId.c_str()); + } +} + +int32_t RdbGeneralStore::Close() +{ + manager_.CloseStore(delegate_); + delegate_ = nullptr; + store_ = nullptr; + return 0; +} + +int32_t RdbGeneralStore::Execute(const std::string &table, const std::string &sql) +{ + auto ret = store_->ExecuteSql(sql); + if (ret == NativeRdb::E_OK) { + return GeneralError::E_OK; + } + return GeneralError::E_ERROR; +} + +int32_t RdbGeneralStore::BatchInsert(const std::string &table, VBuckets &&values) +{ + std::vector rdbVBucket; + for (auto &bucket : values) { + rdbVBucket.push_back(Convert(std::move(bucket))); + } + int64_t outRowId; + auto ret = store_->BatchInsert(outRowId, table, std::move(rdbVBucket)); + if (ret == NativeRdb::E_OK) { + return GeneralError::E_OK; + } + return GeneralError::E_ERROR; +} + +int32_t RdbGeneralStore::BatchUpdate(const std::string &table, const std::string &sql, VBuckets &&values) +{ + return 0; +} + +int32_t RdbGeneralStore::Delete(const std::string &table, const std::string &sql, Values &&args) +{ + return 0; +} + +std::shared_ptr RdbGeneralStore::Query(const std::string &table, const std::string &sql, Values &&args) +{ + return std::shared_ptr(); +} + +std::shared_ptr RdbGeneralStore::Query(const std::string &table, const GenQuery &query) +{ + return std::shared_ptr(); +} + +int32_t RdbGeneralStore::Watch(int32_t origin, Watcher &watcher) +{ + return 0; +} + +int32_t RdbGeneralStore::Unwatch(int32_t origin, Watcher &watcher) +{ + return 0; +} + +int32_t RdbGeneralStore::Sync(const Devices &devices, int32_t mode, const GenQuery &query, Async async, int32_t wait) +{ + return 0; +} + +NativeRdb::ValuesBucket RdbGeneralStore::Convert(VBucket &&bucket) +{ + ValuesBucket rdbVBucket; + for (auto &[key, value] : bucket) { + rdbVBucket.Put(key, Convert(std::move(value))); + } + return rdbVBucket; +} + +NativeRdb::ValueObject RdbGeneralStore::Convert(Value &&value) +{ + ValueObject rdbValue; + auto *asset = Traits::get_if(&value); + if (asset != nullptr) { + return ConvertAsset(std::move(*asset)); + } + auto *assets = Traits::get_if(&value); + if (assets != nullptr) { + std::vector assetsValue; + for (auto &asset : *assets) { + assetsValue.push_back(ConvertAsset(std::move(asset))); + } + return std::move(assetsValue); + } + + DistributedData::Convert(std::move(value), rdbValue.value); + return rdbValue; +} + +DistributedData::Value RdbGeneralStore::Convert(ValueObject &&rdbValue) +{ + DistributedData::Value value; + auto *rdbAsset = Traits::get_if(&rdbValue.value); + if (rdbAsset != nullptr) { + return ConvertAsset(std::move(*rdbAsset)); + } + auto *rdbAssets = Traits::get_if(&rdbValue.value); + if (rdbAssets != nullptr) { + Assets assets; + for (auto &rdbAsset : *rdbAssets) { + assets.push_back(ConvertAsset(std::move(rdbAsset))); + } + return std::move(assets); + } + DistributedData::Convert(std::move(rdbValue.value), value); + return value; +} + +NativeRdb::AssetValue RdbGeneralStore::ConvertAsset(Asset &&value) +{ + return NativeRdb::AssetValue{ .version = std::move(value.version), + .name = std::move(value.name), + .uri = std::move(value.uri), + .createTime = std::move(value.createTime), + .modifyTime = std::move(value.modifyTime), + .size = std::move(value.size), + .hash = std::move(value.hash) }; +} + +DistributedData::Asset RdbGeneralStore::ConvertAsset(AssetValue &&value) +{ + return DistributedData::Asset{ .version = std::move(value.version), + .name = std::move(value.name), + .uri = std::move(value.uri), + .createTime = std::move(value.createTime), + .modifyTime = std::move(value.modifyTime), + .size = std::move(value.size), + .hash = std::move(value.hash) }; +} +} // namespace OHOS::DistributedRdb diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h new file mode 100644 index 0000000000000000000000000000000000000000..dc7aa0d622dd89b62742e0369d96a91e61ca9a90 --- /dev/null +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_general_store.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_RDB_GENERAL_STORE_H +#define OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_RDB_GENERAL_STORE_H +#include +#include "relational_store_delegate.h" +#include "relational_store_manager.h" + +#include "rdb_store.h" +#include "store/general_store.h" +#include "metadata/store_meta_data.h" +namespace OHOS::DistributedRdb { +class RdbGeneralStore : public DistributedData::GeneralStore { +public: + using Cursor = DistributedData::Cursor; + using GenQuery = DistributedData::GenQuery; + using VBucket = DistributedData::VBucket; + using VBuckets = DistributedData::VBuckets; + using Values = DistributedData::Values; + using StoreMetaData = DistributedData::StoreMetaData; + using RdbStore = OHOS::NativeRdb::RdbStore; + using RdbDelegate = DistributedDB::RelationalStoreDelegate; + using RdbManager = DistributedDB::RelationalStoreManager; + RdbGeneralStore(const StoreMetaData &metaData); + int32_t Close() override; + int32_t Execute(const std::string &table, const std::string &sql) override; + int32_t BatchInsert(const std::string &table, VBuckets &&values) override; + int32_t BatchUpdate(const std::string &table, const std::string &sql, VBuckets &&values) override; + int32_t Delete(const std::string &table, const std::string &sql, Values &&args) override; + std::shared_ptr Query(const std::string &table, const std::string &sql, Values &&args) override; + std::shared_ptr Query(const std::string &table, const GenQuery &query) override; + int32_t Watch(int32_t origin, Watcher &watcher) override; + int32_t Unwatch(int32_t origin, Watcher &watcher) override; + int32_t Sync(const Devices &devices, int32_t mode, const GenQuery &query, Async async, int32_t wait) override; + +private: + NativeRdb::ValuesBucket Convert(DistributedData::VBucket &&bucket); + NativeRdb::ValueObject Convert(DistributedData::Value &&value); + DistributedData::Value Convert(NativeRdb::ValueObject &&rdbValue); + NativeRdb::AssetValue ConvertAsset(DistributedData::Asset &&value); + DistributedData::Asset ConvertAsset(NativeRdb::AssetValue &&value); + + RdbManager manager_; + RdbDelegate *delegate_ = nullptr; + std::shared_ptr store_; +}; +} // namespace OHOS::DistributedRdb +#endif // OHOS_DISTRIBUTED_DATA_DATAMGR_SERVICE_RDB_RDB_GENERAL_STORE_H diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp index 6f7eb43c7717c6889443758082ada79d65d409ed..8f98b6d49ad302a3d287c7b1d8213b6851077d1a 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.cpp @@ -17,16 +17,21 @@ #include "accesstoken_kit.h" #include "account/account_delegate.h" #include "checker/checker_manager.h" +#include "cloud/cloud_event.h" #include "communicator/device_manager_adapter.h" #include "crypto_manager.h" +#include "eventcenter/event_center.h" #include "ipc_skeleton.h" #include "log_print.h" #include "metadata/meta_data_manager.h" #include "metadata/store_meta_data.h" #include "permission/permission_validator.h" #include "rdb_notifier_proxy.h" +#include "store/auto_cache.h" #include "types_export.h" #include "utils/anonymous.h" +#include "cloud/schema_meta.h" +#include "rdb_general_store.h" using OHOS::DistributedKv::AccountDelegate; using OHOS::DistributedData::CheckerManager; using OHOS::DistributedData::MetaDataManager; @@ -41,8 +46,12 @@ namespace OHOS::DistributedRdb { __attribute__((used)) RdbServiceImpl::Factory RdbServiceImpl::factory_; RdbServiceImpl::Factory::Factory() { - FeatureSystem::GetInstance().RegisterCreator("relational_store", - []() { return std::make_shared(); }); + FeatureSystem::GetInstance().RegisterCreator(RdbServiceImpl::SERVICE_NAME, []() { + return std::make_shared(); + }); + AutoCache::GetInstance().RegCreator(RDB_DEVICE_COLLABORATION, [](const StoreMetaData &metaData) -> GeneralStore * { + return new RdbGeneralStore(metaData); + }); } RdbServiceImpl::Factory::~Factory() @@ -77,6 +86,16 @@ RdbServiceImpl::RdbServiceImpl() [this](const std::string& identifier, DistributedDB::AutoLaunchParam ¶m) { return ResolveAutoLaunch(identifier, param); }); + + EventCenter::GetInstance().Subscribe(CloudEvent::NEED_CREATE, [this](const Event &event) { + auto &cloudEvent = static_cast(event); + if (cloudEvent.GetFeatureName() != "relation_store") { + return; + } + DistributedData::SchemaMeta schemaMeta; + MetaDataManager::GetInstance().LoadMeta(cloudEvent.GetSchemaKey(), schemaMeta); + //CreateDatabase(schemaMeta)TODO:根据schema创建表和trigger + }); } int32_t RdbServiceImpl::ResolveAutoLaunch(const std::string &identifier, DistributedDB::AutoLaunchParam ¶m) @@ -136,13 +155,13 @@ void RdbServiceImpl::OnClientDied(pid_t pid) }); } -bool RdbServiceImpl::CheckAccess(const RdbSyncerParam ¶m) +bool RdbServiceImpl::CheckAccess(const std::string& bundleName, const std::string& storeName) { CheckerManager::StoreInfo storeInfo; storeInfo.uid = IPCSkeleton::GetCallingUid(); storeInfo.tokenId = IPCSkeleton::GetCallingTokenID(); - storeInfo.bundleName = param.bundleName_; - storeInfo.storeId = RdbSyncer::RemoveSuffix(param.storeName_); + storeInfo.bundleName = bundleName; + storeInfo.storeId = RdbSyncer::RemoveSuffix(storeName); auto instanceId = RdbSyncer::GetInstIndex(storeInfo.tokenId, storeInfo.bundleName); if (instanceId != 0) { return false; @@ -161,15 +180,18 @@ std::string RdbServiceImpl::ObtainDistributedTableName(const std::string &device return DistributedDB::RelationalStoreManager::GetDistributedTableName(uuid, table); } -int32_t RdbServiceImpl::InitNotifier(const RdbSyncerParam& param, const sptr notifier) +int32_t RdbServiceImpl::InitNotifier(const std::string &bundleName, const sptr ¬ifier) { - if (!CheckAccess(param)) { + if (!CheckAccess(bundleName, "")) { ZLOGE("permission error"); return RDB_ERROR; } - + if (notifier == nullptr) { + ZLOGE("notifier is null"); + return RDB_ERROR; + } pid_t pid = IPCSkeleton::GetCallingPid(); - auto recipient = new(std::nothrow) DeathRecipientImpl([this, pid] { + auto recipient = new (std::nothrow) DeathRecipientImpl([this, pid] { OnClientDied(pid); }); if (recipient == nullptr) { @@ -278,7 +300,7 @@ std::shared_ptr RdbServiceImpl::GetRdbSyncer(const RdbSyncerParam &pa int32_t RdbServiceImpl::SetDistributedTables(const RdbSyncerParam ¶m, const std::vector &tables) { ZLOGI("enter"); - if (!CheckAccess(param)) { + if (!CheckAccess(param.bundleName_, param.storeName_)) { ZLOGE("permission error"); return RDB_ERROR; } @@ -292,7 +314,7 @@ int32_t RdbServiceImpl::SetDistributedTables(const RdbSyncerParam ¶m, const int32_t RdbServiceImpl::DoSync(const RdbSyncerParam ¶m, const SyncOption &option, const RdbPredicates &predicates, SyncResult &result) { - if (!CheckAccess(param)) { + if (!CheckAccess(param.bundleName_, param.storeName_)) { ZLOGE("permission error"); return RDB_ERROR; } @@ -315,7 +337,7 @@ void RdbServiceImpl::OnAsyncComplete(pid_t pid, uint32_t seqNum, const SyncResul int32_t RdbServiceImpl::DoAsync(const RdbSyncerParam ¶m, uint32_t seqNum, const SyncOption &option, const RdbPredicates &predicates) { - if (!CheckAccess(param)) { + if (!CheckAccess(param.bundleName_, param.storeName_)) { ZLOGE("permission error"); return RDB_ERROR; } @@ -325,10 +347,9 @@ int32_t RdbServiceImpl::DoAsync(const RdbSyncerParam ¶m, uint32_t seqNum, co if (syncer == nullptr) { return RDB_ERROR; } - return syncer->DoAsync(option, predicates, - [this, pid, seqNum] (const SyncResult& result) { - OnAsyncComplete(pid, seqNum, result); - }); + return syncer->DoAsync(option, predicates, [this, pid, seqNum](const SyncResult &result) { + OnAsyncComplete(pid, seqNum, result); + }); } std::string RdbServiceImpl::TransferStringToHex(const std::string &origStr) @@ -379,7 +400,7 @@ int32_t RdbServiceImpl::DoUnSubscribe(const RdbSyncerParam& param) int32_t RdbServiceImpl::RemoteQuery(const RdbSyncerParam& param, const std::string& device, const std::string& sql, const std::vector& selectionArgs, sptr& resultSet) { - if (!CheckAccess(param)) { + if (!CheckAccess(param.bundleName_, param.storeName_)) { ZLOGE("permission error"); return RDB_ERROR; } @@ -394,7 +415,7 @@ int32_t RdbServiceImpl::RemoteQuery(const RdbSyncerParam& param, const std::stri int32_t RdbServiceImpl::CreateRDBTable( const RdbSyncerParam ¶m, const std::string &writePermission, const std::string &readPermission) { - if (!CheckAccess(param)) { + if (!CheckAccess(param.bundleName_, param.storeName_)) { ZLOGE("permission error"); return RDB_ERROR; } @@ -422,7 +443,7 @@ int32_t RdbServiceImpl::CreateRDBTable( int32_t RdbServiceImpl::DestroyRDBTable(const RdbSyncerParam ¶m) { - if (!CheckAccess(param)) { + if (!CheckAccess(param.bundleName_, param.storeName_)) { ZLOGE("permission error"); return RDB_ERROR; } @@ -446,4 +467,25 @@ int32_t RdbServiceImpl::DestroyRDBTable(const RdbSyncerParam ¶m) delete syncer; return RDB_OK; } + +int32_t RdbServiceImpl::OnInitialize() +{ + auto tokenId = IPCSkeleton::GetCallingTokenID(); + auto initEvt = std::make_unique(CloudEvent::FEATURE_INIT, tokenId); + EventCenter::GetInstance().PostEvent(std::move(initEvt)); + return RDB_OK; +} + +int32_t RdbServiceImpl::GetSchema(const std::string &bundleName, const std::string &storeName) +{ + if (!CheckAccess(bundleName, storeName)) { + ZLOGE("permission error"); + return RDB_ERROR; + } + auto event = std::make_unique(CloudEvent::GET_SCHEMA, IPCSkeleton::GetCallingTokenID(), + storeName, bundleName); + EventCenter::GetInstance().PostEvent(std::move(event)); + return RDB_OK; +} + } // namespace OHOS::DistributedRdb diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.h index 35f93b7c10ff0be9af32c292b39201bd17f49b0c..b2e32eb2fdb471e14f6284a4f8be4fa149e35c4d 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_impl.h @@ -41,7 +41,7 @@ public: /* IPC interface */ std::string ObtainDistributedTableName(const std::string& device, const std::string& table) override; - int32_t InitNotifier(const RdbSyncerParam& param, const sptr notifier) override; + int32_t InitNotifier(const std::string& bundleName, const sptr ¬ifier) override; int32_t SetDistributedTables(const RdbSyncerParam& param, const std::vector& tables) override; @@ -56,6 +56,10 @@ public: int32_t ResolveAutoLaunch(const std::string &identifier, DistributedDB::AutoLaunchParam ¶m) override; + int32_t OnInitialize() override; + + int32_t GetSchema(const std::string &bundleName, const std::string &storeName) override; + protected: int32_t DoSync(const RdbSyncerParam& param, const SyncOption& option, const RdbPredicates& predicates, SyncResult& result) override; @@ -70,7 +74,7 @@ protected: private: std::string GenIdentifier(const RdbSyncerParam& param); - bool CheckAccess(const RdbSyncerParam& param); + bool CheckAccess(const std::string& bundleName, const std::string& storeName); void SyncerTimeout(std::shared_ptr syncer); diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp index fc8a54726d85534da98269ed891fa1120e6f8d96..85e3719edcef38ee95bcd6735904a84fb99c8491 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.cpp @@ -19,6 +19,7 @@ #include #include "log_print.h" #include "itypes_util.h" +#include "utils/anonymous.h" namespace OHOS::DistributedRdb { int32_t RdbServiceStub::OnRemoteObtainDistributedTableName(MessageParcel &data, MessageParcel &reply) @@ -26,36 +27,48 @@ int32_t RdbServiceStub::OnRemoteObtainDistributedTableName(MessageParcel &data, std::string device; std::string table; if (!ITypesUtil::Unmarshal(data, device, table)) { - ZLOGE("read from message parcel failed"); - reply.WriteString(""); - return RDB_OK; + ZLOGE("Unmarshal device:%{public}s table:%{public}s", DistributedData::Anonymous::Change(device).c_str(), + table.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } - reply.WriteString(ObtainDistributedTableName(device, table)); + std::string distributedTableName = ObtainDistributedTableName(device, table); + if (!ITypesUtil::Marshal(reply, distributedTableName)) { + ZLOGE("Marshal distributedTableName:%{public}s", distributedTableName.c_str()); + return IPC_STUB_WRITE_PARCEL_ERR; + } + return RDB_OK; +} + +int32_t RdbServiceStub::OnGetSchema(MessageParcel &data, MessageParcel &reply) { + std::string bundleName; + std::string storeName; + if (!ITypesUtil::Unmarshal(data, bundleName, storeName)) { + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s", bundleName.c_str(), storeName.c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + auto status = GetSchema(bundleName, storeName); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; + } return RDB_OK; } int32_t RdbServiceStub::OnRemoteInitNotifier(MessageParcel &data, MessageParcel &reply) { - RdbSyncerParam param; + std::string bundleName; sptr notifier; - if (!ITypesUtil::Unmarshal(data, param, notifier)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; - } - if (notifier == nullptr) { - ZLOGE("notifier is null"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; - } - if (InitNotifier(param, notifier) != RDB_OK) { - ZLOGE("init notifier failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; - } - ZLOGI("success"); - reply.WriteInt32(RDB_OK); + if (!ITypesUtil::Unmarshal(data, bundleName, notifier) || bundleName.empty() || notifier == nullptr) { + ZLOGE("Unmarshal bundleName:%{public}s notifier is nullptr:%{public}d", bundleName.c_str(), + notifier == nullptr); + return IPC_STUB_INVALID_DATA_ERR; + } + auto status = InitNotifier(bundleName, notifier); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; + } return RDB_OK; } @@ -64,12 +77,16 @@ int32_t RdbServiceStub::OnRemoteSetDistributedTables(MessageParcel &data, Messag RdbSyncerParam param; std::vector tables; if (!ITypesUtil::Unmarshal(data, param, tables)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s tables size:%{public}zu", + param.bundleName_.c_str(), param.storeName_.c_str(), tables.size()); + return IPC_STUB_INVALID_DATA_ERR; } - reply.WriteInt32(SetDistributedTables(param, tables)); + auto status = SetDistributedTables(param, tables); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; + } return RDB_OK; } @@ -79,19 +96,16 @@ int32_t RdbServiceStub::OnRemoteDoSync(MessageParcel &data, MessageParcel &reply SyncOption option {}; RdbPredicates predicates; if (!ITypesUtil::Unmarshal(data, param, option, predicates)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s tables:%{public}s", param.bundleName_.c_str(), + param.storeName_.c_str(), predicates.table_.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } SyncResult result; - if (DoSync(param, option, predicates, result) != RDB_OK) { - reply.WriteInt32(RDB_ERROR); - return RDB_OK; - } - if (!ITypesUtil::Marshal(reply, result)) { - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + auto status = DoSync(param, option, predicates, result); + if (!ITypesUtil::Marshal(reply, status, result)) { + ZLOGE("Marshal status:0x%{public}x result size:%{public}zu", status, result.size()); + return IPC_STUB_WRITE_PARCEL_ERR; } return RDB_OK; } @@ -103,12 +117,16 @@ int32_t RdbServiceStub::OnRemoteDoAsync(MessageParcel &data, MessageParcel &repl SyncOption option {}; RdbPredicates predicates; if (!ITypesUtil::Unmarshal(data, param, seqNum, option, predicates)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s seqNum:%{public}u tables:%{public}s", + param.bundleName_.c_str(), param.storeName_.c_str(), seqNum, predicates.table_.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } - reply.WriteInt32(DoAsync(param, seqNum, option, predicates)); + auto status = DoAsync(param, seqNum, option, predicates); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; + } return RDB_OK; } @@ -116,11 +134,16 @@ int32_t RdbServiceStub::OnRemoteDoSubscribe(MessageParcel &data, MessageParcel & { RdbSyncerParam param; if (!ITypesUtil::Unmarshal(data, param)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s", param.bundleName_.c_str(), + param.storeName_.c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + + auto status = DoSubscribe(param); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } - reply.WriteInt32(DoSubscribe(param)); return RDB_OK; } @@ -128,11 +151,16 @@ int32_t RdbServiceStub::OnRemoteDoUnSubscribe(MessageParcel &data, MessageParcel { RdbSyncerParam param; if (!ITypesUtil::Unmarshal(data, param)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s", param.bundleName_.c_str(), + param.storeName_.c_str()); + return IPC_STUB_INVALID_DATA_ERR; + } + + auto status = DoUnSubscribe(param); + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } - reply.WriteInt32(DoUnSubscribe(param)); return RDB_OK; } @@ -143,19 +171,19 @@ int32_t RdbServiceStub::OnRemoteDoRemoteQuery(MessageParcel& data, MessageParcel std::string sql; std::vector selectionArgs; if (!ITypesUtil::Unmarshal(data, param, device, sql, selectionArgs)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s device:%{public}s sql:%{public}s " + "selectionArgs size:%{public}zu", param.bundleName_.c_str(), param.storeName_.c_str(), + DistributedData::Anonymous::Change(device).c_str(), + DistributedData::Anonymous::Change(sql).c_str(), selectionArgs.size()); + return IPC_STUB_INVALID_DATA_ERR; } sptr resultSet; - int32_t status = RemoteQuery(param, device, sql, selectionArgs, resultSet); - if (status != RDB_OK) { - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + auto status = RemoteQuery(param, device, sql, selectionArgs, resultSet); + if (!ITypesUtil::Marshal(reply, status, resultSet)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } - reply.WriteInt32(RDB_OK); - reply.WriteRemoteObject(resultSet); return RDB_OK; } @@ -188,17 +216,18 @@ int32_t RdbServiceStub::OnRemoteDoCreateTable(MessageParcel &data, MessageParcel std::string writePermission; std::string readPermission; if (!ITypesUtil::Unmarshal(data, param, writePermission, readPermission)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s writePermission:%{public}s " + "readPermission:%{public}s", param.bundleName_.c_str(), param.storeName_.c_str(), + DistributedData::Anonymous::Change(writePermission).c_str(), + DistributedData::Anonymous::Change(readPermission).c_str()); + return IPC_STUB_INVALID_DATA_ERR; } int32_t status = CreateRDBTable(param, writePermission, readPermission); - if (status != RDB_OK) { - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } - reply.WriteInt32(RDB_OK); return RDB_OK; } @@ -206,17 +235,16 @@ int32_t RdbServiceStub::OnRemoteDoDestroyTable(MessageParcel &data, MessageParce { RdbSyncerParam param; if (!ITypesUtil::Unmarshal(data, param)) { - ZLOGE("read from message parcel failed"); - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + ZLOGE("Unmarshal bundleName_:%{public}s storeName_:%{public}s", param.bundleName_.c_str(), + param.storeName_.c_str()); + return IPC_STUB_INVALID_DATA_ERR; } int32_t status = DestroyRDBTable(param); - if (status != RDB_OK) { - reply.WriteInt32(RDB_ERROR); - return RDB_OK; + if (!ITypesUtil::Marshal(reply, status)) { + ZLOGE("Marshal status:0x%{public}x", status); + return IPC_STUB_WRITE_PARCEL_ERR; } - reply.WriteInt32(RDB_OK); return RDB_OK; } } // namespace OHOS::DistributedRdb diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h index 901a7d6e779d013968eb098a7bba2ddc7b2b5eaf..2e1af17aed3306dd8b07f69440a5e24cf93b5819 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_service_stub.h @@ -50,6 +50,8 @@ private: int32_t OnRemoteObtainDistributedTableName(MessageParcel& data, MessageParcel& reply); + int32_t OnGetSchema(MessageParcel&data, MessageParcel& reply); + int32_t OnRemoteInitNotifier(MessageParcel&data, MessageParcel& reply); int32_t OnRemoteSetDistributedTables(MessageParcel &data, MessageParcel &reply); @@ -79,7 +81,8 @@ private: [RDB_SERVICE_CMD_UNSUBSCRIBE] = &RdbServiceStub::OnRemoteDoUnSubscribe, [RDB_SERVICE_CMD_REMOTE_QUERY] = &RdbServiceStub::OnRemoteDoRemoteQuery, [RDB_SERVICE_CREATE_RDB_TABLE] = &RdbServiceStub::OnRemoteDoCreateTable, - [RDB_SERVICE_DESTROY_RDB_TABLE] = &RdbServiceStub::OnRemoteDoDestroyTable + [RDB_SERVICE_DESTROY_RDB_TABLE] = &RdbServiceStub::OnRemoteDoDestroyTable, + [RDB_SERVICE_CMD_GET_SCHEMA] = &RdbServiceStub::OnGetSchema }; }; } // namespace OHOS::DistributedRdb diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp b/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp index 1bd74d455409bfeaf4e6f6517f0b86e0dc0bac87..3d47af3ef72d9b438b627ab04c4626548e91cd8f 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.cpp @@ -109,9 +109,10 @@ int32_t RdbSyncer::Init( pid_ = pid; uid_ = uid; token_ = token; + StoreMetaData oldMeta; StoreMetaData meta; - if (CreateMetaData(meta) != RDB_OK) { + if (CreateMetaData(meta, oldMeta) != RDB_OK) { ZLOGE("create meta data failed"); return RDB_ERROR; } @@ -119,6 +120,11 @@ int32_t RdbSyncer::Init( ZLOGE("delegate is nullptr"); return RDB_ERROR; } + + if (oldMeta.storeType == RDB_DEVICE_COLLABORATION && oldMeta.version < StoreMetaData::UUID_CHANGED_TAG) { + delegate_->RemoveDeviceData(); + } + ZLOGI("success"); return RDB_OK; } @@ -150,10 +156,9 @@ void RdbSyncer::FillMetaData(StoreMetaData &meta) meta.isEncrypt = param_.isEncrypt_; } -int32_t RdbSyncer::CreateMetaData(StoreMetaData &meta) +int32_t RdbSyncer::CreateMetaData(StoreMetaData &meta, StoreMetaData &old) { FillMetaData(meta); - StoreMetaData old; bool isCreated = MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), old); if (isCreated && (old.storeType != meta.storeType || Constant::NotEqual(old.isEncrypt, meta.isEncrypt) || old.area != meta.area)) { diff --git a/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.h b/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.h index e049a864e218d6584ae00066261f4aba1f0cbbaa..9b5f90b4b6871307f4020d4de2cd0263cfcbec5f 100644 --- a/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.h +++ b/datamgr_service/services/distributeddataservice/service/rdb/rdb_syncer.h @@ -70,7 +70,7 @@ private: std::string GetAppId() const; - int32_t CreateMetaData(StoreMetaData &meta); + int32_t CreateMetaData(StoreMetaData &meta, StoreMetaData &old); void FillMetaData(StoreMetaData &meta); int32_t InitDBDelegate(const StoreMetaData &meta); bool SetSecretKey(const StoreMetaData &meta); diff --git a/datamgr_service/services/distributeddataservice/service/test/BUILD.gn b/datamgr_service/services/distributeddataservice/service/test/BUILD.gn index f334bc90d43ba5ad96ecd1fe19367040d7a32d29..70ad6fddbf99bd05d4b6dbd047e361a6af889c04 100644 --- a/datamgr_service/services/distributeddataservice/service/test/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/service/test/BUILD.gn @@ -29,7 +29,10 @@ config("module_private_config") { "../../framework/include/", ] - defines = [ "TEST_ON_DEVICE" ] + defines = [ + "TEST_ON_DEVICE", + "OPENSSL_SUPPRESS_DEPRECATED", + ] } ohos_unittest("ConfigFactoryTest") { diff --git a/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp b/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp index 6430fac49a239e8694df403b529cb632149f4093..141f065ddd7cf9d1af9b1d4266407911399f7453 100644 --- a/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/config_factory_test.cpp @@ -69,7 +69,7 @@ HWTEST_F(ConfigFactoryTest, ComponentConfig, TestSize.Level0) ASSERT_EQ(config.destructor, ""); ASSERT_EQ(config.params, "{\"count\":1,\"key\":\"value\"}"); const ComponentConfig &cfg = (*components)[1]; - ASSERT_EQ(cfg.lib, "libconfigdemo2.z.so"); + ASSERT_EQ(cfg.lib, "libudmf_server.z.so"); } /** diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp b/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp index 9f7e36472871a3fc4a1840d2f2de8b5c03d321df..87639965c2b44870b3de0d12a3528b3a020bf1a4 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp +++ b/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.cpp @@ -305,5 +305,10 @@ DBStatus DBStoreMock::DeleteBatch(ConcurrentMap &store, const std::v }); return OK; } + +DBStatus DBStoreMock::UpdateKey(const UpdateKeyCallback &callback) +{ + return NOT_SUPPORT; +} } // namespace DistributedData } // namespace OHOS \ No newline at end of file diff --git a/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.h b/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.h index eedd339a4a764acf1cd647bb61b3869ae4538f74..e50def98c4a8d00c89840247d92c8dd87b508343 100644 --- a/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.h +++ b/datamgr_service/services/distributeddataservice/service/test/mock/db_store_mock.h @@ -36,6 +36,7 @@ public: using SecurityOption = DistributedDB::SecurityOption; using RemotePushFinishedNotifier = DistributedDB::RemotePushFinishedNotifier; using PushDataInterceptor = DistributedDB::PushDataInterceptor; + using UpdateKeyCallback = DistributedDB::UpdateKeyCallback; DBStatus Get(const Key &key, Value &value) const override; DBStatus GetEntries(const Key &keyPrefix, std::vector &entries) const override; DBStatus GetEntries(const Key &keyPrefix, KvStoreResultSet *&resultSet) const override; @@ -87,6 +88,7 @@ public: DBStatus RemoveDeviceData() override; DBStatus GetKeys(const Key &keyPrefix, std::vector &keys) const override; size_t GetSyncDataSize(const std::string &device) const override; + DBStatus UpdateKey(const UpdateKeyCallback &callback) override; private: static const uint32_t DEFAULT_SIZE = 0; diff --git a/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn b/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn index 57cdc6839f050e2c4d3e9f2cb73ac7be0e872fb6..d223694029b9c52221fc57e871e4275fc1a37772 100644 --- a/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn +++ b/datamgr_service/services/distributeddataservice/test/fuzztest/schemaquery_fuzzer/BUILD.gn @@ -64,6 +64,7 @@ ohos_fuzztest("SchemaQueryFuzzTest") { "OMIT_FLATBUFFER", "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", + "OPENSSL_SUPPRESS_DEPRECATED", ] external_deps = [ diff --git a/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn b/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn index 70d15988c946b1a414058576e39767fd86dead19..fb3e4402dca8637e48a9dc91c7ef701aa02b0a7a 100644 --- a/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn +++ b/datamgr_service/test/fuzztest/autolaunch_fuzzer/BUILD.gn @@ -78,6 +78,7 @@ ohos_fuzztest("AutoLaunchFuzzTest") { "OMIT_FLATBUFFER", "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn b/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn index fd7b73abb30d29854e495d074a4d6d15003feee8..9ee8840fe0628534ba4f8cfba0ad1cba72e4b125 100644 --- a/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn +++ b/datamgr_service/test/fuzztest/kvstoredisksize_fuzzer/BUILD.gn @@ -79,6 +79,7 @@ ohos_fuzztest("KvStoreDiskSizeFuzzTest") { "OMIT_FLATBUFFER", "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/googletest/.clang-format b/googletest/.clang-format deleted file mode 100644 index 5b9bfe6d224232981ada90cee232c716afbdf09d..0000000000000000000000000000000000000000 --- a/googletest/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ -# Run manually to reformat a file: -# clang-format -i --style=file -Language: Cpp -BasedOnStyle: Google diff --git a/kv_store/frameworks/common/executor.h b/kv_store/frameworks/common/executor.h new file mode 100644 index 0000000000000000000000000000000000000000..91e123e1cc4d5838b2f35c1865b498ea41399f7b --- /dev/null +++ b/kv_store/frameworks/common/executor.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_EXECUTOR_H +#define OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_EXECUTOR_H +#include +#include +#include +#include + +#include "priority_queue.h" +namespace OHOS { + +class Executor : public std::enable_shared_from_this { +public: + using TaskId = uint64_t; + using Task = std::function; + using Duration = std::chrono::steady_clock::duration; + using Time = std::chrono::steady_clock::time_point; + static constexpr Time INVALID_TIME = std::chrono::time_point(); + static constexpr Duration INVALID_INTERVAL = std::chrono::milliseconds(0); + static constexpr uint64_t UNLIMITED_TIMES = std::numeric_limits::max(); + static constexpr Duration INVALID_DELAY = std::chrono::seconds(0); + static constexpr TaskId INVALID_TASK_ID = static_cast(0l); + + enum Status { + RUNNING, + IS_STOPPING, + STOPPED + }; + struct InnerTask { + std::function exec = [](InnerTask innerTask) {}; + Duration interval = INVALID_INTERVAL; + uint64_t times = UNLIMITED_TIMES; + TaskId taskId = INVALID_TASK_ID; + Time startTime = INVALID_TIME; + InnerTask() = default; + + bool Valid() const + { + return taskId != INVALID_TASK_ID; + } + }; + + Executor() + : thread_([this] { + Run(); + thread_.detach(); + self_ = nullptr; + }) + { + } + + void Bind(PriorityQueue *queue, std::function)> idle, + std::function, bool)> release) + { + std::unique_lock lock(mutex_); + self_ = shared_from_this(); + waits_ = queue; + idle_ = std::move(idle); + release_ = std::move(release); + condition_.notify_one(); + } + + void Stop(bool wait = false) + { + { + std::unique_lock lock(mutex_); + running_ = IS_STOPPING; + condition_.notify_one(); + } + if (wait) { + thread_.join(); + } + } + +private: + static constexpr Duration TIME_OUT = std::chrono::seconds(2); + void Run() + { + std::unique_lock lock(mutex_); + do { + do { + condition_.wait(lock, [this] { + return running_ == IS_STOPPING || waits_ != nullptr; + }); + while (running_ == RUNNING && waits_ != nullptr && waits_->Size() > 0) { + auto currentTask = waits_->Pop(); + lock.unlock(); + currentTask.exec(currentTask); + lock.lock(); + waits_->Finish(currentTask.taskId); + } + if (!idle_(self_) && running_ == RUNNING) { + continue; + } + waits_ = nullptr; + } while (running_ == RUNNING && + condition_.wait_until(lock, std::chrono::steady_clock::now() + TIME_OUT, [this]() { + return waits_ != nullptr; + })); + } while (!release_(self_, running_ == IS_STOPPING)); + running_ = STOPPED; + } + + Status running_ = RUNNING; + std::mutex mutex_; + std::condition_variable condition_; + std::shared_ptr self_; + PriorityQueue *waits_ = nullptr; + std::function)> idle_; + std::function, bool)> release_; + std::thread thread_; +}; +} // namespace OHOS +#endif // OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_EXECUTOR_H diff --git a/kv_store/frameworks/common/executor_pool.h b/kv_store/frameworks/common/executor_pool.h new file mode 100644 index 0000000000000000000000000000000000000000..776f893f7cd3fbbb3b1697a645bf9ffb6aca3106 --- /dev/null +++ b/kv_store/frameworks/common/executor_pool.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_EXECUTOR_POOL_H +#define OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_EXECUTOR_POOL_H +#include +#include +#include +#include +#include + +#include "executor.h" +#include "pool.h" +#include "priority_queue.h" +namespace OHOS { +class ExecutorPool { +public: + using TaskId = Executor::TaskId; + using Task = Executor::Task; + using Duration = Executor::Duration; + using Time = Executor::Time; + using InnerTask = Executor::InnerTask; + using Status = Executor::Status; + static constexpr Time INVALID_TIME = std::chrono::time_point(); + static constexpr Duration INVALID_INTERVAL = std::chrono::milliseconds(0); + static constexpr uint64_t UNLIMITED_TIMES = std::numeric_limits::max(); + static constexpr Duration INVALID_DELAY = std::chrono::seconds(0); + static constexpr TaskId INVALID_TASK_ID = static_cast(0l); + + ExecutorPool(size_t max, size_t min) + { + pool_ = new (std::nothrow) Pool(max, min); + execs_ = new PriorityQueue(InnerTask()); + delayTasks_ = new PriorityQueue(InnerTask()); + taskId_ = INVALID_TASK_ID; + } + ~ExecutorPool() + { + poolStatus = Status::IS_STOPPING; + execs_->Clean(); + delayTasks_->Clean(); + std::shared_ptr scheduler; + { + std::lock_guard scheduleLock(mtx_); + scheduler = std::move(scheduler_); + } + if (scheduler != nullptr) { + scheduler->Stop(true); + } + pool_->Clean([](std::shared_ptr executor) { + executor->Stop(true); + }); + delete execs_; + delete delayTasks_; + delete pool_; + poolStatus = Status::STOPPED; + } + + TaskId Execute(Task task) + { + if (poolStatus != Status::RUNNING) { + return INVALID_TASK_ID; + } + auto run = [task](InnerTask innerTask) { + task(); + }; + return Execute(std::move(run), GenTaskId()); + } + + TaskId Execute(Task task, Duration delay) + { + return Schedule(std::move(task), delay, INVALID_INTERVAL, 1); + } + + TaskId Schedule(Task task, Duration interval) + { + return Schedule(std::move(task), INVALID_DELAY, interval, UNLIMITED_TIMES); + } + + TaskId Schedule(Task task, Duration delay, Duration interval) + { + return Schedule(std::move(task), delay, interval, UNLIMITED_TIMES); + } + + TaskId Schedule(Task task, Duration delay, Duration interval, uint64_t times) + { + InnerTask innerTask; + auto run = [task](InnerTask innerTask) { + task(); + }; + innerTask.exec = std::move(run); + innerTask.startTime = std::chrono::steady_clock::now() + delay; + innerTask.interval = interval; + innerTask.times = times; + innerTask.taskId = GenTaskId(); + return Schedule(std::move(innerTask)); + } + + bool Remove(TaskId taskId, bool wait = false) + { + bool res = true; + auto delay = delayTasks_->Find(taskId); + if (!delay.Valid()) { + res = false; + } + delayTasks_->Remove(taskId, wait); + execs_->Remove(taskId, wait); + return res; + } + + TaskId Reset(TaskId taskId, Duration interval) + { + return Reset(taskId, INVALID_DELAY, interval); + } + + TaskId Reset(TaskId taskId, Duration delay, Duration interval) + { + auto innerTask = delayTasks_->Find(taskId); + if (!innerTask.Valid()) { + return INVALID_TASK_ID; + } + delayTasks_->Remove(taskId, false); + auto startTime = std::chrono::steady_clock::now() + delay; + innerTask.startTime = startTime; + innerTask.interval = interval; + delayTasks_->Push(std::move(innerTask), taskId, startTime); + return taskId; + } + +private: + TaskId Execute(std::function task, TaskId taskId) + { + InnerTask innerTask; + innerTask.exec = task; + innerTask.taskId = taskId; + execs_->Push(std::move(innerTask), taskId, INVALID_TIME); + auto executor = pool_->Get(); + if (executor == nullptr) { + return taskId; + } + executor->Bind( + execs_, + [this](std::shared_ptr exe) { + pool_->Idle(exe); + return true; + }, + [this](std::shared_ptr exe, bool force) -> bool { + return pool_->Release(exe, force); + }); + return taskId; + } + + TaskId Schedule(InnerTask innerTask) + { + auto func = innerTask.exec; + auto id = innerTask.taskId; + auto run = [this, func, id](InnerTask task) { + if (task.interval != INVALID_INTERVAL && --task.times > 0) { + task.startTime = std::chrono::steady_clock::now() + task.interval; + delayTasks_->Push(task, task.taskId, task.startTime); + } + Execute(func, id); + }; + innerTask.exec = run; + delayTasks_->Push(innerTask, innerTask.taskId, innerTask.startTime); + std::lock_guard scheduleLock(mtx_); + if (scheduler_ == nullptr) { + scheduler_ = pool_->Get(true); + scheduler_->Bind( + delayTasks_, + [this](std::shared_ptr exe) { + std::unique_lock lock(mtx_); + if (delayTasks_->Size() != 0) { + return false; + } + scheduler_ = nullptr; + pool_->Idle(exe); + return true; + }, + [this](std::shared_ptr exe, bool force) -> bool { + return pool_->Release(exe, force); + }); + } + return innerTask.taskId; + } + + TaskId GenTaskId() + { + auto taskId = ++taskId_; + if (taskId == INVALID_TASK_ID) { + taskId = ++taskId_; + } + return taskId; + } + + Status poolStatus = Status::RUNNING; + std::mutex mtx_; + Pool *pool_; + std::shared_ptr scheduler_ = nullptr; + PriorityQueue *execs_; + PriorityQueue *delayTasks_; + std::atomic taskId_; +}; +} // namespace OHOS + +#endif // OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_EXECUTOR_POOL_H diff --git a/kv_store/frameworks/common/log_print.h b/kv_store/frameworks/common/log_print.h index 717da466ef4e648eaf5f33fe3a2c8135a6bab009..100c5fc42f2623ab164cbfa0ab6ce19ebed20f31 100644 --- a/kv_store/frameworks/common/log_print.h +++ b/kv_store/frameworks/common/log_print.h @@ -42,6 +42,13 @@ static inline OHOS::HiviewDFX::HiLogLabel LogLabel() } } // end namespace DistributedKVStore +namespace CloudData { +static inline OHOS::HiviewDFX::HiLogLabel LogLabel() +{ + return { LOG_CORE, 0xD001613, "CLOUD" }; +} +} // end namespace CloudData + namespace AppDistributedKv { static inline OHOS::HiviewDFX::HiLogLabel LogLabel() { @@ -66,7 +73,7 @@ static inline OHOS::HiviewDFX::HiLogLabel LogLabel() namespace DistributedObject { static inline OHOS::HiviewDFX::HiLogLabel LogLabel() { - return { LOG_CORE, 0xD001654, "DOBJECT" }; + return { LOG_CORE, 0xD001654, "DOBJECT" }; } } // end namespace DistributedObject } // end namespace OHOS @@ -84,7 +91,7 @@ static inline OHOS::HiviewDFX::HiLogLabel LogLabel() OHOS::HiviewDFX::HiLog::Error(LogLabel(), LOG_TAG "::%{public}s: " fmt, __FUNCTION__, ##__VA_ARGS__) #else - #error // unknown system +#error // unknown system #endif #endif // DISTRIBUTEDDATA_LOG_PRINT_H diff --git a/kv_store/frameworks/common/pool.h b/kv_store/frameworks/common/pool.h new file mode 100644 index 0000000000000000000000000000000000000000..3f7619274f2a3a7b41eaec1b0cc9b4bad9c6ef0f --- /dev/null +++ b/kv_store/frameworks/common/pool.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_POOL_H +#define OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_POOL_H +#include +#include +namespace OHOS { +template +class Pool { +public: + Pool(uint32_t capability, uint32_t min) : capability_(capability), min_(min) {} + + std::shared_ptr Get(bool isForce = false) + { + std::unique_lock lock(mutex_); + if (idle_ == nullptr) { + if (!isForce && current_ >= capability_) { + return nullptr; + } + auto cur = new Node(); + idle_ = cur; + current_++; + } + Node *cur = idle_; + idle_ = idle_->next; + if (idle_ == nullptr) { + } + if (idle_ != nullptr) { + idle_->prev = nullptr; + } + cur->next = busy_; + if (busy_ != nullptr) { + cur->prev = busy_->prev; + busy_->prev = cur; + } + busy_ = cur; + return cur->data; + }; + + int32_t Release(std::shared_ptr data, bool force = false) + { + std::unique_lock lock(mutex_); + Node *cur = idle_; + if (!force && current_ <= min_) { + return false; + } + while (cur != nullptr) { + if (cur->data == data) { + if (cur->next != nullptr) { + cur->next->prev = cur->prev; + } + if (cur->prev != nullptr) { + cur->prev->next = cur->next; + } + if (idle_ == cur) { + idle_ = cur->next; + } + current_--; + delete cur; + return true; + } else { + cur = cur->next; + continue; + } + } + return false; + } + + void Idle(std::shared_ptr data) + { + std::unique_lock lock(mutex_); + Node *cur = busy_; + while (cur != nullptr && cur->data != data) { + cur = cur->next; + } + if (cur == nullptr) { + return; + } + if (cur == busy_) { + busy_ = busy_->next; + } + if (cur->next != nullptr) { + cur->next->prev = cur->prev; + } + if (cur->prev != nullptr) { + cur->prev->next = cur->next; + } + cur->prev = nullptr; + cur->next = idle_; + if (idle_ != nullptr) { + idle_->prev = cur; + } + idle_ = cur; + } + + int32_t Clean(std::function)> close) + { + auto temp = min_; + min_ = 0; + while (busy_ != nullptr) { + close(busy_->data); + } + while (idle_ != nullptr) { + close(idle_->data); + } + min_ = temp; + return true; + } + +private: + struct Node { + Node *prev = nullptr; + Node *next = nullptr; + std::shared_ptr data = std::make_shared(); + }; + + uint32_t capability_; + uint32_t min_; + uint32_t current_ = 0; + Node *idle_ = nullptr; + Node *busy_ = nullptr; + std::mutex mutex_; +}; +} // namespace OHOS + +#endif // OHOS_DISTRIBUTED_DATA_KV_STORE_FRAMEWORKS_COMMON_POOL_H diff --git a/kv_store/frameworks/common/priority_queue.h b/kv_store/frameworks/common/priority_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..e1afc5f76d229ab5d7865cf24c5dd0bb9a382f38 --- /dev/null +++ b/kv_store/frameworks/common/priority_queue.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_PRIORITY_QUEUE_H +#define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_PRIORITY_QUEUE_H +#include +#include +#include +#include +#include +#include +namespace OHOS { +template +class PriorityQueue { +public: + struct PQMatrix { + _Tsk task_; + _Tid id_; + PQMatrix(_Tsk task, _Tid id) : task_(task), id_(id) {} + }; + using TskIndex = typename std::map<_Tme, PQMatrix>::iterator; + + PriorityQueue(const _Tsk &task) : INVALID_TSK(std::move(task)) {} + _Tsk Pop() + { + std::unique_lock lock(pqMtx_); + while (!tasks_.empty()) { + if (tasks_.begin()->first > std::chrono::steady_clock::now()) { + popCv_.wait_until(lock, tasks_.begin()->first); + continue; + } + auto temp = tasks_.begin(); + auto id = temp->second.id_; + running.emplace(id); + auto res = std::move(temp->second.task_); + tasks_.erase(temp); + indexes_.erase(id); + return res; + } + return INVALID_TSK; + } + + bool Push(_Tsk tsk, _Tid id, _Tme tme) + { + std::unique_lock lock(pqMtx_); + if (!tsk.Valid()) { + return false; + } + auto temp = tasks_.emplace(tme, PQMatrix(std::move(tsk), id)); + indexes_.emplace(id, temp); + popCv_.notify_all(); + return true; + } + + size_t Size() + { + std::lock_guard lock(pqMtx_); + return tasks_.size(); + } + + _Tsk Find(_Tid id) + { + std::unique_lock lock(pqMtx_); + if (indexes_.find(id) != indexes_.end()) { + return indexes_[id]->second.task_; + } + return INVALID_TSK; + } + + bool Remove(_Tid id, bool wait) + { + std::unique_lock lock(pqMtx_); + removeCv_.wait(lock, [this, id, wait] { + return !wait || running.find(id) == running.end(); + }); + auto index = indexes_.find(id); + if (index == indexes_.end()) { + return false; + } + tasks_.erase(index->second); + indexes_.erase(index); + popCv_.notify_all(); + return true; + } + + void Clean() + { + std::unique_lock lock(pqMtx_); + indexes_.clear(); + tasks_.clear(); + } + + void Finish(_Tid id) + { + std::unique_lock lock(pqMtx_); + running.erase(id); + removeCv_.notify_all(); + } + +private: + const _Tsk INVALID_TSK; + std::mutex pqMtx_; + std::condition_variable popCv_; + std::condition_variable removeCv_; + std::multimap<_Tme, PQMatrix> tasks_; + std::set<_Tid> running; + std::map<_Tid, TskIndex> indexes_; +}; +} // namespace OHOS +#endif //OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_PRIORITY_QUEUE_H diff --git a/kv_store/frameworks/common/task_scheduler.h b/kv_store/frameworks/common/task_scheduler.h index 478fff8e6b0803669dbe992f8603f6fec486a784..dd99e3239a0c9db7ca6c2032dfd233e5a8c0f87d 100644 --- a/kv_store/frameworks/common/task_scheduler.h +++ b/kv_store/frameworks/common/task_scheduler.h @@ -52,7 +52,6 @@ public: } TaskScheduler(const std::string &name) : TaskScheduler(std::numeric_limits::max(), name) {} TaskScheduler(size_t capacity = std::numeric_limits::max()) : TaskScheduler(capacity, "") {} - ~TaskScheduler() { isRunning_ = false; @@ -60,7 +59,6 @@ public: Execute([]() {}); thread_->join(); } - // execute task at specific time TaskId At(const Time &begin, Task task, Duration interval = INVALID_INTERVAL, uint64_t times = UNLIMITED_TIMES) { @@ -80,7 +78,6 @@ public: indexes_[innerTask.taskId] = it; return innerTask.taskId; } - TaskId Reset(TaskId taskId, const Duration &interval) { std::unique_lock lock(mutex_); @@ -88,17 +85,14 @@ public: running_.interval = interval; return running_.taskId; } - auto index = indexes_.find(taskId); if (index == indexes_.end()) { return INVALID_TASK_ID; } - auto &innerTask = index->second->second; if (innerTask.interval != INVALID_INTERVAL) { innerTask.interval = interval; } - auto it = tasks_.insert({ std::chrono::steady_clock::now() + interval, std::move(innerTask) }); if (it == tasks_.begin() || index->second == tasks_.begin()) { condition_.notify_one(); @@ -107,20 +101,17 @@ public: indexes_[taskId] = it; return taskId; } - void Clean() { std::unique_lock lock(mutex_); indexes_.clear(); tasks_.clear(); } - // execute task periodically with duration TaskId Every(Duration interval, Task task) { return At(std::chrono::steady_clock::now() + interval, task, interval); } - // remove task in SchedulerTask void Remove(TaskId taskId, bool wait = false) { @@ -129,31 +120,27 @@ public: return (!wait || running_.taskId != taskId); }); auto index = indexes_.find(taskId); - if (index != indexes_.end()) { + if (index == indexes_.end()) { return; } tasks_.erase(index->second); indexes_.erase(index); condition_.notify_one(); } - // execute task periodically with duration after delay TaskId Every(Duration delay, Duration interval, Task task) { return At(std::chrono::steady_clock::now() + delay, task, interval); } - // execute task for some times periodically with duration after delay TaskId Every(int32_t times, Duration delay, Duration interval, Task task) { return At(std::chrono::steady_clock::now() + delay, task, interval, times); } - TaskId Execute(Task task) { return At(std::chrono::steady_clock::now(), std::move(task)); } - private: struct InnerTask { TaskId taskId = INVALID_TASK_ID; @@ -182,11 +169,9 @@ private: tasks_.erase(it); running_.times--; } - if (exec) { exec(); } - { std::unique_lock lock(mutex_); if (running_.interval != INVALID_INTERVAL && running_.times > 0) { diff --git a/kv_store/frameworks/common/test/concurrent_map_test.cpp b/kv_store/frameworks/common/test/concurrent_map_test.cpp index 0136a8d5e488a24a41cd3940194d22d57f70aee9..0ef31a6870c7600cc4a243710415e6cbe4fa85f0 100644 --- a/kv_store/frameworks/common/test/concurrent_map_test.cpp +++ b/kv_store/frameworks/common/test/concurrent_map_test.cpp @@ -125,4 +125,4 @@ HWTEST_F(ConcurrentMapTest, EmplaceWithArgs, TestSize.Level0) ASSERT_EQ(it.second.name, value.name); ASSERT_EQ(it.second.testCase, value.testCase); } -} \ No newline at end of file +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/frameworks/common/test/lru_bucket_test.cpp b/kv_store/frameworks/common/test/lru_bucket_test.cpp index f0965da8586172e7818bf6ddfa4e350055ce2f7b..50f7dfbf66d9fa366b3ebc75abd896cb9bdb092e 100644 --- a/kv_store/frameworks/common/test/lru_bucket_test.cpp +++ b/kv_store/frameworks/common/test/lru_bucket_test.cpp @@ -17,7 +17,7 @@ #include "lru_bucket.h" #include "gtest/gtest.h" - +namespace OHOS::Test { using namespace testing::ext; template using LRUBucket = OHOS::LRUBucket<_Key, _Tp>; @@ -316,4 +316,5 @@ HWTEST_F(LRUBucketTest, update_several, TestSize.Level0) ASSERT_TRUE(bucket_.Get("test_9", value)); ASSERT_TRUE(bucket_.Get("test_8", value)); ASSERT_TRUE(bucket_.Get("test_7", value)); -} \ No newline at end of file +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/frameworks/common/test/task_scheduler_test.cpp b/kv_store/frameworks/common/test/task_scheduler_test.cpp index 67e27fc266ad991264d9e13c43b6132bc46f9274..e4a1c667e53eabbcbebd8a87f8a0f6091a74b0d0 100644 --- a/kv_store/frameworks/common/test/task_scheduler_test.cpp +++ b/kv_store/frameworks/common/test/task_scheduler_test.cpp @@ -18,14 +18,14 @@ #include #include "block_data.h" - +namespace OHOS::Test { using namespace testing::ext; using namespace OHOS; using duration = std::chrono::steady_clock::duration; class TaskSchedulerTest : public testing::Test { public: - static constexpr uint32_t SHORT_INTERVAL = 100; - static constexpr uint32_t LONG_INTERVAL = 300; + static constexpr uint32_t SHORT_INTERVAL = 100; // ms + static constexpr uint32_t LONG_INTERVAL = 1; // s static void SetUpTestCase(void){}; static void TearDownTestCase(void){}; void SetUp(){}; @@ -62,21 +62,23 @@ HWTEST_F(TaskSchedulerTest, At, TestSize.Level0) /** * @tc.name: Every -* @tc.desc: +* @tc.desc:execute task periodically with duration * @tc.type: FUNC * @tc.require: * @tc.author: ht */ -HWTEST_F(TaskSchedulerTest, Every, TestSize.Level0) +HWTEST_F(TaskSchedulerTest, ExecuteDuration, TestSize.Level0) { TaskScheduler taskScheduler("everyTest"); auto blockData = std::make_shared>(LONG_INTERVAL, 0); - taskScheduler.Every(std::chrono::milliseconds(SHORT_INTERVAL), [blockData]() { - int testData = 1; + int testData = 0; + taskScheduler.Every(std::chrono::milliseconds(SHORT_INTERVAL), [blockData, &testData]() { + testData++; blockData->SetValue(testData); }); - for (int i = 1; i < 5; ++i) { - ASSERT_EQ(blockData->GetValue(), 1); + for (int i = 1; i < 10; ++i) { + ASSERT_EQ(blockData->GetValue(), i); + blockData->Clear(0); } } @@ -151,3 +153,109 @@ HWTEST_F(TaskSchedulerTest, Reset3, TestSize.Level0) auto resetTaskId = taskScheduler.Reset(atTaskId, std::chrono::milliseconds(0)); ASSERT_EQ(resetTaskId, TaskScheduler::INVALID_TASK_ID); } + +/** +* @tc.name: Every +* @tc.desc: execute task for some times periodically with duration. +* @tc.type: FUNC +* @tc.require: +* @tc.author: zuojiangjiang +*/ +HWTEST_F(TaskSchedulerTest, EveryExecuteTimes, TestSize.Level0) +{ + TaskScheduler taskScheduler("everyTimes"); + auto blockData = std::make_shared>(LONG_INTERVAL, 0); + int testData = 0; + int times = 5; + auto taskId = taskScheduler.Every(times, std::chrono::milliseconds(0), + std::chrono::milliseconds(SHORT_INTERVAL), [blockData, times, &testData]() { + testData++; + if (testData < times) { + blockData->Clear(testData); + return; + } + blockData->SetValue(testData); + }); + ASSERT_EQ(blockData->GetValue(), times); + auto resetId = taskScheduler.Reset(taskId, std::chrono::milliseconds(SHORT_INTERVAL)); + ASSERT_EQ(resetId, TaskScheduler::INVALID_TASK_ID); + ASSERT_EQ(blockData->GetValue(), times); +} + +/** +* @tc.name: Remove +* @tc.desc: remove task before execute. +* @tc.type: FUNC +* @tc.require: +* @tc.author: zuojiangjiang +*/ +HWTEST_F(TaskSchedulerTest, RemoveBeforeExecute, TestSize.Level0) +{ + TaskScheduler taskScheduler("RemoveBeforeExecute"); + auto expiredTime = std::chrono::steady_clock::now() + std::chrono::milliseconds(SHORT_INTERVAL); + auto blockData = std::make_shared>(LONG_INTERVAL, 0); + int testData = 0; + auto taskId = taskScheduler.At(expiredTime, [blockData, testData]() { + int tmpData = testData + 1; + blockData->SetValue(tmpData); + }, std::chrono::milliseconds(SHORT_INTERVAL)); + taskScheduler.Remove(taskId); + auto resetId = taskScheduler.Reset(taskId, std::chrono::milliseconds(SHORT_INTERVAL)); + ASSERT_EQ(resetId, TaskScheduler::INVALID_TASK_ID); + ASSERT_EQ(blockData->GetValue(), testData); +} + +/** +* @tc.name: Remove +* @tc.desc: remove task during execute, and waiting. +* @tc.type: FUNC +* @tc.require: +* @tc.author: zuojiangjiang +*/ +HWTEST_F(TaskSchedulerTest, RemoveWaitExecute, TestSize.Level0) +{ + TaskScheduler taskScheduler("RemoveWaitExecute"); + auto expiredTime = std::chrono::steady_clock::now() + std::chrono::milliseconds(0); + auto blockDataTest = std::make_shared>(LONG_INTERVAL, 0); + auto blockDataWait = std::make_shared>(LONG_INTERVAL, 0); + int testData = 1; + auto taskId = taskScheduler.At(expiredTime, [blockDataTest, blockDataWait, &testData]() { + blockDataTest->SetValue(testData); + blockDataWait->GetValue(); + int tmpData = testData + 1; + blockDataTest->SetValue(tmpData); + }, std::chrono::milliseconds(SHORT_INTERVAL)); + ASSERT_EQ(blockDataTest->GetValue(), testData); + auto resetId = taskScheduler.Reset(taskId, std::chrono::milliseconds(SHORT_INTERVAL)); + ASSERT_EQ(taskId, resetId); + taskScheduler.Remove(taskId, true); + ASSERT_EQ(blockDataTest->GetValue(), testData + 1); +} + +/** +* @tc.name: Remove +* @tc.desc: remove task during execute, but no wait. +* @tc.type: FUNC +* @tc.require: +* @tc.author: zuojiangjiang +*/ +HWTEST_F(TaskSchedulerTest, RemoveNoWaitExecute, TestSize.Level0) +{ + TaskScheduler taskScheduler("RemoveNoWaitExecute"); + auto expiredTime = std::chrono::steady_clock::now() + std::chrono::milliseconds(0); + auto blockDataTest = std::make_shared>(LONG_INTERVAL, 0); + auto blockDataWait = std::make_shared>(LONG_INTERVAL, 0); + int testData = 1; + auto taskId = taskScheduler.At(expiredTime, [blockDataTest, blockDataWait, &testData]() { + blockDataTest->SetValue(testData); + blockDataWait->GetValue(); + int tmpData = testData + 1; + blockDataTest->SetValue(tmpData); + }); + ASSERT_EQ(blockDataTest->GetValue(), testData); + blockDataTest->Clear(0); + taskScheduler.Remove(taskId); + blockDataWait->SetValue(testData); + ASSERT_EQ(blockDataTest->GetValue(), testData + 1); +} +} // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/frameworks/common/test/traits_test.cpp b/kv_store/frameworks/common/test/traits_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cbf2625aef0d76f1c2c4c87e7dc5ef833b5010fe --- /dev/null +++ b/kv_store/frameworks/common/test/traits_test.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "traits.h" + +#include +using namespace testing::ext; +namespace OHOS::Test { +class TraitsTest : public testing::Test { +public: + class From { + public: + From() {} + + private: + int64_t id_ = 0; + }; + class Convertible { + public: + Convertible(const From &){}; + Convertible(){} + Convertible(Convertible &&) noexcept {}; + Convertible &operator=(Convertible &&) noexcept + { + return *this; + } + operator From() + { + return From(); + } + private: + int64_t id_ = 1; + }; + static void SetUpTestCase(void){}; + static void TearDownTestCase(void){}; + void SetUp(){}; + void TearDown() {} +}; + +/** +* @tc.name: same_index_of_v +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, same_index_of_v, TestSize.Level0) +{ + auto index = Traits::same_index_of_v>; + ASSERT_EQ(index, 0); + index = Traits::same_index_of_v>; + ASSERT_EQ(index, 3); + index = Traits::same_index_of_v; + ASSERT_EQ(index, 0); +} + +/** +* @tc.name: same_in_v +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, same_in_v, TestSize.Level0) +{ + auto exist = Traits::same_in_v>; + ASSERT_TRUE(exist); + exist = Traits::same_in_v>; + ASSERT_FALSE(exist); + exist = Traits::same_in_v; + ASSERT_FALSE(exist); +} + +/** +* @tc.name: convertible_index_of_v +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, convertible_index_of_v, TestSize.Level0) +{ + auto index = Traits::convertible_index_of_v>; + ASSERT_EQ(index, 0); + index = Traits::convertible_index_of_v>; + ASSERT_EQ(index, 1); + index = Traits::convertible_index_of_v>; + ASSERT_EQ(index, 2); + index = Traits::convertible_index_of_v; + ASSERT_EQ(index, 0); +} + +/** +* @tc.name: convertible_in_v +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, convertible_in_v, TestSize.Level0) +{ + auto convertible = Traits::convertible_in_v>; + ASSERT_TRUE(convertible); + convertible = Traits::convertible_in_v>; + ASSERT_TRUE(convertible); + convertible = Traits::convertible_in_v>; + ASSERT_FALSE(convertible); + convertible = Traits::convertible_in_v; + ASSERT_FALSE(convertible); +} + +/** +* @tc.name: variant_size_of_v +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, variant_size_of_v, TestSize.Level0) +{ + std::variant> value; + auto size = Traits::variant_size_of_v; + ASSERT_EQ(size, 6); + std::variant value2; + size = Traits::variant_size_of_v; + ASSERT_EQ(size, 1); +} + +/** +* @tc.name: variant_index_of_v +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, variant_index_of_v, TestSize.Level0) +{ + std::variant> value; + auto index = Traits::variant_index_of_v; + ASSERT_EQ(index, 0); + index = Traits::variant_index_of_v; + ASSERT_EQ(index, 1); + index = Traits::variant_index_of_v; + ASSERT_EQ(index, 2); + index = Traits::variant_index_of_v; + ASSERT_EQ(index, 3); + index = Traits::variant_index_of_v; + ASSERT_EQ(index, 4); + index = Traits::variant_index_of_v, decltype(value)>; + ASSERT_EQ(index, 5); + index = Traits::variant_index_of_v; + ASSERT_EQ(index, 6); +} + +/** +* @tc.name: get_if_same_type +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, get_if_same_type, TestSize.Level0) +{ + // 1. When the _Tp is a type in the ..._Types, the get_if is equal to the std::get_if. + std::variant value; + auto *nil = Traits::get_if(&value); + ASSERT_NE(nil, nullptr); + auto *number = Traits::get_if(&value); + ASSERT_EQ(number, nullptr); + value = int64_t(1); + number = Traits::get_if(&value); + ASSERT_NE(number, nullptr); + ASSERT_EQ(*number, 1); + value = 1.5; + auto *dVal = Traits::get_if(&value); + ASSERT_NE(dVal, nullptr); + ASSERT_DOUBLE_EQ(*dVal, 1.5); + value = "test case"; + auto *charPtr = Traits::get_if(&value); + ASSERT_NE(charPtr, nullptr); + ASSERT_TRUE(strcmp(*charPtr, "test case") == 0); +} +/** +* @tc.name: get_if_convertible_type +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, get_if_convertible_type, TestSize.Level0) +{ + // 2. When the _Tp is not a type in the ..._Types but someone in the ...Types can convert to _Tp implicitly, + // the get_if will return it. + std::variant value; + value = int64_t(1); + auto *fVal = Traits::get_if(&value); + static_assert(std::is_same_v, "int64_t convert to float implicitly!"); + ASSERT_NE(fVal, nullptr); + ASSERT_EQ(*fVal, 1); + + value = "test case"; + auto *strVal = Traits::get_if(&value); + ASSERT_NE(strVal, nullptr); + ASSERT_TRUE(strcmp(*strVal, "test case") == 0); + + value = From(); + auto *toVal = Traits::get_if(&value); + ASSERT_NE(toVal, nullptr); + + std::variant val2; + val2 = Convertible(); + auto *fromVal = Traits::get_if(&val2); + ASSERT_NE(fromVal, nullptr); +} + +/** +* @tc.name: get_if_invalid_type +* @tc.desc: +* @tc.type: FUNC +* @tc.require: +* @tc.author: Sven Wang +*/ +HWTEST_F(TraitsTest, get_if_invalid_type, TestSize.Level0) +{ + // 3. When the _Tp is not a type in the ..._Types and can't convert, the get_if will return nullptr. + std::variant value; + auto *unknown = Traits::get_if>(&value); + ASSERT_EQ(unknown, nullptr); + value = int64_t(9); + unknown = Traits::get_if>(&value); + ASSERT_EQ(unknown, nullptr); + value = 1.5; + unknown = Traits::get_if>(&value); + ASSERT_EQ(unknown, nullptr); + value = "test case"; + unknown = Traits::get_if>(&value); + ASSERT_EQ(unknown, nullptr); +} +} // namespace OHOS::Test diff --git a/kv_store/frameworks/common/traits.h b/kv_store/frameworks/common/traits.h new file mode 100644 index 0000000000000000000000000000000000000000..26c747305cfd1e5310d12e78ba9b29028415013a --- /dev/null +++ b/kv_store/frameworks/common/traits.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_TRAITS_H +#define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_TRAITS_H +#include +#include +#include +namespace OHOS { +namespace Traits { +template +struct index_of : std::integral_constant {}; + +template +inline constexpr size_t index_of_v = index_of::value; + +template +struct index_of + : std::integral_constant ? 0 : index_of_v + 1> {}; + +// If there is one in the ...Types, that is equal to T. same_index_of_v is the index. +// If there is no one in the ...Types, that is equal to T. same_index_of_v is sizeof ...(Types) +template +inline constexpr size_t same_index_of_v = index_of::value; + +// There is one in the ...Types, that is equal to T. If not, the same_in_v will be false. +template +inline constexpr bool same_in_v = (same_index_of_v < sizeof...(Types)); + +template +struct convertible_index_of : std::integral_constant {}; + +// If there is one in the ...Types that can convert to T implicitly, convertible_index_v is the index. +// If there is no one in the ...Types that can convert to T implicitly, convertible_index_v is sizeof ...(Types) +template +inline constexpr size_t convertible_index_of_v = convertible_index_of::value; + +template +struct convertible_index_of + : std::integral_constant ? 0 : convertible_index_of_v + 1> {}; + +// There is one in the ...Types, that can convert to T implicitly. If not, the convertible_in_v will be false. +template +inline constexpr bool convertible_in_v = (convertible_index_of_v < sizeof...(Types)); + +template +struct variant_size_of { + static constexpr size_t value = sizeof...(Types); +}; + +template +struct variant_index_of { + static constexpr size_t value = same_index_of_v; +}; + +template +variant_size_of variant_size_test(const std::variant &); + +template +variant_index_of variant_index_test(const T &, const std::variant &); + +// variant_index_of_v is the count of the variant V's types. +template +inline constexpr size_t variant_size_of_v = decltype(variant_size_test(std::declval()))::value; + +// If T is one type of the variant V, variant_index_of_v is the index. If not, variant_index_of_v is the size. +template +inline constexpr size_t variant_index_of_v = decltype(variant_index_test(std::declval(), std::declval()))::value; + +/* + * Extend the template std::get_if(variant<_Types...>*) function to support these: + * 1. When the _Tp is a type in the ..._Types, the get_if is equal to the std::get_if. + * 2. When the _Tp is not a type in the ..._Types but someone in the ...Types can convert to _Tp implicitly, + * the get_if will return it. + * 3. When the _Tp is not a type in the ..._Types and can't convert, the get_if will return nullptr. + * */ +template +std::enable_if_t, T *> get_if(std::variant *input) +{ + return std::get_if(input); +} + +template +std::enable_if_t, const T *> get_if(const std::variant *input) +{ + return std::get_if(input); +} + +template ? convertible_index_of_v : 0> +constexpr std::enable_if_t && convertible_in_v, + std::add_pointer_t>>> +get_if(std::variant *input) +{ + return std::get_if(input); +} + +template ? convertible_index_of_v : 0> +constexpr std::enable_if_t && convertible_in_v, + std::add_pointer_t>>> +get_if(const std::variant *input) +{ + return std::get_if(input); +} + +template +std::enable_if_t && !convertible_in_v, T *> get_if(std::variant *input) +{ + (void)input; + return nullptr; +} + +template +std::enable_if_t && !convertible_in_v, const T *> get_if( + const std::variant *input) +{ + (void)input; + return nullptr; +} +} // namespace Traits +} // namespace OHOS +#endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_TRAITS_H diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp index 88d7c69946f2cefc2ca0df48242aa035dd9c33cc..5d7e5e713ce7d2ffa57664bdeef04072ac67458b 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/device_kvstore_test.cpp @@ -236,7 +236,7 @@ HWTEST_F(DeviceKvStoreTest, GetDataQueryEntriesAndResultSet, TestSize.Level1) // prepare 10 size_t sum = 10; - int sumGet = 10; + int sumGet = 0; std::string prefix = "prefix_"; for (size_t i = 0; i < sum; i++) { kvStore_->Put({prefix + std::to_string(i)}, {std::to_string(i)}); diff --git a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp index 4821a1bcfe3a528351bb6ebe7ed0bf67942648b6..e65db8d563a22377ac98dfc71c12089bc806089a 100644 --- a/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/distributeddatafwk/test/unittest/distributed_kv_data_manager_test.cpp @@ -711,18 +711,4 @@ HWTEST_F(DistributedKvDataManagerTest, RegisterKvStoreServiceDeathRecipient001, manager.RegisterKvStoreServiceDeathRecipient(kvStoreDeathRecipient); kvStoreDeathRecipient->OnRemoteDied(); } - -/** -* @tc.name: UnRegisterKvStoreServiceDeathRecipient001 -* @tc.desc: Unregister the callback called when the service dies. -* @tc.type: FUNC -* @tc.require: AR000CQDUS AR000CQDU1 -* @tc.author: liqiao -*/ -HWTEST_F(DistributedKvDataManagerTest, UnRegisterKvStoreServiceDeathRecipient001, TestSize.Level1) -{ - ZLOGI("UnRegisterKvStoreServiceDeathRecipient001 begin."); - std::shared_ptr kvStoreDeathRecipientPtr = std::make_shared(); - manager.UnRegisterKvStoreServiceDeathRecipient(kvStoreDeathRecipientPtr); -} } // namespace OHOS::Test \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/dev_manager.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/dev_manager.h index d04cf321267daa64d14626c85a1a03332d671684..30b18d3371a5abf1e8895e3aad03d45d62a732fa 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/dev_manager.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/dev_manager.h @@ -32,7 +32,7 @@ public: std::string ToUUID(const std::string &networkId); std::string ToNetworkId(const std::string &uuid); const DetailInfo &GetLocalDevice(); - std::vector GetRemoteDevices() const; + std::vector GetRemoteDevices(); class Observer { public: Observer() = default; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h index 74af08fbfad879815cf8eb389cb7c83e11d66a66..c343d06abefc3d02485e90a7f1d801d60b8ff5df 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service.h @@ -63,8 +63,6 @@ public: virtual Status Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) = 0; virtual Status GetBackupPassword( const AppId &appId, const StoreId &storeId, std::vector &password) = 0; - virtual DevBrief GetLocalDevice() = 0; - virtual std::vector GetRemoteDevices() = 0; protected: enum TransId : int32_t { @@ -86,11 +84,7 @@ protected: TRANS_SUB, TRANS_UNSUB, TRANS_GET_PASSWORD, - TRANS_NO_APPID_BEGIN, - TRANS_GET_LOCAL_DEVICE = TRANS_NO_APPID_BEGIN, - TRANS_GET_REMOTE_DEVICES, - TRANS_NO_APPID_END, - TRANS_BUTT = TRANS_NO_APPID_END, + TRANS_BUTT, }; }; } // namespace OHOS::DistributedKv diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h index b38c055a8fc4011af087389df79a9b0335777985..94adb55561963498c423e79cef4042ae73ceb4ce 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/kvdb_service_client.h @@ -48,8 +48,6 @@ public: Status Subscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; Status Unsubscribe(const AppId &appId, const StoreId &storeId, sptr observer) override; Status GetBackupPassword(const AppId &appId, const StoreId &storeId, std::vector &password) override; - DevBrief GetLocalDevice() override; - std::vector GetRemoteDevices() override; sptr GetSyncAgent(const AppId &appId); protected: diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/observer_bridge.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/observer_bridge.h index 1d53bdc821f1c00af62129989a41ebb48ef9cbcf..85991d85f3134100d077ee2499dedcd2c7df1ba5 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/observer_bridge.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/observer_bridge.h @@ -33,6 +33,7 @@ public: Status RegisterRemoteObserver(); Status UnregisterRemoteObserver(); void OnChange(const DBChangedData &data) override; + void OnServiceDeath(); private: class ObserverClient : public KvStoreObserverClient { diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h index 00bfeb3a409b10e431f36d3fba62968080d911e0..87f0ab5eabc158e411c2463db02aaf5c040d7941 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/single_store_impl.h @@ -22,12 +22,15 @@ #include "dev_manager.h" #include "kv_store_nb_delegate.h" #include "kvdb_service.h" +#include "kvstore_death_recipient.h" #include "observer_bridge.h" #include "single_kvstore.h" #include "sync_observer.h" namespace OHOS::DistributedKv { -class SingleStoreImpl : public SingleKvStore, public DevManager::Observer { +class SingleStoreImpl : public SingleKvStore, + public DevManager::Observer, + public KvStoreDeathRecipient { public: using Observer = KvStoreObserver; using SyncCallback = KvStoreSyncCallback; @@ -67,6 +70,7 @@ public: std::map &status) override; void Online(const std::string &device) override; void Offline(const std::string &device) override; + void OnRemoteDied() override; // normal function int32_t Close(bool isForce = false); @@ -99,6 +103,7 @@ private: std::function BridgeReleaser(); Status DoSync(const SyncInfo &syncInfo, std::shared_ptr observer); void DoAutoSync(); + void Register(); bool autoSync_ = false; int32_t ref_ = 1; @@ -111,6 +116,8 @@ private: std::shared_ptr dbStore_ = nullptr; std::shared_ptr syncObserver_ = nullptr; ConcurrentMap>> observers_; + static constexpr int32_t INTERVAL = 500; // ms + uint64_t taskId_ = 0; }; } // namespace OHOS::DistributedKv #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_KVDB_SINGLE_STORE_IMPL_H diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/include/task_executor.h b/kv_store/frameworks/innerkitsimpl/kvdb/include/task_executor.h index 4348b561a47956e85a4fcfab2e2afe67d54e758e..5a10d5df9a96b17e480fc2185f5b3b6ea923772d 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/include/task_executor.h +++ b/kv_store/frameworks/innerkitsimpl/kvdb/include/task_executor.h @@ -20,7 +20,8 @@ namespace OHOS::DistributedKv { class TaskExecutor { public: static TaskExecutor &GetInstance(); - bool Execute(TaskScheduler::Task &&task, int32_t interval = 0); + TaskScheduler::TaskId Execute(TaskScheduler::Task &&task, int32_t interval = 0); + void RemoveTask(TaskScheduler::TaskId taskId); private: TaskExecutor(); diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp index 76199f4b75fb3d2596c8ed79a2dd4caa971d0aee..2644cc25fa7fa489ea19195d0408f943379e8704 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/dev_manager.cpp @@ -24,6 +24,7 @@ #include "task_executor.h" namespace OHOS::DistributedKv { using namespace OHOS::DistributedHardware; +using DevInfo = OHOS::DistributedHardware::DmDeviceInfo; constexpr int32_t DM_OK = 0; constexpr int32_t DM_ERROR = -1; constexpr size_t DevManager::MAX_ID_LEN; @@ -77,7 +78,7 @@ void DmDeathCallback::OnRemoteDied() DevManager::DevManager(const std::string &pkgName) : PKG_NAME(pkgName + PKG_NAME_EX) { - RegisterDevCallback(); +// RegisterDevCallback(); } int32_t DevManager::Init() @@ -163,39 +164,45 @@ const DevManager::DetailInfo &DevManager::GetLocalDevice() if (!localInfo_.uuid.empty()) { return localInfo_; } - auto service = KVDBServiceClient::GetInstance(); - if (service == nullptr) { - ZLOGE("service unavailable"); + DevInfo info; + auto ret = DeviceManager::GetInstance().GetLocalDeviceInfo(PKG_NAME, info); + if (ret != DM_OK) { + ZLOGE("get local device info fail"); return invalidDetail_; } - auto device = service->GetLocalDevice(); - if (device.uuid.empty() || device.networkId.empty()) { + auto networkId = std::string(info.networkId); + std::string uuid; + DeviceManager::GetInstance().GetEncryptedUuidByNetworkId(PKG_NAME, networkId, uuid); + if (uuid.empty() || networkId.empty()) { return invalidDetail_; } - localInfo_.networkId = std::move(device.networkId); - localInfo_.uuid = std::move(device.uuid); - ZLOGI("[LocalDevice] uuid:%{public}s, networkId:%{public}s", - StoreUtil::Anonymous(localInfo_.uuid).c_str(), StoreUtil::Anonymous(localInfo_.networkId).c_str()); + localInfo_.networkId = std::move(networkId); + localInfo_.uuid = std::move(uuid); + ZLOGI("[LocalDevice] uuid:%{public}s, networkId:%{public}s", StoreUtil::Anonymous(localInfo_.uuid).c_str(), + StoreUtil::Anonymous(localInfo_.networkId).c_str()); return localInfo_; } -std::vector DevManager::GetRemoteDevices() const +std::vector DevManager::GetRemoteDevices() { - auto service = KVDBServiceClient::GetInstance(); - if (service == nullptr) { - ZLOGE("service unavailable"); + std::vector dmInfos; + auto ret = DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", dmInfos); + if (ret != DM_OK) { + ZLOGE("get trusted device:%{public}d", ret); return {}; } - auto devices = service->GetRemoteDevices(); - if (devices.empty()) { + if (dmInfos.empty()) { ZLOGD("no remote device"); return {}; } std::vector dtInfos; - for (auto &device : devices) { + for (auto &device : dmInfos) { DetailInfo dtInfo; + auto networkId = std::string(device.networkId); + std::string uuid; + DeviceManager::GetInstance().GetEncryptedUuidByNetworkId(PKG_NAME, networkId, uuid); dtInfo.networkId = std::move(device.networkId); - dtInfo.uuid = std::move(device.uuid); + dtInfo.uuid = std::move(uuid); dtInfos.push_back(dtInfo); } return dtInfos; @@ -215,7 +222,7 @@ void DevManager::Offline(const std::string &networkId) deviceInfos_.Delete(deviceInfo.uuid); } ZLOGI("%{public}s observers:%{public}zu", StoreUtil::Anonymous(networkId).c_str(), observers_.Size()); - observers_.ForEach([&networkId](const auto &key, auto &value) { + observers_.ForEachCopies([&networkId](const auto &key, auto &value) { value->Offline(networkId); return false; }); @@ -230,7 +237,7 @@ void DevManager::OnChanged(const std::string &networkId) void DevManager::OnReady(const std::string &networkId) { ZLOGI("%{public}s observers:%{public}zu", StoreUtil::Anonymous(networkId).c_str(), observers_.Size()); - observers_.ForEach([&networkId](const auto &key, auto &value) { + observers_.ForEachCopies([&networkId](const auto &key, auto &value) { value->Online(networkId); return false; }); diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp index a6279327a86136eb04d8a484836fb0b0b7228ffc..3dcfa4e941a2d35c13421d30e664fdbf7ba1dd93 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/kvdb_service_client.cpp @@ -74,10 +74,15 @@ std::shared_ptr KVDBServiceClient::GetInstance() return nullptr; } - sptr client = iface_cast(service); + sptr client = nullptr; + if (service->IsProxyObject()) { + client = iface_cast(service); + } + if (client == nullptr) { client = new (std::nothrow) KVDBServiceClient(service); } + if (client == nullptr) { return nullptr; } @@ -290,29 +295,6 @@ Status KVDBServiceClient::GetBackupPassword( return static_cast(status); } -KVDBService::DevBrief KVDBServiceClient::GetLocalDevice() -{ - DevBrief brief; - MessageParcel reply; - int32_t status = IPC_SEND(TRANS_GET_LOCAL_DEVICE, reply); - if (status != SUCCESS) { - ZLOGE("status:0x%{public}x", status); - } - ITypesUtil::Unmarshal(reply, brief); - return brief; -} - -std::vector KVDBServiceClient::GetRemoteDevices() -{ - std::vector briefs; - MessageParcel reply; - int32_t status = IPC_SEND(TRANS_GET_REMOTE_DEVICES, reply); - if (status != SUCCESS) { - ZLOGE("status:0x%{public}x", status); - } - ITypesUtil::Unmarshal(reply, briefs); - return briefs; -} sptr KVDBServiceClient::GetSyncAgent(const AppId &appId) { diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/observer_bridge.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/observer_bridge.cpp index 85019f8623ebef3619c4dd56ab56bf8d3c890369..373c8bf57f585ebc72673d90fb81046d70c8453e 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/observer_bridge.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/observer_bridge.cpp @@ -106,4 +106,12 @@ std::vector ObserverBridge::ConvertDB(const T &dbEntries, std::string &de } return entries; } + +void ObserverBridge::OnServiceDeath() +{ + if (remote_ == nullptr) { + return; + } + remote_ = nullptr; +} } // namespace OHOS::DistributedKv diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp index 30825703710cd4e7ae41d35ab61753ded7e737a5..ce279b409c1722f6413870ea31d5f30c65c6339c 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/security_manager.cpp @@ -70,21 +70,23 @@ SecurityManager::DBPassword SecurityManager::GetDBPassword(const std::string &na { DBPassword dbPassword; auto secKey = LoadKeyFromFile(name, path, dbPassword.isKeyOutdated); + std::vector key{}; + if (secKey.empty() && needCreate) { - secKey = Random(KEY_SIZE); - if (!SaveKeyToFile(name, path, secKey)) { + key = Random(KEY_SIZE); + if (!SaveKeyToFile(name, path, key)) { secKey.assign(secKey.size(), 0); + key.assign(key.size(), 0); return dbPassword; } } - std::vector secretKey{}; - if (Decrypt(secKey, secretKey)) { - dbPassword.SetValue(secKey.data(), secKey.size()); + if ((!secKey.empty() && Decrypt(secKey, key)) || !key.empty()) { + dbPassword.SetValue(key.data(), key.size()); } secKey.assign(secKey.size(), 0); - secretKey.assign(secKey.size(), 0); + key.assign(key.size(), 0); return dbPassword; } diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp index e79f8a3835750293ec5232350842715858a69ee2..1ec7e803eebba3323da0b859fbf68ac4fd64820b 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/single_store_impl.cpp @@ -23,6 +23,7 @@ #include "log_print.h" #include "store_result_set.h" #include "store_util.h" +#include "task_executor.h" namespace OHOS::DistributedKv { using namespace OHOS::DistributedDataDfx; using namespace std::chrono; @@ -56,6 +57,9 @@ SingleStoreImpl::~SingleStoreImpl() if (interval_ > 0) { DevManager::GetInstance().Unregister(this); } + if (taskId_ > 0) { + TaskExecutor::GetInstance().RemoveTask(taskId_); + } } StoreId SingleStoreImpl::GetStoreId() const @@ -514,7 +518,7 @@ Status SingleStoreImpl::UnRegisterSyncCallback() Status SingleStoreImpl::SetSyncParam(const KvSyncParam &syncParam) { - DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), true); + DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON); auto service = KVDBServiceClient::GetInstance(); if (service == nullptr) { return SERVER_UNAVAILABLE; @@ -524,7 +528,7 @@ Status SingleStoreImpl::SetSyncParam(const KvSyncParam &syncParam) Status SingleStoreImpl::GetSyncParam(KvSyncParam &syncParam) { - DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), true); + DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON); auto service = KVDBServiceClient::GetInstance(); if (service == nullptr) { return SERVER_UNAVAILABLE; @@ -534,7 +538,7 @@ Status SingleStoreImpl::GetSyncParam(KvSyncParam &syncParam) Status SingleStoreImpl::SetCapabilityEnabled(bool enabled) const { - DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), true); + DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON); auto service = KVDBServiceClient::GetInstance(); if (service == nullptr) { return SERVER_UNAVAILABLE; @@ -548,7 +552,7 @@ Status SingleStoreImpl::SetCapabilityEnabled(bool enabled) const Status SingleStoreImpl::SetCapabilityRange(const std::vector &localLabels, const std::vector &remoteLabels) const { - DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), true); + DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON); auto service = KVDBServiceClient::GetInstance(); if (service == nullptr) { return SERVER_UNAVAILABLE; @@ -558,7 +562,7 @@ Status SingleStoreImpl::SetCapabilityRange(const std::vector &local Status SingleStoreImpl::SubscribeWithQuery(const std::vector &devices, const DataQuery &query) { - DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), true); + DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON); auto service = KVDBServiceClient::GetInstance(); if (service == nullptr) { return SERVER_UNAVAILABLE; @@ -579,7 +583,7 @@ Status SingleStoreImpl::SubscribeWithQuery(const std::vector &devic Status SingleStoreImpl::UnsubscribeWithQuery(const std::vector &devices, const DataQuery &query) { - DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), true); + DdsTrace trace(std::string(LOG_TAG "::") + std::string(__FUNCTION__), TraceSwitch::BYTRACE_ON); auto service = KVDBServiceClient::GetInstance(); if (service == nullptr) { return SERVER_UNAVAILABLE; @@ -814,4 +818,43 @@ void SingleStoreImpl::Online(const std::string &device) void SingleStoreImpl::Offline(const std::string &device) { } + +void SingleStoreImpl::OnRemoteDied() +{ + std::shared_lock lock(rwMutex_); + if (taskId_ > 0) { + return; + } + observers_.ForEach([](const auto &, std::pair> &pair) { + if ((pair.first & SUBSCRIBE_TYPE_REMOTE) == SUBSCRIBE_TYPE_REMOTE) { + pair.second->OnServiceDeath(); + } + return false; + }); + taskId_ = TaskExecutor::GetInstance().Execute([this]() { + Register(); + }, INTERVAL); +} + +void SingleStoreImpl::Register() +{ + std::shared_lock lock(rwMutex_); + Status status = SUCCESS; + observers_.ForEach([&status](const auto &, std::pair> &pair) { + if ((pair.first & SUBSCRIBE_TYPE_REMOTE) == SUBSCRIBE_TYPE_REMOTE) { + status = pair.second->RegisterRemoteObserver(); + if (status != SUCCESS) { + return true; + } + } + return false; + }); + if (status != SUCCESS) { + taskId_ = TaskExecutor::GetInstance().Execute([this]() { + Register(); + }, INTERVAL); + } else { + taskId_ = 0; + } +} } // namespace OHOS::DistributedKv \ No newline at end of file diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp index 2e64222cc0b4d5af1d66a951d6e61ac028be6a1e..2cc33ef617e01c538f0bad3977a3d8a39aa954cf 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/store_factory.cpp @@ -17,6 +17,7 @@ #include "backup_manager.h" #include "device_convertor.h" +#include "kvstore_service_death_notifier.h" #include "log_print.h" #include "security_manager.h" #include "single_store_impl.h" @@ -105,6 +106,7 @@ std::shared_ptr StoreFactory::GetOrOpenStore(const AppId &appId, } isCreate = true; stores[storeId] = kvStore; + KvStoreServiceDeathNotifier::AddServiceDeathWatcher(kvStore); return !stores.empty(); }); return kvStore; @@ -132,6 +134,7 @@ Status StoreFactory::Close(const AppId &appId, const StoreId &storeId, bool isFo status = SUCCESS; auto ref = it->second->Close(isForce); if (ref <= 0) { + KvStoreServiceDeathNotifier::RemoveServiceDeathWatcher(it->second); it = values.erase(it); } else { ++it; diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/src/task_executor.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/src/task_executor.cpp index daec059e57cf20c0947edfb3322d7eae370d9487..fecdeac714a90c744a15dc05e1937c256f1f2d2b 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/src/task_executor.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/src/task_executor.cpp @@ -21,14 +21,21 @@ TaskExecutor &TaskExecutor::GetInstance() return instance; } -bool TaskExecutor::Execute(TaskScheduler::Task &&task, int32_t interval) +TaskScheduler::TaskId TaskExecutor::Execute(TaskScheduler::Task &&task, int32_t interval) { if (pool_ == nullptr) { - return false; + return TaskScheduler::INVALID_TASK_ID; } auto time = TaskScheduler::Clock::now() + std::chrono::milliseconds(interval); - pool_->At(time, std::move(task)); - return true; + return pool_->At(time, std::move(task)); +} + +void TaskExecutor::RemoveTask(TaskScheduler::TaskId taskId) +{ + if (pool_ == nullptr) { + return; + } + pool_->Remove(taskId, true); } TaskExecutor::TaskExecutor() diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp index d71333e178953b481d2db53a402ebf9dbabaf799..0722af98a24386a0ffae0fa346128454c8726d7e 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/single_store_impl_test.cpp @@ -29,13 +29,7 @@ namespace OHOS::Test { std::vector Random(int32_t len) { -// std::random_device randomDevice; -// std::uniform_int_distribution distribution(0, std::numeric_limits::max()); - std::vector key(len, 'a'); -// for (int32_t i = 0; i < len; i++) { -// key[i] = static_cast(distribution(randomDevice)); -// } - return key; + return std::vector(len, 'a'); } class SingleStoreImplTest : public testing::Test { @@ -921,7 +915,7 @@ HWTEST_F(SingleStoreImplTest, MaxLogSizeTest002, TestSize.Level0) auto status = kvStore_->GetResultSet({ "" }, output); ASSERT_EQ(status, SUCCESS); ASSERT_NE(output, nullptr); - ASSERT_GT(output->GetCount(), 0); + ASSERT_EQ(output->GetCount(), 3); EXPECT_EQ(output->MoveToFirst(), true); /** * @tc.steps:step3. Put more data into the database. diff --git a/kv_store/frameworks/innerkitsimpl/kvdb/test/store_factory_test.cpp b/kv_store/frameworks/innerkitsimpl/kvdb/test/store_factory_test.cpp index 8c96694ec5785c30f8d7c258dc0e0d4be52d65a1..7a14167bd700a81a0a790857ff15e5ef2f10a29a 100644 --- a/kv_store/frameworks/innerkitsimpl/kvdb/test/store_factory_test.cpp +++ b/kv_store/frameworks/innerkitsimpl/kvdb/test/store_factory_test.cpp @@ -66,9 +66,13 @@ public: static void DeleteKVStore(); }; -void StoreFactoryTest::SetUpTestCase(void){} +void StoreFactoryTest::SetUpTestCase(void) +{ +} -void StoreFactoryTest::TearDownTestCase(void){} +void StoreFactoryTest::TearDownTestCase(void) +{ +} void StoreFactoryTest::SetUp(void) { diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp index d41f0cc400112cd9f679ac4247aa9795dcbfc9dd..a69f8c7a4cf6e54796ad1af4b866a64e55a8b943 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp +++ b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_device_kv_store.cpp @@ -286,6 +286,8 @@ napi_value JsDeviceKVStore::GetResultSet(napi_env env, napi_callback_info info) ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; CHECK_STATUS_RETURN_VOID(ctxt, "kvStore->GetResultSet() failed!"); ctxt->resultSet->SetNative(kvResultSet); + bool isSchema = reinterpret_cast(ctxt->native)->IsSchemaStore(); + ctxt->resultSet->SetSchema(isSchema); }; auto output = [env, ctxt](napi_value& result) { ctxt->status = napi_get_reference_value(env, ctxt->ref, &result); diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_kv_manager.cpp b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_kv_manager.cpp index defda843f92eca28866887e651fcf8a229ddbc93..ff9d3027bb53fd480094940767f04ba6934f5ef6 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_kv_manager.cpp +++ b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_kv_manager.cpp @@ -152,6 +152,7 @@ napi_value JsKVManager::GetKVStore(napi_env env, napi_callback_info info) CHECK_STATUS_RETURN_VOID(ctxt, "output get ref value failed"); ctxt->status = napi_delete_reference(env, ctxt->ref); CHECK_STATUS_RETURN_VOID(ctxt, "output del ref failed"); + ZLOGI("output del ref success"); }; return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); } diff --git a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_single_kv_store.cpp b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_single_kv_store.cpp index 504b3eb7ad9b58be0ba83b777859cad79688b23c..bf01fe487c7fbe5d5bc405a8e505ee7861e4b8fb 100644 --- a/kv_store/frameworks/jskitsimpl/distributeddata/src/js_single_kv_store.cpp +++ b/kv_store/frameworks/jskitsimpl/distributeddata/src/js_single_kv_store.cpp @@ -236,6 +236,8 @@ napi_value JsSingleKVStore::GetResultSet(napi_env env, napi_callback_info info) ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; CHECK_STATUS_RETURN_VOID(ctxt, "kvStore->GetResultSet() failed!"); ctxt->resultSet->SetNative(kvResultSet); + bool isSchema = reinterpret_cast(ctxt->native)->IsSchemaStore(); + ctxt->resultSet->SetSchema(isSchema); }; auto output = [env, ctxt](napi_value& result) { ctxt->status = napi_get_reference_value(env, ctxt->ref, &result); diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_device_kv_store.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_device_kv_store.cpp index 829be592596ad1ac0b18c3e6711140ce3e3a0387..c3ea9f58220922e7cf9be0737b08fc8e41d4e1e0 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_device_kv_store.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_device_kv_store.cpp @@ -54,6 +54,8 @@ napi_value JsDeviceKVStore::Constructor(napi_env env) DECLARE_NAPI_FUNCTION("rollback", JsSingleKVStore::Rollback), DECLARE_NAPI_FUNCTION("enableSync", JsSingleKVStore::EnableSync), DECLARE_NAPI_FUNCTION("setSyncRange", JsSingleKVStore::SetSyncRange), + DECLARE_NAPI_FUNCTION("backup", JsSingleKVStore::Backup), + DECLARE_NAPI_FUNCTION("restore", JsSingleKVStore::Restore), /* JsDeviceKVStore externs JsSingleKVStore */ DECLARE_NAPI_FUNCTION("get", JsDeviceKVStore::Get), DECLARE_NAPI_FUNCTION("getEntries", JsDeviceKVStore::GetEntries), @@ -252,6 +254,8 @@ napi_value JsDeviceKVStore::GetResultSet(napi_env env, napi_callback_info info) ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; ctxt->resultSet->SetKvStoreResultSetPtr(kvResultSet); + bool isSchema = reinterpret_cast(ctxt->native)->IsSchemaStore(); + ctxt->resultSet->SetSchema(isSchema); }; auto output = [env, ctxt](napi_value& result) { ctxt->status = napi_get_reference_value(env, ctxt->ref, &result); diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_error_utils.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_error_utils.cpp index 7904735dc4f8cd0a5f3d38f4811d8925096c2377..2e3f5031b854fbd645e17d2a833b9f0459e5ab3a 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_error_utils.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_error_utils.cpp @@ -30,8 +30,9 @@ static constexpr JsErrorCode JS_ERROR_CODE_MSGS[] = { { Status::STORE_META_CHANGED, 15100002, "Open existed database with changed options." }, { Status::PERMISSION_DENIED, 202, "Permission denied" }, { Status::CRYPT_ERROR, 15100003, "Database corrupted." }, - { Status::OVER_MAX_LIMITS, 15100001, "Over max subscribe limits." }, + { Status::OVER_MAX_LIMITS, 15100001, "Over max limits." }, { Status::ALREADY_CLOSED, 15100005, "Database or result set already closed." }, + { Status::WAL_OVER_LIMITS, 14800047, "the WAL file size exceeds the default limit."} }; const std::optional GetJsErrorCode(int32_t errorCode) diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp index 4870603c7a8b89d5a103471ff8930fcad61ce51a..091f131e3b74250a18edaf8711875927506ea0ad 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_kv_manager.cpp @@ -159,6 +159,7 @@ napi_value JsKVManager::GetKVStore(napi_env env, napi_callback_info info) ctxt->status = napi_get_reference_value(env, ctxt->ref, &result); napi_delete_reference(env, ctxt->ref); ASSERT_STATUS(ctxt, "output KVManager failed"); + ZLOGI("output delete reference success"); }; return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output); } @@ -327,7 +328,6 @@ napi_value JsKVManager::Off(napi_env env, napi_callback_info info) auto ctxt = std::make_shared(); auto input = [env, ctxt](size_t argc, napi_value* argv) { // required 1 or 2 arguments :: [callback] - // ASSERT_ARGS(ctxt, (argc == 1) || (argc == 2), "invalid arguments!"); ASSERT_BUSINESS_ERR(ctxt, argc > 0, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); std::string event; ctxt->status = JSUtil::GetValue(env, argv[0], event); diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp index 138bab26b842ab694ebb8eb0a55b672e41de5d3c..8320919f5e1c02d38892882e4e8550b81e65dadf 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_single_kv_store.cpp @@ -1008,6 +1008,8 @@ napi_value JsSingleKVStore::GetResultSet(napi_env env, napi_callback_info info) ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure; ctxt->resultSet->SetKvStoreResultSetPtr(kvResultSet); + bool isSchema = reinterpret_cast(ctxt->native)->IsSchemaStore(); + ctxt->resultSet->SetSchema(isSchema); }; auto output = [env, ctxt](napi_value& result) { ctxt->status = napi_get_reference_value(env, ctxt->ref, &result); diff --git a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_util.cpp b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_util.cpp index d293e93b60eed3bd25b6c50e68dfab58707a4e48..4ce4e13c00c50b45aba268615d8b3ea0ea7bc96b 100644 --- a/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_util.cpp +++ b/kv_store/frameworks/jskitsimpl/distributedkvstore/src/js_util.cpp @@ -310,7 +310,7 @@ JSUtil::StatusMsg JSUtil::SetValue(napi_env env, const JSUtil::KvStoreVariant& i return SetValue(env, *dblValue, out); } - ZLOGE("napi_value <- KvStoreVariant INVALID value type"); + ZLOGE("napi_value <- KvStoreVariant INVALID value type"); return napi_invalid_arg; } diff --git a/kv_store/frameworks/libs/distributeddb/BUILD.gn b/kv_store/frameworks/libs/distributeddb/BUILD.gn index 7f8451d22a52f46c64a493485da64749a2d9330e..cf7b051d032f60b02289d4bb5227c5405439caf2 100644 --- a/kv_store/frameworks/libs/distributeddb/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/BUILD.gn @@ -50,6 +50,7 @@ config("distrdb_config") { "SQLITE_DISTRIBUTE_RELATIONAL", "USE_DFX_ABILITY", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] if (is_debug) { defines += [ "TRACE_SQLITE_EXECUTE" ] diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_common.h b/kv_store/frameworks/libs/distributeddb/common/include/db_common.h index c43981059ebe737f0813b855f8228775b63971c8..24217cd5615fb54eb27a20e4e3ee640f138c39fd 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_common.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_common.h @@ -60,6 +60,13 @@ public: static std::string GetDistributedTableName(const std::string &device, const std::string &tableName); + static std::string GetDistributedTableName(const std::string &device, const std::string &tableName, + const StoreInfo &info); + + static std::string GetDistributedTableNameWithHash(const std::string &device, const std::string &tableName); + + static std::string CalDistributedTableName(const std::string &device, const std::string &tableName); + static void GetDeviceFromName(const std::string &deviceTableName, std::string &deviceHash, std::string &tableName); static std::string TrimSpace(const std::string &input); diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h b/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h index 928a08655105c6315c9eea4c8cce428fb7881f42..e593bd3feab17e0d9a923e55c2ebf5e36b9f326d 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_constant.h @@ -159,6 +159,8 @@ public: static constexpr uint32_t MAX_CONDITION_COUNT = 32; static constexpr uint32_t REMOTE_QUERY_MAX_SQL_LEN = 1000000U; + + static constexpr int HASH_KEY_SIZE = 32; // size of SHA256_DIGEST_LENGTH }; } // namespace DistributedDB #endif // DISTRIBUTEDDB_CONSTANT_H diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h b/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h index 13a1098cc42bb0be2f621e2ca2ea7c388aa3a787..716689d2652ab10f6a73cca1417cfb162809b175 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_errno.h @@ -125,6 +125,7 @@ constexpr int E_NONEXISTENT = (E_BASE + 103); // for result set, nonexistent in constexpr int E_TYPE_MISMATCH = (E_BASE + 104); // for result set, mismatch type constexpr int E_DENIED_SQL = (E_BASE + 105); // denied sql, not permit to execute constexpr int E_USER_CHANGE = (E_BASE + 106); // user change +constexpr int E_CONSTRAINT = (E_BASE + 107); // sql failed with constraint // Num 150+ is reserved for schema related errno, since it may be added regularly constexpr int E_JSON_PARSE_FAIL = (E_BASE + 150); // Parse json fail in grammatical level constexpr int E_JSON_INSERT_PATH_EXIST = (E_BASE + 151); // Path already exist before insert diff --git a/kv_store/frameworks/libs/distributeddb/common/include/db_types.h b/kv_store/frameworks/libs/distributeddb/common/include/db_types.h index e553ddcb55c000d060e6846c50e02bacbbe1995c..6b836a6fccc7b92afc9385a7033405a53740fe0e 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/db_types.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/db_types.h @@ -157,8 +157,8 @@ enum DistributedTableMode : int { struct CaseInsensitiveComparator { bool operator() (const std::string& first, const std::string& second) const { - std::string str1(first.length(),' '); - std::string str2(second.length(),' '); + std::string str1(first.length(), ' '); + std::string str2(second.length(), ' '); std::transform(first.begin(), first.end(), str1.begin(), tolower); std::transform(second.begin(), second.end(), str2.begin(), tolower); return str1 < str2; diff --git a/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h b/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h index 856c5b31d8a09a284f806dc1356d8dbf79adb08d..115ba70666a4636c591a5dafb1ccaf67b3dd7163 100644 --- a/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h +++ b/kv_store/frameworks/libs/distributeddb/common/include/runtime_context.h @@ -141,6 +141,13 @@ public: virtual void StopTaskPool() = 0; virtual void StopTimeTickMonitorIfNeed() = 0; + + virtual void SetTranslateToDeviceIdCallback(const TranslateToDeviceIdCallback &callback) = 0; + + virtual int TranslateDeviceId(const std::string &deviceId, + const StoreInfo &info, std::string &newDeviceId) = 0; + + virtual bool ExistTranslateDevIdCallback() const = 0; protected: RuntimeContext() = default; virtual ~RuntimeContext() {} diff --git a/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp b/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp index da7c4e6fb58261575c907578094221d979154200..cb0b47454c09f9a40a080aacf3079e7c6dbb4bfa 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/auto_launch.cpp @@ -34,6 +34,7 @@ namespace DistributedDB { namespace { constexpr int MAX_AUTO_LAUNCH_ITEM_NUM = 8; + const char *AUTO_LAUNCH_ID = "AutoLaunchID"; } void AutoLaunch::SetCommunicatorAggregator(ICommunicatorAggregator *aggregator) @@ -1029,6 +1030,7 @@ int AutoLaunch::GetAutoLaunchRelationProperties(const AutoLaunchParam ¶m, } propertiesPtr->SetCipherArgs(param.option.cipher, param.option.passwd, param.option.iterateTimes); } + propertiesPtr->SetIntProp(AUTO_LAUNCH_ID, static_cast(RuntimeContext::GetInstance()->GenerateSessionId())); return E_OK; } @@ -1296,14 +1298,26 @@ void AutoLaunch::CloseConnection(DBType type, const DBProperties &properties) return; } std::string identifier = properties.GetStringProp(DBProperties::IDENTIFIER_DATA, ""); - std::lock_guard lock(dataLock_); + int closeId = properties.GetIntProp(AUTO_LAUNCH_ID, 0); + std::lock_guard lock(extLock_); auto itemMapIter = extItemMap_.find(identifier); if (itemMapIter == extItemMap_.end()) { + LOGD("[AutoLaunch] Abort close because not found id"); return; } std::string userId = properties.GetStringProp(DBProperties::USER_ID, ""); auto itemIter = itemMapIter->second.find(userId); if (itemIter == itemMapIter->second.end()) { + LOGD("[AutoLaunch] Abort close because not found user id"); + return; + } + if (itemIter->second.propertiesPtr == nullptr) { + LOGD("[AutoLaunch] Abort close because properties is invalid"); + return; + } + int targetId = itemIter->second.propertiesPtr->GetIntProp(AUTO_LAUNCH_ID, 0); + if (closeId != targetId) { + LOGD("[AutoLaunch] Abort close because connection has been closed"); return; } TryCloseConnection(itemIter->second); diff --git a/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp b/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp index 99fc897dcbb66b061a7e7a2a8aa2fbf05c10fc65..6ac0ad91f034b09053fa79cf391633908caf4cd1 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/data_value.cpp @@ -175,7 +175,7 @@ DataValue &DataValue::operator=(const Blob &blob) int DataValue::Set(Blob *&blob) { ResetValue(); - if (blob == nullptr || blob->GetSize() <= 0) { + if (blob == nullptr || blob->GetSize() < 0) { LOGE("Transfer Blob to DataValue failed."); return -E_INVALID_ARGS; } @@ -257,7 +257,7 @@ int DataValue::GetBlob(Blob *&outVal) const int DataValue::SetBlob(const Blob &val) { ResetValue(); - if (val.GetSize() <= 0) { + if (val.GetSize() < 0) { return E_OK; } value_.blobPtr = new(std::nothrow) Blob(); diff --git a/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp b/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp index 74bf012ffaf9064336b1b15c1bf5cd472689ffbf..ee39d9cedcd74294b3e431652efdf935959921ba 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/db_common.cpp @@ -21,6 +21,7 @@ #include "db_errno.h" #include "platform_specific.h" #include "hash.h" +#include "runtime_context.h" #include "value_hash_calc.h" namespace DistributedDB { @@ -321,9 +322,32 @@ std::string DBCommon::StringMasking(const std::string &oriStr, size_t remain) } std::string DBCommon::GetDistributedTableName(const std::string &device, const std::string &tableName) +{ + if (!RuntimeContext::GetInstance()->ExistTranslateDevIdCallback()) { + return GetDistributedTableNameWithHash(device, tableName); + } + return CalDistributedTableName(device, tableName); +} + +std::string DBCommon::GetDistributedTableName(const std::string &device, const std::string &tableName, + const StoreInfo &info) +{ + std::string newDeviceId; + if (RuntimeContext::GetInstance()->TranslateDeviceId(device, info, newDeviceId) != E_OK) { + return GetDistributedTableNameWithHash(device, tableName); + } + return CalDistributedTableName(newDeviceId, tableName); +} + +std::string DBCommon::GetDistributedTableNameWithHash(const std::string &device, const std::string &tableName) { std::string deviceHashHex = DBCommon::TransferStringToHex(DBCommon::TransferHashString(device)); - return DBConstant::RELATIONAL_PREFIX + tableName + "_" + deviceHashHex; + return CalDistributedTableName(deviceHashHex, tableName); +} + +std::string DBCommon::CalDistributedTableName(const std::string &device, const std::string &tableName) +{ + return DBConstant::RELATIONAL_PREFIX + tableName + "_" + device; } void DBCommon::GetDeviceFromName(const std::string &deviceTableName, std::string &deviceHash, std::string &tableName) diff --git a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp index 9fe505aa41dd5af6ae16ea68e7ec21f56e917241..dd39f1db68463996f5fc3ab3fdbf6b44239a962a 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.cpp @@ -14,6 +14,7 @@ */ #include "runtime_context_impl.h" +#include "db_common.h" #include "db_errno.h" #include "db_dfx_adapter.h" #include "log_print.h" @@ -746,4 +747,33 @@ void RuntimeContextImpl::StopTimeTickMonitorIfNeed() timeTickMonitor_ = nullptr; } } + +void RuntimeContextImpl::SetTranslateToDeviceIdCallback(const TranslateToDeviceIdCallback &callback) +{ + std::lock_guard autoLock(translateToDeviceIdLock_); + translateToDeviceIdCallback_ = callback; + deviceIdCache_.clear(); +} + +int RuntimeContextImpl::TranslateDeviceId(const std::string &deviceId, + const StoreInfo &info, std::string &newDeviceId) +{ + const std::string id = DBCommon::GenerateIdentifierId(info.storeId, info.appId, info.userId); + std::lock_guard autoLock(translateToDeviceIdLock_); + if (translateToDeviceIdCallback_ == nullptr) { + return -E_NOT_SUPPORT; + } + if (deviceIdCache_.find(deviceId) == deviceIdCache_.end() || + deviceIdCache_[deviceId].find(id) == deviceIdCache_[deviceId].end()) { + deviceIdCache_[deviceId][id] = translateToDeviceIdCallback_(deviceId, info); + } + newDeviceId = deviceIdCache_[deviceId][id]; + return E_OK; +} + +bool RuntimeContextImpl::ExistTranslateDevIdCallback() const +{ + std::lock_guard autoLock(translateToDeviceIdLock_); + return translateToDeviceIdCallback_ != nullptr; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h index 62b9ce623c790f949af7c6b026006c2e9b50c8c1..6ed8218b4957e5a8da478b7dce96287920a33296 100644 --- a/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h +++ b/kv_store/frameworks/libs/distributeddb/common/src/runtime_context_impl.h @@ -130,6 +130,12 @@ public: void StopTimeTickMonitorIfNeed() override; + void SetTranslateToDeviceIdCallback(const TranslateToDeviceIdCallback &callback) override; + + int TranslateDeviceId(const std::string &deviceId, + const StoreInfo &info, std::string &newDeviceId) override; + + bool ExistTranslateDevIdCallback() const override; private: static constexpr int MAX_TP_THREADS = 10; // max threads of the task pool. static constexpr int MIN_TP_THREADS = 1; // min threads of the task pool. @@ -192,6 +198,10 @@ private: // Get map from this callback, use for run permission check in remote device mutable std::shared_mutex permissionConditionLock_; PermissionConditionCallback permissionConditionCallback_; + + mutable std::mutex translateToDeviceIdLock_; + TranslateToDeviceIdCallback translateToDeviceIdCallback_; + std::map> deviceIdCache_; // cache > }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp index 3cb9f9aab447e1014d37bdebba8e481af0ac4e28..4f8427e1aecfd8f3558c77c43ebec03c2fa12261 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/communicator_aggregator.cpp @@ -405,6 +405,17 @@ void CommunicatorAggregator::SendPacketsAndDisposeTask(const SendTask &inTask, break; } } + if (errCode == -E_WAIT_RETRY) { + const int RETRY_INTERVAL = 1000; + TimerId timerId = 0u; + const std::string target = inTask.dstTarget; + RefObject::IncObjRef(this); + errCode = RuntimeContext::GetInstance()->SetTimer(RETRY_INTERVAL, [this, target](TimerId id) { + OnSendable(target); + RefObject::DecObjRef(this); + return -E_END_TIMER; + }, nullptr, timerId); + } if (taskNeedFinalize) { TaskFinalizer(inTask, errCode); } diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp index 921a3732fab62fb3521053ccc1a4c16545239038..849bae8450ab65b1378b30ed26417c41ecd3c63f 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/network_adapter.cpp @@ -214,6 +214,10 @@ int NetworkAdapter::SendBytes(const std::string &dstTarget, const uint8_t *bytes DeviceInfos dstDevInfo; dstDevInfo.identifier = dstTarget; DBStatus errCode = processCommunicator_->SendData(dstDevInfo, bytes, length); + if (errCode == DBStatus::RATE_LIMIT) { + LOGD("[NAdapt][SendBytes] rate limit!"); + return -E_WAIT_RETRY; + } if (errCode != DBStatus::OK) { LOGE("[NAdapt][SendBytes] SendData Fail, errCode=%d.", static_cast(errCode)); // These code is compensation for the probable defect of IProcessCommunicator implementation. diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp b/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp index 5268d29109c9b47f1a1e378230089daa48c45c3c..4fce91dbdf500b8d9cedecaffb0949d00fc8e1af 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.cpp @@ -15,6 +15,7 @@ #include "protocol_proto.h" #include +#include #include #include "db_common.h" #include "endian_convert.h" @@ -60,6 +61,7 @@ FrameType GetFrameType(uint8_t inPacketType) } std::map ProtocolProto::msgIdMapFunc_; +std::shared_mutex ProtocolProto::msgIdMutex_; uint32_t ProtocolProto::GetAppLayerFrameHeaderLength() { @@ -366,6 +368,7 @@ int ProtocolProto::CombinePacketIntoFrame(SerialBuffer *inFrame, const uint8_t * int ProtocolProto::RegTransformFunction(uint32_t msgId, const TransformFunc &inFunc) { + std::unique_lock autoLock(msgIdMutex_); if (msgIdMapFunc_.count(msgId) != 0) { return -E_ALREADY_REGISTER; } @@ -378,6 +381,7 @@ int ProtocolProto::RegTransformFunction(uint32_t msgId, const TransformFunc &inF void ProtocolProto::UnRegTransformFunction(uint32_t msgId) { + std::unique_lock autoLock(msgIdMutex_); if (msgIdMapFunc_.count(msgId) != 0) { msgIdMapFunc_.erase(msgId); } @@ -582,12 +586,12 @@ int ProtocolProto::CalculateXorSum(const uint8_t *bytes, uint32_t length, uint64 int ProtocolProto::CalculateDataSerializeLength(const Message *inMsg, uint32_t &outLength) { uint32_t messageId = inMsg->GetMessageId(); - if (msgIdMapFunc_.count(messageId) == 0) { + TransformFunc function; + if (GetTransformFunc(messageId, function) != E_OK) { LOGE("[Proto][CalcuDataSerialLen] Not registered for messageId=%" PRIu32 ".", messageId); return -E_NOT_REGISTER; } - TransformFunc function = msgIdMapFunc_[messageId]; uint32_t serializeLen = function.computeFunc(inMsg); uint32_t alignedLen = BYTE_8_ALIGN(serializeLen); // Currently not allowed the upper module to send a message without data. Regard serializeLen zero as abnormal. @@ -625,8 +629,11 @@ int ProtocolProto::SerializeMessage(SerialBuffer *inBuff, const Message *inMsg) return E_OK; } // If dataLen not zero, the TransformFunc of this messageId must exist, the caller's logic guarantee it - uint32_t messageId = inMsg->GetMessageId(); - TransformFunc function = msgIdMapFunc_[messageId]; + TransformFunc function; + if (GetTransformFunc(inMsg->GetMessageId(), function) != E_OK) { + LOGE("[Proto][Serialize] Not register, messageId=%" PRIu32 ".", inMsg->GetMessageId()); + return -E_NOT_REGISTER; + } int result = function.serializeFunc(payloadByteLen.first + sizeof(MessageHeader), dataLen, inMsg); if (result != E_OK) { LOGE("[Proto][Serialize] SerializeFunc Fail, result=%d.", result); @@ -674,12 +681,11 @@ int ProtocolProto::DeSerializeMessage(const SerialBuffer *inBuff, Message *inMsg if (onlyMsgHeader || dataLen == 0) { // Do not need to deserialize data return E_OK; } - uint32_t messageId = inMsg->GetMessageId(); - if (msgIdMapFunc_.count(messageId) == 0) { - LOGE("[Proto][DeSerialize] Not register, messageId=%" PRIu32 ".", messageId); + TransformFunc function; + if (GetTransformFunc(inMsg->GetMessageId(), function) != E_OK) { + LOGE("[Proto][DeSerialize] Not register, messageId=%" PRIu32 ".", inMsg->GetMessageId()); return -E_NOT_REGISTER; } - TransformFunc function = msgIdMapFunc_[messageId]; int result = function.deserializeFunc(payloadByteLen.first + sizeof(MessageHeader), dataLen, inMsg); if (result != E_OK) { LOGE("[Proto][DeSerialize] DeserializeFunc Fail, result=%d.", result); @@ -723,11 +729,6 @@ int ProtocolProto::ParseCommPhyHeaderCheckMagicAndVersion(const uint8_t *bytes, int ProtocolProto::ParseCommPhyHeaderCheckField(const std::string &srcTarget, const CommPhyHeader &phyHeader, const uint8_t *bytes, uint32_t length) { - if (phyHeader.sourceId != Hash::HashFunc(srcTarget)) { - LOGE("[Proto][ParsePhyCheck] SourceId Error: inSourceId=%" PRIu64 ", srcTarget=%s{private}, hashId=%" PRIu64, - ULL(phyHeader.sourceId), srcTarget.c_str(), ULL(Hash::HashFunc(srcTarget))); - return -E_PARSE_FAIL; - } if (phyHeader.packetLen != length) { LOGE("[Proto][ParsePhyCheck] PacketLen=%" PRIu32 " Mismatch length=%" PRIu32 ".", phyHeader.packetLen, length); return -E_PARSE_FAIL; @@ -1092,4 +1093,15 @@ int ProtocolProto::FillExtendHeadDataIfNeed(std::shared_ptr } return E_OK; } + +int ProtocolProto::GetTransformFunc(uint32_t messageId, DistributedDB::TransformFunc &function) +{ + std::shared_lock autoLock(msgIdMutex_); + const auto &entry = msgIdMapFunc_.find(messageId); + if (entry == msgIdMapFunc_.end()) { + return -E_NOT_REGISTER; + } + function = entry->second; + return E_OK; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.h b/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.h index c5f7e0918c1703daf5207438a40dfce3934e231f..f151f0a609d7c265eccc20571dfcad7cc9891bb9 100644 --- a/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.h +++ b/kv_store/frameworks/libs/distributeddb/communicator/src/protocol_proto.h @@ -18,6 +18,7 @@ #include #include +#include #include "communicator_type_define.h" #include "frame_header.h" #include "iprocess_communicator.h" @@ -130,6 +131,9 @@ private: static int FillExtendHeadDataIfNeed(std::shared_ptr &extendHandle, SerialBuffer *buffer, uint32_t headSize); + static int GetTransformFunc(uint32_t messageId, TransformFunc &function); + + static std::shared_mutex msgIdMutex_; static std::map msgIdMapFunc_; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/distributeddb.gni b/kv_store/frameworks/libs/distributeddb/distributeddb.gni index a6e2c5880ccdd3891ed347fe6161c90bf4fead57..87c4b4666ea329c58d51d746d4f1911dc52017b6 100644 --- a/kv_store/frameworks/libs/distributeddb/distributeddb.gni +++ b/kv_store/frameworks/libs/distributeddb/distributeddb.gni @@ -145,6 +145,7 @@ distributeddb_src = [ "${distributeddb_path}/storage/src/sqlite/sqlite_local_storage_engine.cpp", "${distributeddb_path}/storage/src/sqlite/sqlite_local_storage_executor.cpp", "${distributeddb_path}/storage/src/sqlite/sqlite_log_table_manager.cpp", + "${distributeddb_path}/storage/src/sqlite/sqlite_meta_executor.cpp", "${distributeddb_path}/storage/src/sqlite/sqlite_multi_ver_data_storage.cpp", "${distributeddb_path}/storage/src/sqlite/sqlite_multi_ver_transaction.cpp", "${distributeddb_path}/storage/src/sqlite/sqlite_query_helper.cpp", diff --git a/kv_store/frameworks/libs/distributeddb/include/types_export.h b/kv_store/frameworks/libs/distributeddb/include/types_export.h index 95adef5e899bf4cd490bb5625d14b6aaee63837d..9772f2a8837ccffeedd1d1f5e13b72641bcf8c3e 100644 --- a/kv_store/frameworks/libs/distributeddb/include/types_export.h +++ b/kv_store/frameworks/libs/distributeddb/include/types_export.h @@ -206,5 +206,12 @@ enum class CompressAlgorithm : uint8_t { NONE = 0, ZLIB = 1 }; + +struct StoreInfo { + std::string userId; + std::string appId; + std::string storeId; +}; +using TranslateToDeviceIdCallback = std::function; } // namespace DistributedDB #endif // DISTRIBUTEDDB_TYPES_EXPORT_H diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h index 21a112187afa4849d6db44b17519a3964384cdab..453aea705e8d1ad7343b1e2f7091a03e2f1af7ba 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/kv_store_nb_delegate.h @@ -227,6 +227,9 @@ public: // calculate full sync sync data size after Serialize; // return 1M while sync data size is larger than 1M, otherwise return actualy size DB_API virtual size_t GetSyncDataSize(const std::string &device) const = 0; + + // update all key in sync_data which is not deleted data + DB_API virtual DBStatus UpdateKey(const UpdateKeyCallback &callback) = 0; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h index 9bb6f38e5adc133f04e81e764f1dc2ea91911226..3405f055bf5096516f454fcfb0b29be32a295406 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/relational/relational_store_delegate.h @@ -50,6 +50,9 @@ public: // timeout is in ms. DB_API virtual DBStatus RemoteQuery(const std::string &device, const RemoteCondition &condition, uint64_t timeout, std::shared_ptr &result) = 0; + + // remove all device data + DB_API virtual DBStatus RemoveDeviceData() = 0; }; } // namespace DistributedDB #endif // RELATIONAL_STORE_DELEGATE_H \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h index 1386e47410a2c220dd423ac0530e390acbc01b23..5bbd98fb13c1b825931285357e0f219f6230f8a4 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/runtime_config.h @@ -50,6 +50,7 @@ public: DB_API static bool IsProcessSystemApiAdapterValid(); + DB_API static void SetTranslateToDeviceIdCallback(const TranslateToDeviceIdCallback &callback); private: static std::mutex communicatorMutex_; static std::mutex multiUserMutex_; diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h b/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h index 1fc0b12eddcd3f3c8245e74b18285b65a34751b0..21f693edb4174206d3bea19e921849d555f846bf 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/include/store_types.h @@ -65,6 +65,9 @@ enum DBStatus { NONEXISTENT, // for row record, pass invalid column name or invalid column index. TYPE_MISMATCH, // for row record, get value with mismatch func. REMOTE_OVER_SIZE, // for remote query, the data is too many, only get part or data. + RATE_LIMIT, + DATA_HANDLE_ERROR, // remote handle data failed + CONSTRAINT, // constraint check failed in sqlite }; struct KvStoreConfig { @@ -128,5 +131,7 @@ struct RemoteCondition { std::string sql; // The sql statement; std::vector bindArgs; // The bind args. }; + +using UpdateKeyCallback = std::function; } // namespace DistributedDB #endif // KV_STORE_TYPE_H diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp index 3128f46fc2a5b942accc6bf8bf3fd1fff39df2ff..94305280fd2c80fdf55ec0c274d13e5e5f57070b 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_errno.cpp @@ -66,6 +66,7 @@ namespace { { -E_FEEDBACK_UNKNOWN_MESSAGE, NOT_SUPPORT }, { -E_NOT_PERMIT, PERMISSION_CHECK_FORBID_SYNC }, { -E_REMOTE_OVER_SIZE, OVER_MAX_LIMITS }, + { -E_CONSTRAINT, CONSTRAINT }, }; } diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp index 4f45317896c7ecaebd90eb8436f11ea3c94c3c02..9a8f477202621ece9458b724f2c7f5cf759acb72 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.cpp @@ -974,4 +974,22 @@ size_t KvStoreNbDelegateImpl::GetSyncDataSize(const std::string &device) const } return size; } + +DBStatus KvStoreNbDelegateImpl::UpdateKey(const UpdateKeyCallback &callback) +{ + if (conn_ == nullptr) { + LOGE("%s", INVALID_CONNECTION); + return DB_ERROR; + } + if (callback == nullptr) { + return INVALID_ARGS; + } + int errCode = conn_->UpdateKey(callback); + if (errCode == E_OK) { + LOGI("[KvStoreNbDelegate] update keys success"); + return OK; + } + LOGW("[KvStoreNbDelegate] update keys failed:%d", errCode); + return TransferDBErrno(errCode); +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h index 7ca51a31e59980327498285ae4c00f0306cb3011..24d7c5d8923dc4cd1e30a20ed3203e0986f1e812 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/kv_store_nb_delegate_impl.h @@ -156,6 +156,8 @@ public: size_t GetSyncDataSize(const std::string &device) const override; + // update all key in sync_data which is not deleted data + DBStatus UpdateKey(const UpdateKeyCallback &callback) override; private: DBStatus GetInner(const IOption &option, const Key &key, Value &value) const; DBStatus PutInner(const IOption &option, const Key &key, const Value &value); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp index 714364dac3e3f551f568e7307647659cf5fd27fa..02a18d3daa43e5827ea4150019b5bb7f2db54d54 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.cpp @@ -160,5 +160,20 @@ DBStatus RelationalStoreDelegateImpl::RemoteQuery(const std::string &device, con } return OK; } + +DBStatus RelationalStoreDelegateImpl::RemoveDeviceData() +{ + if (conn_ == nullptr) { + LOGE("Invalid connection for operation!"); + return DB_ERROR; + } + + int errCode = conn_->RemoveDeviceData(); + if (errCode != E_OK) { + LOGW("[RelationalStore Delegate] remove device data failed:%d", errCode); + return TransferDBErrno(errCode); + } + return OK; +} } // namespace DistributedDB #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h index 508bd94540bd3cc612a51d610f389da3e6d83e60..a5a2a7373fcbf3ceecbf51859a753fbb4072e566 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_delegate_impl.h @@ -46,6 +46,8 @@ public: DBStatus RemoteQuery(const std::string &device, const RemoteCondition &condition, uint64_t timeout, std::shared_ptr &result) override; + DBStatus RemoveDeviceData() override; + private: static void OnSyncComplete(const std::map> &devicesStatus, const SyncStatusCallback &onComplete); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp index 84ca3ba52802bd3c2105709ddab5e5f3296c397d..c3dd979f65be57e9413d5c4aaf72eafd9e31ec01 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/relational/relational_store_manager.cpp @@ -133,7 +133,7 @@ DBStatus RelationalStoreManager::CloseStore(RelationalStoreDelegate *store) std::string RelationalStoreManager::GetDistributedTableName(const std::string &device, const std::string &tableName) { - if (device.empty() || tableName.empty()) { + if ((!RuntimeContext::GetInstance()->ExistTranslateDevIdCallback() && device.empty()) || tableName.empty()) { return {}; } return DBCommon::GetDistributedTableName(device, tableName); diff --git a/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp b/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp index 1dbabc517ce0724c432cb55d1798f5bf1ef2a2bd..d55b996e4551b80903079a302f19c64c956c5c66 100644 --- a/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp +++ b/kv_store/frameworks/libs/distributeddb/interfaces/src/runtime_config.cpp @@ -128,5 +128,10 @@ DBStatus RuntimeConfig::SetPermissionConditionCallback(const PermissionCondition int errCode = RuntimeContext::GetInstance()->SetPermissionConditionCallback(callback); return TransferDBErrno(errCode); } + +void RuntimeConfig::SetTranslateToDeviceIdCallback(const DistributedDB::TranslateToDeviceIdCallback &callback) +{ + RuntimeContext::GetInstance()->SetTranslateToDeviceIdCallback(callback); +} } // namespace DistributedDB #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/ikvdb_connection.h b/kv_store/frameworks/libs/distributeddb/storage/include/ikvdb_connection.h index 8cfebe8f0402977c7f02edb0a5536968de4350d0..eec37ba70d14b129cb7644af9931d64db2f23eaf 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/ikvdb_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/ikvdb_connection.h @@ -131,6 +131,8 @@ public: virtual int GetKeys(const IOption &option, const Key &keyPrefix, std::vector &keys) const = 0; virtual int GetSyncDataSize(const std::string &device, size_t &size) const = 0; + + virtual int UpdateKey(const UpdateKeyCallback &callback) = 0; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_manager.h b/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_manager.h index 7ea47927c4ccc71cfc7310adb8e98cd5ddc08728..88f028cda8699b0fc63edc3be2fcc73d3741ed0c 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_manager.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/kvdb_manager.h @@ -128,9 +128,13 @@ private: static int TryLockDB(const KvDBProperties &kvDBProp, int retryTimes); static int UnlockDB(const KvDBProperties &kvDBProp); + static bool CheckOpenDBOptionWithCached(const KvDBProperties &properties, IKvDB *kvdb); + static std::atomic instance_; static std::mutex kvDBLock_; static std::mutex instanceLock_; + + static std::mutex fileHandleMutex_; static std::map locks_; std::map localKvDBs_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h b/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h index 202b5f52debdf637f1a2be9b1207bff4cdf7f913..bd48de49e6761947474bb4a99d75ef0390997ad6 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/include/relational_store_connection.h @@ -53,6 +53,7 @@ public: virtual int CreateDistributedTable(const std::string &tableName) = 0; virtual int RegisterLifeCycleCallback(const DatabaseLifeCycleNotifier ¬ifier) = 0; + virtual int RemoveDeviceData() = 0; virtual int RemoveDeviceData(const std::string &device) = 0; virtual int RemoveDeviceData(const std::string &device, const std::string &tableName) = 0; virtual void RegisterObserverAction(const RelationalObserverAction &action) = 0; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.cpp index 7e6047d1a3363da37f5c7ee9eb769cf2c36db1f8..9bd0b60c3c11573350d6cf6baa2f244ace65e02b 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.cpp @@ -356,4 +356,9 @@ int GenericKvDBConnection::GetSyncDataSize(const std::string &device, size_t &si { return -E_NOT_SUPPORT; } + +int GenericKvDBConnection::UpdateKey(const UpdateKeyCallback &callback) +{ + return -E_NOT_SUPPORT; +} } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.h b/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.h index d99aa4d6d42bd741dd246bc3a7a639fc90ac38e4..09c1088bf01cc292dbd629c35a767a6017c0713e 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/generic_kvdb_connection.h @@ -78,6 +78,8 @@ public: int GetKeys(const IOption &option, const Key &keyPrefix, std::vector &keys) const override; int GetSyncDataSize(const std::string &device, size_t &size) const override; + + int UpdateKey(const UpdateKeyCallback &callback) override; protected: // Get the stashed 'KvDB_ pointer' without ref. template diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/kvdb_manager.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/kvdb_manager.cpp index 162457d3804b573072792b9c81dbe09c7412a876..1bbba479e02e32135f60ac013ddf372b350e425a 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/kvdb_manager.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/kvdb_manager.cpp @@ -29,6 +29,7 @@ std::atomic KvDBManager::instance_{nullptr}; std::mutex KvDBManager::kvDBLock_; std::mutex KvDBManager::instanceLock_; std::map KvDBManager::locks_; +std::mutex KvDBManager::fileHandleMutex_; namespace { DefaultFactory g_defaultFactory; @@ -120,7 +121,7 @@ int KvDBManager::ExecuteRemoveDatabase(const KvDBProperties &properties) } errCode = -E_NOT_FOUND; - for (const KvDBType kvDbType : g_dbTypeArr) { + for (KvDBType kvDbType : g_dbTypeArr) { int innerErrCode = E_OK; IKvDB *kvdb = factory->CreateKvDb(kvDbType, innerErrCode); if (innerErrCode != E_OK) { @@ -206,9 +207,12 @@ int KvDBManager::TryLockDB(const KvDBProperties &kvDBProp, int retryTimes) return E_OK; } - if (locks_.count(id) != 0) { - LOGI("db has been locked!"); - return E_OK; + { + std::lock_guard autoLock(fileHandleMutex_); + if (locks_.count(id) != 0) { + LOGI("db has been locked!"); + return E_OK; + } } std::string hexHashId = DBCommon::TransferStringToHex((id)); @@ -223,6 +227,7 @@ int KvDBManager::TryLockDB(const KvDBProperties &kvDBProp, int retryTimes) errCode = OS::FileLock(handle, false); // not block process if (errCode == E_OK) { LOGI("[%s]locked!", STR_MASK(DBCommon::TransferStringToHex(KvDBManager::GenerateKvDBIdentifier(kvDBProp)))); + std::lock_guard autoLock(fileHandleMutex_); locks_[id] = handle; return errCode; } else if (errCode == -E_BUSY) { @@ -246,23 +251,57 @@ int KvDBManager::UnlockDB(const KvDBProperties &kvDBProp) return E_OK; } std::string identifierDir = KvDBManager::GenerateKvDBIdentifier(kvDBProp); - if (locks_.count(identifierDir) == 0) { - return E_OK; + OS::FileHandle *handle = nullptr; + { + std::lock_guard autoLock(fileHandleMutex_); + if (locks_.count(identifierDir) == 0) { + return E_OK; + } + handle = locks_[identifierDir]; } - int errCode = OS::FileUnlock(locks_[identifierDir]); + int errCode = OS::FileUnlock(handle); if (errCode != E_OK) { LOGE("DB unlocked! errCode = [%d]", errCode); return errCode; } - errCode = OS::CloseFile(locks_[identifierDir]); + errCode = OS::CloseFile(handle); if (errCode != E_OK) { LOGE("DB closed! errCode = [%d]", errCode); return errCode; } + std::lock_guard autoLock(fileHandleMutex_); locks_.erase(identifierDir); return E_OK; } +bool KvDBManager::CheckOpenDBOptionWithCached(const KvDBProperties &properties, IKvDB *kvDB) +{ + bool isMemoryDb = properties.GetBoolProp(KvDBProperties::MEMORY_MODE, false); + std::string canonicalDir = properties.GetStringProp(KvDBProperties::DATA_DIR, ""); + if (!isMemoryDb && (canonicalDir.empty() || canonicalDir != kvDB->GetStorePath())) { + LOGE("Failed to check store path, the input path does not match with cached store."); + return false; + } + + bool compressOnSyncUser = properties.GetBoolProp(KvDBProperties::COMPRESS_ON_SYNC, false); + bool compressOnSyncGet = kvDB->GetMyProperties().GetBoolProp(KvDBProperties::COMPRESS_ON_SYNC, false); + if (compressOnSyncUser != compressOnSyncGet) { + LOGE("Failed to check compress option, the input %d not match with cached %d.", compressOnSyncUser, + compressOnSyncGet); + return false; + } + if (compressOnSyncUser) { + int compressRateUser = properties.GetIntProp(KvDBProperties::COMPRESSION_RATE, 0); + int compressRateGet = kvDB->GetMyProperties().GetIntProp(KvDBProperties::COMPRESSION_RATE, 0); + if (compressRateUser != compressRateGet) { + LOGE("Failed to check compress rate, the input %d not match with cached %d.", compressRateUser, + compressRateGet); + return false; + } + } + return true; +} + // Used to open a kvdb with the given property IKvDBConnection *KvDBManager::GetDatabaseConnection(const KvDBProperties &properties, int &errCode, bool isNeedIfOpened) @@ -283,10 +322,8 @@ IKvDBConnection *KvDBManager::GetDatabaseConnection(const KvDBProperties &proper LOGE("Failed to open the db:%d", errCode); } } else { - bool isMemoryDb = properties.GetBoolProp(KvDBProperties::MEMORY_MODE, false); - std::string canonicalDir = properties.GetStringProp(KvDBProperties::DATA_DIR, ""); - if (!isMemoryDb && (canonicalDir.empty() || canonicalDir != kvDB->GetStorePath())) { - LOGE("Failed to check store path, the input path does not match with cached store."); + if (!CheckOpenDBOptionWithCached(properties, kvDB)) { + LOGE("Failed to check open db option"); errCode = -E_INVALID_ARGS; } else { connection = kvDB->GetDBConnection(errCode); @@ -304,7 +341,8 @@ IKvDBConnection *KvDBManager::GetDatabaseConnection(const KvDBProperties &proper std::string userId = properties.GetStringProp(KvDBProperties::USER_ID, ""); std::string storeId = properties.GetStringProp(KvDBProperties::STORE_ID, ""); manager->DataBaseCorruptNotify(appId, userId, storeId); - LOGE("Database [%s] is corrupted:%d", STR_MASK(DBCommon::TransferStringToHex(identifier)), errCode); + LOGE("Database [%s] is corrupted or invalid passwd:%d", STR_MASK(DBCommon::TransferStringToHex(identifier)), + errCode); } return connection; @@ -447,7 +485,7 @@ int KvDBManager::CalculateKvStoreSize(const KvDBProperties &properties, uint64_t } uint64_t totalSize = 0; - for (const KvDBType kvDbType : g_dbTypeArr) { + for (KvDBType kvDbType : g_dbTypeArr) { int innerErrCode = E_OK; IKvDB *kvDB = factory->CreateKvDb(kvDbType, innerErrCode); if (innerErrCode != E_OK) { diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp index 7b6be36816a16d80695449dce5b9e72571abe361..f6587af57fece3c1a86c5c029b7bf75e52538f5d 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_able_storage.cpp @@ -478,8 +478,14 @@ int RelationalSyncAbleStorage::SaveSyncDataItems(const QueryObject &object, std: return errCode; } + StoreInfo info = { + storageEngine_->GetProperties().GetStringProp(DBProperties::USER_ID, ""), + storageEngine_->GetProperties().GetStringProp(DBProperties::APP_ID, ""), + storageEngine_->GetProperties().GetStringProp(DBProperties::STORE_ID, "") + }; auto inserter = RelationalSyncDataInserter::CreateInserter(deviceName, query, storageEngine_->GetSchema(), - remoteSchema.GetTable(query.GetTableName()).GetFieldInfos(), dataItems); + remoteSchema.GetTable(query.GetTableName()).GetFieldInfos(), info); + inserter.SetEntries(dataItems); auto *handle = GetHandle(true, errCode, OperatePerm::NORMAL_PERM); if (handle == nullptr) { @@ -604,12 +610,17 @@ int RelationalSyncAbleStorage::CreateDistributedDeviceTable(const std::string &d return errCode; } + StoreInfo info = { + storageEngine_->GetProperties().GetStringProp(DBProperties::USER_ID, ""), + storageEngine_->GetProperties().GetStringProp(DBProperties::APP_ID, ""), + storageEngine_->GetProperties().GetStringProp(DBProperties::STORE_ID, "") + }; for (const auto &[table, strategy] : syncStrategy) { if (!strategy.permitSync) { continue; } - errCode = handle->CreateDistributedDeviceTable(device, storageEngine_->GetSchema().GetTable(table)); + errCode = handle->CreateDistributedDeviceTable(device, storageEngine_->GetSchema().GetTable(table), info); if (errCode != E_OK) { LOGE("Create distributed device table failed. %d", errCode); break; @@ -820,14 +831,14 @@ int RelationalSyncAbleStorage::GetRemoteDeviceSchema(const std::string &deviceId if (errCode == -E_NOT_FOUND) { LOGW("Get remote device schema miss cached."); std::string keyStr = DBConstant::REMOTE_DEVICE_SCHEMA_KEY_PREFIX + DBCommon::TransferHashString(deviceId); - Key remoteSchemaKey(keyStr.begin(), keyStr.end());\ + Key remoteSchemaKey(keyStr.begin(), keyStr.end()); Value remoteSchemaBuff; errCode = GetMetaData(remoteSchemaKey, remoteSchemaBuff); if (errCode != E_OK) { LOGE("Get remote device schema from meta failed. err=%d", errCode); return errCode; } - std::string remoteSchema(remoteSchemaBuff.begin(), remoteSchemaBuff.end()); + remoteSchema = std::string(remoteSchemaBuff.begin(), remoteSchemaBuff.end()); errCode = remoteDeviceSchema_.Put(deviceId, remoteSchema); } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.cpp index aeebb9fe3a3bd65e3fa4438d19adeff4e8f03db2..07fb30965db54807d9b56e3b6a6c607f4ac5fdfe 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * 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 @@ -50,11 +50,10 @@ RelationalSyncDataInserter::~RelationalSyncDataInserter() RelationalSyncDataInserter RelationalSyncDataInserter::CreateInserter(const std::string &deviceName, const QueryObject &query, const RelationalSchemaObject &localSchema, const std::vector &remoteFields, - const std::vector &entries) + const StoreInfo &info) { RelationalSyncDataInserter inserter; - inserter.SetDeviceId(deviceName); - inserter.SetEntries(entries); + inserter.SetHashDevId(DBCommon::TransferStringToHex(DBCommon::TransferHashString(deviceName))); inserter.SetRemoteFields(remoteFields); inserter.SetQuery(query); TableInfo localTable = localSchema.GetTable(query.GetTableName()); @@ -63,14 +62,14 @@ RelationalSyncDataInserter RelationalSyncDataInserter::CreateInserter(const std: if (localSchema.GetTableMode() == DistributedTableMode::COLLABORATION) { inserter.SetInsertTableName(localTable.GetTableName()); } else { - inserter.SetInsertTableName(DBCommon::GetDistributedTableName(deviceName, localTable.GetTableName())); + inserter.SetInsertTableName(DBCommon::GetDistributedTableName(deviceName, localTable.GetTableName(), info)); } return inserter; } -void RelationalSyncDataInserter::SetDeviceId(std::string deviceId) +void RelationalSyncDataInserter::SetHashDevId(const std::string &hashDevId) { - deviceId_ = std::move(deviceId); + hashDevId_ = hashDevId; } void RelationalSyncDataInserter::SetRemoteFields(std::vector remoteFields) @@ -88,7 +87,7 @@ void RelationalSyncDataInserter::SetLocalTable(TableInfo localTable) localTable_ = std::move(localTable); } -const TableInfo &RelationalSyncDataInserter::GetLocalTable() +const TableInfo &RelationalSyncDataInserter::GetLocalTable() const { return localTable_; } @@ -208,9 +207,8 @@ int RelationalSyncDataInserter::GetDeleteSyncDataStmt(sqlite3 *db, sqlite3_stmt int RelationalSyncDataInserter::GetSaveLogStatement(sqlite3 *db, sqlite3_stmt *&logStmt, sqlite3_stmt *&queryStmt) { - std::string devName = DBCommon::TransferHashString(deviceId_); const std::string tableName = DBConstant::RELATIONAL_PREFIX + query_.GetTableName() + "_log"; - std::string dataFormat = "?, '" + deviceId_ + "', ?, ?, ?, ?, ?"; + std::string dataFormat = "?, '" + hashDevId_ + "', ?, ?, ?, ?, ?"; std::string columnList = "data_key, device, ori_device, timestamp, wtimestamp, flag, hash_key"; std::string sql = "INSERT OR REPLACE INTO " + tableName + " (" + columnList + ") VALUES (" + dataFormat + ");"; @@ -251,7 +249,7 @@ int RelationalSyncDataInserter::Iterate(const std::function &s { int errCode = E_OK; for (auto &it : entries_) { - it.dev = deviceId_; + it.dev = hashDevId_; errCode = saveSyncDataItem(it); if (errCode != E_OK) { LOGE("Save sync data item failed. err=%d", errCode); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.h b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.h index 0a9bb827492c030c7bcf694c91574e7222575600..7120c28a3a734bae7d433b50e79d3761d7f9fce7 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/relational_sync_data_inserter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * 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 @@ -45,15 +45,15 @@ public: static RelationalSyncDataInserter CreateInserter(const std::string &deviceName, const QueryObject &query, const RelationalSchemaObject &localSchema, const std::vector &remoteFields, - const std::vector &entries); + const StoreInfo &info); - void SetDeviceId(std::string deviceId); + void SetHashDevId(const std::string &hashDevId); // Set remote fields in cid order - void SetRemoteFields(std::vector fields); + void SetRemoteFields(std::vector remoteFields); void SetEntries(std::vector entries); void SetLocalTable(TableInfo localTable); - const TableInfo &GetLocalTable(); + const TableInfo &GetLocalTable() const; void SetQuery(QueryObject query); void SetInsertTableName(std::string tableName); @@ -73,7 +73,7 @@ private: int GetSaveLogStatement(sqlite3 *db, sqlite3_stmt *&logStmt, sqlite3_stmt *&queryStmt); - std::string deviceId_; + std::string hashDevId_; std::vector remoteFields_; std::vector entries_; TableInfo localTable_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp index 59e7c7908e682d653faa662c9f4f8d52a59cb04f..1d85cfa0abe75589a4c9015a01d41fe851d84376 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.cpp @@ -431,7 +431,7 @@ int SQLiteRelationalStore::CreateDistributedTable(const std::string &tableName) return errCode; } -int SQLiteRelationalStore::RemoveDeviceData(const std::string &device, const std::string &tableName) +int SQLiteRelationalStore::RemoveDeviceData() { auto mode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); @@ -441,49 +441,83 @@ int SQLiteRelationalStore::RemoveDeviceData(const std::string &device, const std } TableInfoMap tables = sqliteStorageEngine_->GetSchema().GetTables(); // TableInfoMap - if (!tableName.empty() && tables.find(tableName) == tables.end()) { - LOGW("Remove device data with table name which is not a distributed table or not exist."); + if (tables.empty()) { return E_OK; } int errCode = E_OK; - auto *handle = GetHandle(true, errCode); + auto *handle = GetHandleAndStartTransaction(errCode); if (handle == nullptr) { return errCode; } - errCode = handle->StartTransaction(TransactType::IMMEDIATE); - if (errCode != E_OK) { - ReleaseHandle(handle); - return errCode; - } - - errCode = handle->DeleteDistributedDeviceTable(device, tableName); - if (errCode != E_OK) { - LOGE("delete device data failed. %d", errCode); - goto END; - } + std::vector tableNameList; + for (const auto &table: tables) { + errCode = handle->DeleteDistributedDeviceTable("", table.second.GetTableName()); + if (errCode != E_OK) { + LOGE("delete device data failed. %d", errCode); + break; + } - for (const auto &it : tables) { - if (tableName.empty() || it.second.GetTableName() == tableName) { - errCode = handle->DeleteDistributedDeviceTableLog(device, it.second.GetTableName()); - if (errCode != E_OK) { - LOGE("delete device data failed. %d", errCode); - break; - } + errCode = handle->DeleteDistributedAllDeviceTableLog(table.second.GetTableName()); + if (errCode != E_OK) { + LOGE("delete device data failed. %d", errCode); + break; } + tableNameList.push_back(table.second.GetTableName()); } -END: if (errCode != E_OK) { (void)handle->Rollback(); ReleaseHandle(handle); return errCode; } + errCode = handle->Commit(); ReleaseHandle(handle); storageEngine_->NotifySchemaChanged(); - return (errCode != E_OK) ? errCode : syncAbleEngine_->EraseDeviceWaterMark(device, true, tableName); + return (errCode != E_OK) ? errCode : EraseAllDeviceWatermark(tableNameList); +} + +int SQLiteRelationalStore::RemoveDeviceData(const std::string &device, const std::string &tableName) +{ + auto mode = static_cast(sqliteStorageEngine_->GetProperties().GetIntProp( + RelationalDBProperties::DISTRIBUTED_TABLE_MODE, DistributedTableMode::SPLIT_BY_DEVICE)); + if (mode == DistributedTableMode::COLLABORATION) { + LOGE("Not support remove device data in collaboration mode."); + return -E_NOT_SUPPORT; + } + + TableInfoMap tables = sqliteStorageEngine_->GetSchema().GetTables(); // TableInfoMap + if (tables.empty() || (!tableName.empty() && tables.find(tableName) == tables.end())) { + LOGE("Remove device data with table name which is not a distributed table or no distributed table found."); + return -E_DISTRIBUTED_SCHEMA_NOT_FOUND; + } + + bool isNeedHash = false; + std::string hashDeviceId; + int errCode = syncAbleEngine_->GetHashDeviceId(device, hashDeviceId); + if (errCode == -E_NOT_SUPPORT) { + isNeedHash = true; + hashDeviceId = device; + errCode = E_OK; + } + if (errCode != E_OK) { + return errCode; + } + if (isNeedHash) { + // check device is uuid in meta + std::set hashDevices; + errCode = GetExistDevices(hashDevices); + if (errCode != E_OK) { + return errCode; + } + if (hashDevices.find(DBCommon::TransferHashString(device)) == hashDevices.end()) { + LOGD("[SQLiteRelationalStore] not match device, just return"); + return E_OK; + } + } + return RemoveDeviceDataInner(hashDeviceId, device, tableName, isNeedHash); } void SQLiteRelationalStore::RegisterObserverAction(const RelationalObserverAction &action) @@ -673,5 +707,126 @@ int SQLiteRelationalStore::RemoteQuery(const std::string &device, const RemoteCo return syncAbleEngine_->RemoteQuery(device, condition, timeout, connectionId, result); } + +int SQLiteRelationalStore::EraseAllDeviceWatermark(const std::vector &tableNameList) +{ + std::set devices; + int errCode = GetExistDevices(devices); + if (errCode != E_OK) { + return errCode; + } + for (const auto &tableName: tableNameList) { + for (const auto &device: devices) { + errCode = syncAbleEngine_->EraseDeviceWaterMark(device, false, tableName); + if (errCode != E_OK) { + return errCode; + } + } + } + return errCode; +} + +std::string SQLiteRelationalStore::GetDevTableName(const std::string &device, const std::string &hashDev) const +{ + std::string devTableName; + StoreInfo info = { + sqliteStorageEngine_->GetProperties().GetStringProp(DBProperties::USER_ID, ""), + sqliteStorageEngine_->GetProperties().GetStringProp(DBProperties::APP_ID, ""), + sqliteStorageEngine_->GetProperties().GetStringProp(DBProperties::STORE_ID, "") + }; + if (RuntimeContext::GetInstance()->TranslateDeviceId(device, info, devTableName) != E_OK) { + devTableName = hashDev; + } + return devTableName; +} + +SQLiteSingleVerRelationalStorageExecutor *SQLiteRelationalStore::GetHandleAndStartTransaction(int &errCode) const +{ + auto *handle = GetHandle(true, errCode); + if (handle == nullptr) { + return nullptr; + } + + errCode = handle->StartTransaction(TransactType::IMMEDIATE); + if (errCode != E_OK) { + ReleaseHandle(handle); + return nullptr; + } + return handle; +} + +int SQLiteRelationalStore::RemoveDeviceDataInner(const std::string &mappingDev, const std::string &device, + const std::string &tableName, bool isNeedHash) +{ + int errCode = E_OK; + auto *handle = GetHandle(true, errCode); + if (handle == nullptr) { + return errCode; + } + + errCode = handle->StartTransaction(TransactType::IMMEDIATE); + if (errCode != E_OK) { + ReleaseHandle(handle); + return errCode; + } + + std::string hashHexDev; + std::string hashDev; + std::string devTableName; + if (!isNeedHash) { + // if is not need hash mappingDev mean hash(uuid) device is param device + hashHexDev = DBCommon::TransferStringToHex(mappingDev); + hashDev = mappingDev; + devTableName = device; + } else { + // if is need hash mappingDev mean uuid + hashDev = DBCommon::TransferHashString(mappingDev); + hashHexDev = DBCommon::TransferStringToHex(hashDev); + devTableName = GetDevTableName(mappingDev, hashHexDev); + } + errCode = handle->DeleteDistributedDeviceTable(devTableName, tableName); + TableInfoMap tables = sqliteStorageEngine_->GetSchema().GetTables(); // TableInfoMap + if (errCode != E_OK) { + LOGE("delete device data failed. %d", errCode); + goto END; + } + + for (const auto &it : tables) { + if (tableName.empty() || it.second.GetTableName() == tableName) { + errCode = handle->DeleteDistributedDeviceTableLog(hashHexDev, it.second.GetTableName()); + if (errCode != E_OK) { + LOGE("delete device data failed. %d", errCode); + break; + } + } + } + +END: + if (errCode != E_OK) { + (void)handle->Rollback(); + ReleaseHandle(handle); + return errCode; + } + errCode = handle->Commit(); + ReleaseHandle(handle); + storageEngine_->NotifySchemaChanged(); + return (errCode != E_OK) ? errCode : syncAbleEngine_->EraseDeviceWaterMark(hashDev, false, tableName); +} + +int SQLiteRelationalStore::GetExistDevices(std::set &hashDevices) +{ + int errCode = E_OK; + auto *handle = GetHandle(true, errCode); + if (handle == nullptr) { + LOGE("[SingleVerRDBStore] GetExistsDeviceList get handle failed:%d", errCode); + return errCode; + } + errCode = handle->GetExistsDeviceList(hashDevices); + if (errCode != E_OK) { + LOGE("[SingleVerRDBStore] Get remove device list from meta failed. err=%d", errCode); + } + ReleaseHandle(handle); + return errCode; +} } #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h index 216b0ad26edc82ea08330c3ddd11054c27d078e7..7603a830a41fd4d10908d8e06ddc20b26713f56a 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store.h @@ -58,6 +58,7 @@ public: int CreateDistributedTable(const std::string &tableName); + int RemoveDeviceData(); int RemoveDeviceData(const std::string &device, const std::string &tableName); void RegisterObserverAction(const RelationalObserverAction &action); @@ -98,6 +99,17 @@ private: void IncreaseConnectionCounter(); int InitStorageEngine(const RelationalDBProperties &kvDBProp); + int EraseAllDeviceWatermark(const std::vector &tableNameList); + + std::string GetDevTableName(const std::string &device, const std::string &hashDev) const; + + SQLiteSingleVerRelationalStorageExecutor *GetHandleAndStartTransaction(int &errCode) const; + + int RemoveDeviceDataInner(const std::string &mappingDev, const std::string &device, + const std::string &tableName, bool isNeedHash); + + int GetExistDevices(std::set &hashDevices); + // use for sync Interactive std::unique_ptr syncAbleEngine_ = nullptr; // For storage operate sync function // use ref obj same as kv diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp index 86e72eed861431787f77a251443ed14c90c9dcbd..57fb3c36ea20d1ef70e12971af946424e93119c3 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.cpp @@ -156,6 +156,21 @@ int SQLiteRelationalStoreConnection::CreateDistributedTable(const std::string &t return errCode; } +int SQLiteRelationalStoreConnection::RemoveDeviceData() +{ + auto *store = GetDB(); + if (store == nullptr) { + LOGE("[RelationalConnection] store is null, get DB failed!"); + return -E_INVALID_CONNECTION; + } + + int errCode = store->RemoveDeviceData(); + if (errCode != E_OK) { + LOGE("[RelationalConnection] remove device data failed. %d", errCode); + } + return errCode; +} + int SQLiteRelationalStoreConnection::RemoveDeviceData(const std::string &device) { return RemoveDeviceData(device, {}); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h index 3c51d21de0b4b2eb3edd81cc23922c9514c67181..0c85ca89c4ba3ef5b8636cd22d4f097afe0a48ad 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/relational/sqlite_relational_store_connection.h @@ -39,6 +39,7 @@ public: int CreateDistributedTable(const std::string &tableName) override; int RegisterLifeCycleCallback(const DatabaseLifeCycleNotifier ¬ifier) override; + int RemoveDeviceData() override; int RemoveDeviceData(const std::string &device) override; int RemoveDeviceData(const std::string &device, const std::string &tableName) override; void RegisterObserverAction(const RelationalObserverAction &action) override; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_meta_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_meta_executor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdc929b8a4d62ae1d18359576d3a7882614619ae --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_meta_executor.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "sqlite_meta_executor.h" + +#include "db_common.h" +#include "db_constant.h" +namespace DistributedDB { +int SqliteMetaExecutor::GetMetaKeysByKeyPrefix(const std::string &keyPre, sqlite3 *dbHandle, MetaMode metaMode, + bool isMemDb, std::set &outKeys) +{ + sqlite3_stmt *statement = nullptr; + std::string sqlStr; + switch (metaMode) { + case MetaMode::KV: + sqlStr = SELECT_META_KEYS_BY_PREFIX; + break; + case MetaMode::KV_ATTACH: + sqlStr = SELECT_ATTACH_META_KEYS_BY_PREFIX; + break; + case MetaMode::RDB: + sqlStr = SELECT_RDB_META_KEYS_BY_PREFIX; + break; + default: + return -E_INVALID_ARGS; + } + int errCode = SQLiteUtils::GetStatement(dbHandle, sqlStr, statement); + if (errCode != E_OK) { + LOGE("[SqliteMetaExecutor] Get statement failed:%d", errCode); + return errCode; + } + + Key keyPrefix; + DBCommon::StringToVector(keyPre + '%', keyPrefix); + errCode = SQLiteUtils::BindBlobToStatement(statement, 1, keyPrefix); // 1: bind index for prefix key + if (errCode != E_OK) { + LOGE("[SqliteMetaExecutor] Bind statement failed:%d", errCode); + SQLiteUtils::ResetStatement(statement, true, errCode); + return errCode; + } + + std::vector keys; + errCode = GetAllKeys(statement, isMemDb, keys); + SQLiteUtils::ResetStatement(statement, true, errCode); + for (const auto &it : keys) { + if (it.size() >= keyPre.size() + DBConstant::HASH_KEY_SIZE) { + outKeys.insert({it.begin() + keyPre.size(), it.begin() + keyPre.size() + DBConstant::HASH_KEY_SIZE}); + } else { + LOGW("[SqliteMetaExecutor] Get invalid key, size=%zu", it.size()); + } + } + return errCode; +} + +int SqliteMetaExecutor::GetAllKeys(sqlite3_stmt *statement, bool isMemDb, std::vector &keys) +{ + if (statement == nullptr) { + return -E_INVALID_DB; + } + int errCode; + do { + errCode = SQLiteUtils::StepWithRetry(statement, isMemDb); + if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { + Key key; + errCode = SQLiteUtils::GetColumnBlobValue(statement, 0, key); + if (errCode != E_OK) { + break; + } + + keys.push_back(std::move(key)); + } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { + errCode = E_OK; + break; + } else { + LOGE("SQLite step for getting all keys failed:%d", errCode); + break; + } + } while (true); + return errCode; +} + +int SqliteMetaExecutor::GetExistsDevicesFromMeta(sqlite3 *dbHandle, MetaMode metaMode, + bool isMemDb, std::set &devices) +{ + int errCode = GetMetaKeysByKeyPrefix(DBConstant::DEVICEID_PREFIX_KEY, dbHandle, metaMode, isMemDb, devices); + if (errCode != E_OK) { + LOGE("Get meta data key failed. err=%d", errCode); + return errCode; + } + errCode = GetMetaKeysByKeyPrefix(DBConstant::QUERY_SYNC_PREFIX_KEY, dbHandle, metaMode, isMemDb, devices); + if (errCode != E_OK) { + LOGE("Get meta data key failed. err=%d", errCode); + return errCode; + } + errCode = GetMetaKeysByKeyPrefix(DBConstant::DELETE_SYNC_PREFIX_KEY, dbHandle, metaMode, isMemDb, devices); + if (errCode != E_OK) { + LOGE("Get meta data key failed. err=%d", errCode); + } + return errCode; +} +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_meta_executor.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_meta_executor.h new file mode 100644 index 0000000000000000000000000000000000000000..f2890e7b473817abacfe96ed71f5bbd9d1c3cf94 --- /dev/null +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_meta_executor.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 SQLITE_META_EXECUTOR_H +#define SQLITE_META_EXECUTOR_H + +#include "sqlite_utils.h" + +namespace DistributedDB { +class SqliteMetaExecutor { +public: + enum class MetaMode { + KV = 0, + KV_ATTACH = 1, + RDB = 2 + }; + static int GetMetaKeysByKeyPrefix(const std::string &keyPre, sqlite3 *dbHandle, MetaMode metaMode, bool isMemDb, + std::set &outKeys); + + static int GetAllKeys(sqlite3_stmt *statement, bool isMemDb, std::vector &keys); + + static int GetExistsDevicesFromMeta(sqlite3 *dbHandle, MetaMode metaMode, + bool isMemDb, std::set &devices); +private: + static constexpr const char *SELECT_ATTACH_META_KEYS_BY_PREFIX = + "SELECT key FROM meta.meta_data where key like ?;"; + + static constexpr const char *SELECT_META_KEYS_BY_PREFIX = + "SELECT key FROM meta_data where key like ?;"; + + static constexpr const char *SELECT_RDB_META_KEYS_BY_PREFIX = + "SELECT key FROM naturalbase_rdb_aux_metadata where key like ?;"; +}; +} // DistributedDB +#endif // SQLITE_META_EXECUTOR_H diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp index ae76af04c3de7c189986ab982e956476fb680931..9ad4757add427bb603e8cbe80212a6657a51be57 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_query_helper.cpp @@ -829,8 +829,19 @@ int SqliteQueryHelper::GetSubscribeCondition(const std::string &accessStr, std:: conditionStr += " (1 = 1) "; return E_OK; } - // json_extract_by_path function will return error when value is empty, check it before - conditionStr += "((length(" + accessStr + "value) != 0 AND " + accessStr + "value IS NOT NULL) AND "; + + bool hasQueryByValue = std::any_of(queryObjNodes_.begin(), queryObjNodes_.end(), [](const QueryObjNode &it) { + return GetSymbolType(it.operFlag) == SymbolType::COMPARE_SYMBOL || + GetSymbolType(it.operFlag) == SymbolType::RELATIONAL_SYMBOL || + GetSymbolType(it.operFlag) == SymbolType::RANGE_SYMBOL; + }); + if (hasQueryByValue) { + // json_extract_by_path function will return error when value is empty, check it before when query by value + conditionStr += "((length(" + accessStr + "value) != 0 AND " + accessStr + "value IS NOT NULL) AND "; + } else { + conditionStr += "("; + } + if (hasPrefixKey_) { conditionStr += "(hex(" + accessStr + "key) LIKE '" + DBCommon::VectorToHexString(prefixKey_) + "%')"; } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp index 62b1a51861769e73386d828bf0cd54874d25a101..b1240bdf615922f4dd4bd52e2da070fcf3d55e32 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.cpp @@ -413,13 +413,13 @@ int SQLiteSingleVerNaturalStore::GetAndInitStorageEngine(const KvDBProperties &k } if (storageEngine_->IsEngineCorrupted()) { - LOGE("[SqlSinStore][GetAndInitStorageEngine] database engine is corrupted, not need continue to open!"); + LOGE("[SqlSinStore][GetAndInitStorageEngine] database engine is corrupted or invalid passwd, stop open!"); return -E_INVALID_PASSWD_OR_CORRUPTED_DB; } errCode = InitDatabaseContext(kvDBProp); if (errCode != E_OK) { - LOGE("[SqlSinStore][Open] Init database context fail! errCode = [%d]", errCode); + LOGE("[SqlSinStore][GetAndInitStorageEngine] Init database context fail! errCode = [%d]", errCode); } return errCode; } @@ -974,55 +974,28 @@ int SQLiteSingleVerNaturalStore::RemoveDeviceData(const std::string &deviceName, if (!isInSync && !CheckWritePermission()) { return -E_NOT_PERMIT; } - int errCode = E_OK; - SQLiteSingleVerStorageExecutor *handle = GetHandle(true, errCode); - if (handle == nullptr) { - LOGE("[SingleVerNStore] RemoveDeviceData get handle failed:%d", errCode); - return errCode; - } - uint64_t logFileSize = handle->GetLogFileSize(); - ReleaseHandle(handle); - if (logFileSize > GetMaxLogSize()) { - LOGW("[SingleVerNStore] RmDevData log size[%" PRIu64 "] over the limit", logFileSize); - return -E_LOG_OVER_LIMITS; - } - - bool isNeedHash = true; - std::set removeDevices; - if (deviceName.empty()) { - errCode = GetExistsDeviceList(removeDevices); - if (errCode != E_OK) { - LOGE("[SingleVerNStore] get remove device list failed:%d", errCode); - return errCode; - } - isNeedHash = false; - } else { - removeDevices.insert(deviceName); - } - - LOGD("[SingleVerNStore] remove device data, size=%zu", removeDevices.size()); - for (const auto &iterDevice : removeDevices) { - // Call the syncer module to erase the water mark. - errCode = EraseDeviceWaterMark(iterDevice, isNeedHash); - if (errCode != E_OK) { - LOGE("[SingleVerNStore] erase water mark failed:%d", errCode); - return errCode; + std::string hashDeviceId; + bool hash = false; + do { + if (!deviceName.empty() && !isInSync) { + int errCode = GetHashDeviceId(deviceName, hashDeviceId); + if (errCode == -E_NOT_SUPPORT) { + break; + } + if (errCode != E_OK) { + return errCode; + } + hash = true; } + } while (false); + if (!hash) { + hashDeviceId = DBCommon::TransferHashString(deviceName); } - if (IsExtendedCacheDBMode()) { - errCode = RemoveDeviceDataInCacheMode(deviceName, isNeedNotify); - } else { - errCode = RemoveDeviceDataNormally(deviceName, isNeedNotify); - } - if (errCode != E_OK) { - LOGE("[SingleVerNStore] RemoveDeviceData failed:%d", errCode); - } - - return errCode; + return RemoveDeviceDataInner(hashDeviceId, isNeedNotify, isInSync); } -int SQLiteSingleVerNaturalStore::RemoveDeviceDataInCacheMode(const std::string &deviceName, bool isNeedNotify) +int SQLiteSingleVerNaturalStore::RemoveDeviceDataInCacheMode(const std::string &hashDev, bool isNeedNotify) { int errCode = E_OK; SQLiteSingleVerStorageExecutor *handle = GetHandle(true, errCode); @@ -1032,7 +1005,7 @@ int SQLiteSingleVerNaturalStore::RemoveDeviceDataInCacheMode(const std::string & } uint64_t recordVersion = GetAndIncreaseCacheRecordVersion(); LOGI("Remove device data in cache mode isNeedNotify:%d, recordVersion:%" PRIu64, isNeedNotify, recordVersion); - errCode = handle->RemoveDeviceDataInCacheMode(deviceName, isNeedNotify, recordVersion); + errCode = handle->RemoveDeviceDataInCacheMode(hashDev, isNeedNotify, recordVersion); if (errCode != E_OK) { LOGE("[SingleVerNStore] RemoveDeviceDataInCacheMode failed:%d", errCode); } @@ -1040,7 +1013,7 @@ int SQLiteSingleVerNaturalStore::RemoveDeviceDataInCacheMode(const std::string & return errCode; } -int SQLiteSingleVerNaturalStore::RemoveDeviceDataNormally(const std::string &deviceName, bool isNeedNotify) +int SQLiteSingleVerNaturalStore::RemoveDeviceDataNormally(const std::string &hashDev, bool isNeedNotify) { int errCode = E_OK; SQLiteSingleVerStorageExecutor *handle = GetHandle(true, errCode); @@ -1051,11 +1024,11 @@ int SQLiteSingleVerNaturalStore::RemoveDeviceDataNormally(const std::string &dev std::vector entries; if (isNeedNotify) { - handle->GetAllSyncedEntries(deviceName, entries); + handle->GetAllSyncedEntries(hashDev, entries); } LOGI("Remove device data:%d", isNeedNotify); - errCode = handle->RemoveDeviceData(deviceName); + errCode = handle->RemoveDeviceData(hashDev); ReleaseHandle(handle); if (errCode == E_OK && isNeedNotify) { NotifyRemovedData(entries); @@ -1120,7 +1093,7 @@ SQLiteSingleVerStorageExecutor *SQLiteSingleVerNaturalStore::GetHandle(bool isWr CorruptNotify(); errCode = -E_INVALID_PASSWD_OR_CORRUPTED_DB; engineMutex_.unlock_shared(); // unlock when get handle failed. - LOGI("Handle is corrupted can not to get! errCode = [%d]", errCode); + LOGI("Handle is corrupted or invalid passwd, can not to get! errCode = [%d]", errCode); return nullptr; } @@ -2410,5 +2383,52 @@ void SQLiteSingleVerNaturalStore::Dump(int fd) SyncAbleKvDB::Dump(fd); } +int SQLiteSingleVerNaturalStore::RemoveDeviceDataInner(const std::string &hashDev, bool isNeedNotify, bool isInSync) +{ + int errCode = E_OK; + SQLiteSingleVerStorageExecutor *handle = GetHandle(true, errCode); + if (handle == nullptr) { + LOGE("[SingleVerNStore] RemoveDeviceData get handle failed:%d", errCode); + return errCode; + } + uint64_t logFileSize = handle->GetLogFileSize(); + ReleaseHandle(handle); + if (logFileSize > GetMaxLogSize()) { + LOGW("[SingleVerNStore] RmDevData log size[%" PRIu64 "] over the limit", logFileSize); + return -E_LOG_OVER_LIMITS; + } + + std::set removeDevices; + if (hashDev.empty()) { + errCode = GetExistsDeviceList(removeDevices); + if (errCode != E_OK) { + LOGE("[SingleVerNStore] get remove device list failed:%d", errCode); + return errCode; + } + } else { + removeDevices.insert(hashDev); + } + + LOGD("[SingleVerNStore] remove device data, size=%zu", removeDevices.size()); + for (const auto &iterDevice : removeDevices) { + // Call the syncer module to erase the water mark. + errCode = EraseDeviceWaterMark(iterDevice, false); + if (errCode != E_OK) { + LOGE("[SingleVerNStore] erase water mark failed:%d", errCode); + return errCode; + } + } + + if (IsExtendedCacheDBMode()) { + errCode = RemoveDeviceDataInCacheMode(hashDev, isNeedNotify); + } else { + errCode = RemoveDeviceDataNormally(hashDev, isNeedNotify); + } + if (errCode != E_OK) { + LOGE("[SingleVerNStore] RemoveDeviceData failed:%d", errCode); + } + + return errCode; +} DEFINE_OBJECT_TAG_FACILITIES(SQLiteSingleVerNaturalStore) } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h index d9a63145e9429d63a5c63ea516d727ca8d585864..4ef2d756e01b68785420fe3b9235a52c229fe83c 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store.h @@ -244,9 +244,9 @@ private: // Change value that should be amended, and neglect value that is incompatible void CheckAmendValueContentForSyncProcedure(std::vector &dataItems) const; - int RemoveDeviceDataInCacheMode(const std::string &deviceName, bool isNeedNotify); + int RemoveDeviceDataInCacheMode(const std::string &hashDev, bool isNeedNotify); - int RemoveDeviceDataNormally(const std::string &deviceName, bool isNeedNotify); + int RemoveDeviceDataNormally(const std::string &hashDev, bool isNeedNotify); int SaveSyncDataToMain(const QueryObject &query, std::vector &dataItems, const DeviceInfo &deviceInfo); @@ -275,6 +275,8 @@ private: int GetExistsDeviceList(std::set &devices) const; + int RemoveDeviceDataInner(const std::string &hashDev, bool isNeedNotify, bool isInSync); + DECLARE_OBJECT_TAG(SQLiteSingleVerNaturalStore); Timestamp currentMaxTimestamp_ = 0; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp index ca6de67dfc1ccf5f3dc4ce52b71e9c8cbf0dd059..45072d6ba57228a56ccec82262bbe342d2e84e4f 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.cpp @@ -1833,5 +1833,31 @@ int SQLiteSingleVerNaturalStoreConnection::GetEntriesInner(bool isGetValue, cons return errCode; } +int SQLiteSingleVerNaturalStoreConnection::UpdateKey(const DistributedDB::UpdateKeyCallback &callback) +{ + if (IsExtendedCacheDBMode()) { + LOGE("[Connection] Not support update key in cache mode"); + return -E_NOT_SUPPORT; + } + int errCode = E_OK; + { + std::lock_guard lock(transactionMutex_); + if (writeHandle_ != nullptr) { + LOGD("[Connection] Transaction started already."); + errCode = writeHandle_->UpdateKey(callback); + return errCode; + } + } + + SQLiteSingleVerStorageExecutor *handle = GetExecutor(true, errCode); + if (handle == nullptr) { + LOGE("[Connection]::[UpdateKey] Get executor failed, errCode = [%d]", errCode); + return errCode; + } + + errCode = handle->UpdateKey(callback); + ReleaseExecutor(handle); + return errCode; +} DEFINE_OBJECT_TAG_FACILITIES(SQLiteSingleVerNaturalStoreConnection) } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h index 84381bfcb90f8669fc9e4a1314c445b8d20fb85f..330876c6a9d706a6e678a516b0858c31da9a7a85 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_natural_store_connection.h @@ -107,6 +107,7 @@ public: int GetKeys(const IOption &option, const Key &keyPrefix, std::vector &keys) const override; + int UpdateKey(const UpdateKeyCallback &callback) override; private: int CheckMonoStatus(OperatePerm perm); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp index 02c5c7a6f1892811624dbaf4a9ce7825b8b62bd2..68aab389f88ef0e45057a2a73ef22a0fac5918d9 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.cpp @@ -23,6 +23,7 @@ #include "log_table_manager_factory.h" #include "relational_row_data_impl.h" #include "res_finalizer.h" +#include "sqlite_meta_executor.h" #include "sqlite_relational_utils.h" namespace DistributedDB { @@ -210,8 +211,7 @@ int GetDeviceTableName(sqlite3 *handle, const std::string &tableName, const std: if (device.empty() && tableName.empty()) { // device and table name should not both be empty return -E_INVALID_ARGS; } - std::string deviceHash = DBCommon::TransferStringToHex(DBCommon::TransferHashString(device)); - std::string devicePattern = device.empty() ? "%" : deviceHash; + std::string devicePattern = device.empty() ? "%" : device; std::string tablePattern = tableName.empty() ? "%" : tableName; std::string deviceTableName = DBConstant::RELATIONAL_PREFIX + tablePattern + "_" + devicePattern; @@ -579,33 +579,6 @@ int SQLiteSingleVerRelationalStorageExecutor::DeleteMetaDataByPrefixKey(const Ke return CheckCorruptedStatus(errCode); } -static int GetAllKeys(sqlite3_stmt *statement, std::vector &keys) -{ - if (statement == nullptr) { - return -E_INVALID_DB; - } - int errCode; - do { - errCode = SQLiteUtils::StepWithRetry(statement, false); - if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { - Key key; - errCode = SQLiteUtils::GetColumnBlobValue(statement, 0, key); - if (errCode != E_OK) { - break; - } - - keys.push_back(std::move(key)); - } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { - errCode = E_OK; - break; - } else { - LOGE("SQLite step for getting all keys failed:%d", errCode); - break; - } - } while (true); - return errCode; -} - int SQLiteSingleVerRelationalStorageExecutor::GetAllMetaKeys(std::vector &keys) const { static const std::string SELECT_ALL_META_KEYS = "SELECT key FROM " + DBConstant::RELATIONAL_PREFIX + "metadata;"; @@ -615,7 +588,7 @@ int SQLiteSingleVerRelationalStorageExecutor::GetAllMetaKeys(std::vector &k LOGE("[Relational][GetAllKey] Get statement failed:%d", errCode); return errCode; } - errCode = GetAllKeys(statement, keys); + errCode = SqliteMetaExecutor::GetAllKeys(statement, isMemDb_, keys); SQLiteUtils::ResetStatement(statement, true, errCode); return errCode; } @@ -683,33 +656,33 @@ int SQLiteSingleVerRelationalStorageExecutor::SaveSyncLog(sqlite3_stmt *statemen } int SQLiteSingleVerRelationalStorageExecutor::DeleteSyncDataItem(const DataItem &dataItem, - RelationalSyncDataInserter &inserter, sqlite3_stmt *&stmt) + RelationalSyncDataInserter &inserter, sqlite3_stmt *&rmDataStmt) { - if (stmt == nullptr) { - int errCode = inserter.GetDeleteSyncDataStmt(dbHandle_, stmt); + if (rmDataStmt == nullptr) { + int errCode = inserter.GetDeleteSyncDataStmt(dbHandle_, rmDataStmt); if (errCode != E_OK) { LOGE("[DeleteSyncDataItem] Get statement fail!, errCode:%d", errCode); return errCode; } } - int errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, dataItem.hashKey); // 1 means hash_key index + int errCode = SQLiteUtils::BindBlobToStatement(rmDataStmt, 1, dataItem.hashKey); // 1 means hash_key index if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); + SQLiteUtils::ResetStatement(rmDataStmt, true, errCode); return errCode; } if (mode_ != DistributedTableMode::COLLABORATION) { - errCode = SQLiteUtils::BindTextToStatement(stmt, 2, dataItem.dev); // 2 means device index + errCode = SQLiteUtils::BindTextToStatement(rmDataStmt, 2, dataItem.dev); // 2 means device index if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); + SQLiteUtils::ResetStatement(rmDataStmt, true, errCode); return errCode; } } - errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_); + errCode = SQLiteUtils::StepWithRetry(rmDataStmt, isMemDb_); if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { errCode = E_OK; } - SQLiteUtils::ResetStatement(stmt, false, errCode); // Finalize outside. + SQLiteUtils::ResetStatement(rmDataStmt, false, errCode); // Finalize outside. return errCode; } @@ -745,33 +718,33 @@ int SQLiteSingleVerRelationalStorageExecutor::SaveSyncDataItem(const DataItem &d } int SQLiteSingleVerRelationalStorageExecutor::DeleteSyncLog(const DataItem &dataItem, - RelationalSyncDataInserter &inserter, sqlite3_stmt *&stmt) + RelationalSyncDataInserter &inserter, sqlite3_stmt *&rmLogStmt) { - if (stmt == nullptr) { - int errCode = inserter.GetDeleteLogStmt(dbHandle_, stmt); + if (rmLogStmt == nullptr) { + int errCode = inserter.GetDeleteLogStmt(dbHandle_, rmLogStmt); if (errCode != E_OK) { LOGE("[DeleteSyncLog] Get statement fail!"); return errCode; } } - int errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, dataItem.hashKey); // 1 means hashkey index + int errCode = SQLiteUtils::BindBlobToStatement(rmLogStmt, 1, dataItem.hashKey); // 1 means hashkey index if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); + SQLiteUtils::ResetStatement(rmLogStmt, true, errCode); return errCode; } if (mode_ != DistributedTableMode::COLLABORATION) { - errCode = SQLiteUtils::BindTextToStatement(stmt, 2, dataItem.dev); // 2 means device index + errCode = SQLiteUtils::BindTextToStatement(rmLogStmt, 2, dataItem.dev); // 2 means device index if (errCode != E_OK) { - SQLiteUtils::ResetStatement(stmt, true, errCode); + SQLiteUtils::ResetStatement(rmLogStmt, true, errCode); return errCode; } } - errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb_); + errCode = SQLiteUtils::StepWithRetry(rmLogStmt, isMemDb_); if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { errCode = E_OK; } - SQLiteUtils::ResetStatement(stmt, false, errCode); // Finalize outside. + SQLiteUtils::ResetStatement(rmLogStmt, false, errCode); // Finalize outside. return errCode; } @@ -1091,6 +1064,12 @@ int SQLiteSingleVerRelationalStorageExecutor::DeleteDistributedDeviceTable(const return errCode; } +int SQLiteSingleVerRelationalStorageExecutor::DeleteDistributedAllDeviceTableLog(const std::string &tableName) +{ + std::string deleteLogSql = "DELETE FROM " + DBConstant::RELATIONAL_PREFIX + tableName + "_log WHERE flag&0x02=0"; + return SQLiteUtils::ExecuteRawSQL(dbHandle_, deleteLogSql); +} + int SQLiteSingleVerRelationalStorageExecutor::DeleteDistributedDeviceTableLog(const std::string &device, const std::string &tableName) { @@ -1179,7 +1158,7 @@ int SQLiteSingleVerRelationalStorageExecutor::CheckAndCleanDistributedTable(cons } int SQLiteSingleVerRelationalStorageExecutor::CreateDistributedDeviceTable(const std::string &device, - const TableInfo &baseTbl) + const TableInfo &baseTbl, const StoreInfo &info) { if (dbHandle_ == nullptr) { return -E_INVALID_DB; @@ -1189,7 +1168,7 @@ int SQLiteSingleVerRelationalStorageExecutor::CreateDistributedDeviceTable(const return -E_INVALID_ARGS; } - std::string deviceTableName = DBCommon::GetDistributedTableName(device, baseTbl.GetTableName()); + std::string deviceTableName = DBCommon::GetDistributedTableName(device, baseTbl.GetTableName(), info); int errCode = SQLiteUtils::CreateSameStuTable(dbHandle_, baseTbl, deviceTableName); if (errCode != E_OK) { LOGE("Create device table failed. %d", errCode); @@ -1370,5 +1349,11 @@ int SQLiteSingleVerRelationalStorageExecutor::CheckEncryptedOrCorrupted() const } return errCode; } + +int SQLiteSingleVerRelationalStorageExecutor::GetExistsDeviceList(std::set &devices) const +{ + return SqliteMetaExecutor::GetExistsDevicesFromMeta(dbHandle_, SqliteMetaExecutor::MetaMode::RDB, + isMemDb_, devices); +} } // namespace DistributedDB #endif diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h index ecbda6642f94fd71111181e9e566953a3ddf9c42..b90d2a8c846c0e5f767e9cbf183cf56f499417b5 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_relational_storage_executor.h @@ -64,6 +64,8 @@ public: int DeleteDistributedDeviceTable(const std::string &device, const std::string &tableName); + int DeleteDistributedAllDeviceTableLog(const std::string &tableName); + int DeleteDistributedDeviceTableLog(const std::string &device, const std::string &tableName); int DeleteDistributedLogTable(const std::string &tableName); @@ -71,7 +73,7 @@ public: int CheckAndCleanDistributedTable(const std::vector &tableNames, std::vector &missingTables); - int CreateDistributedDeviceTable(const std::string &device, const TableInfo &baseTbl); + int CreateDistributedDeviceTable(const std::string &device, const TableInfo &baseTbl, const StoreInfo &info); int CheckQueryObjectLegal(const TableInfo &table, QueryObject &query, const std::string &schemaVersion); @@ -84,6 +86,8 @@ public: int CheckEncryptedOrCorrupted() const; + int GetExistsDeviceList(std::set &devices) const; + private: int GetDataItemForSync(sqlite3_stmt *statement, DataItem &dataItem, bool isGettingDeletedData) const; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp index eb31592a7a3e9fcff07604347cfe69b570d6b38a..3282948cf7a7a6d0904bd08102b82a6edc423b1d 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_engine.cpp @@ -392,7 +392,7 @@ int SQLiteSingleVerStorageEngine::ReleaseExecutor(SQLiteSingleVerStorageExecutor Recycle(databaseHandle); handle = nullptr; if (isCorrupted_) { - LOGE("Database is corrupted!"); + LOGE("Database is corrupted or invalid passwd!"); return -E_INVALID_PASSWD_OR_CORRUPTED_DB; // Externally imperceptible, used to terminate migration } return E_OK; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp index d7b1304654a3011cba5294b63607bd3fb42e0af7..91a6cc98a33856589bc78a25cec639101a8eb550 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.cpp @@ -24,11 +24,11 @@ #include "parcel.h" #include "platform_specific.h" #include "runtime_context.h" +#include "sqlite_meta_executor.h" #include "sqlite_single_ver_storage_executor_sql.h" namespace DistributedDB { namespace { -const int HASH_KEY_SIZE = 32; // size of SHA256_DIGEST_LENGTH void InitCommitNotifyDataKeyStatus(SingleVerNaturalStoreCommitNotifyData *committedData, const Key &hashKey, const DataOperStatus &dataStatus) @@ -1405,50 +1405,17 @@ int SQLiteSingleVerStorageExecutor::GetAllMetaKeys(std::vector &keys) const return errCode; } - errCode = GetAllKeys(statement, keys); + errCode = SqliteMetaExecutor::GetAllKeys(statement, isMemDb_, keys); SQLiteUtils::ResetStatement(statement, true, errCode); return errCode; } -int SQLiteSingleVerStorageExecutor::GetMetaKeysByKeyPrefix(const std::string &keyPre, - std::set &outKeys) const -{ - sqlite3_stmt *statement = nullptr; - const std::string &sqlStr = (attachMetaMode_ ? SELECT_ATTACH_META_KEYS_BY_PREFIX : SELECT_META_KEYS_BY_PREFIX); - int errCode = SQLiteUtils::GetStatement(dbHandle_, sqlStr, statement); - if (errCode != E_OK) { - LOGE("[SingleVerExe][GetAllKey] Get statement failed:%d", errCode); - return errCode; - } - - Key keyPrefix; - DBCommon::StringToVector(keyPre + '%', keyPrefix); - errCode = SQLiteUtils::BindBlobToStatement(statement, 1, keyPrefix); // 1: bind index for prefix key - if (errCode != E_OK) { - LOGE("[SingleVerExe][GetAllKey] Bind statement failed:%d", errCode); - SQLiteUtils::ResetStatement(statement, true, errCode); - return errCode; - } - - std::vector keys; - errCode = GetAllKeys(statement, keys); - SQLiteUtils::ResetStatement(statement, true, errCode); - for (const auto &it : keys) { - if (it.size() >= keyPre.size() + HASH_KEY_SIZE) { - outKeys.insert({it.begin() + keyPre.size(), it.begin() + keyPre.size() + HASH_KEY_SIZE}); - } else { - LOGW("[SingleVerExe][GetAllKey] Get invalid key, size=%zu", it.size()); - } - } - return errCode; -} - -int SQLiteSingleVerStorageExecutor::GetAllSyncedEntries(const std::string &deviceName, +int SQLiteSingleVerStorageExecutor::GetAllSyncedEntries(const std::string &hashDev, std::vector &entries) const { int errCode = E_OK; sqlite3_stmt *statement = nullptr; - if (deviceName.empty()) { + if (hashDev.empty()) { std::string sql = (executorState_ == ExecutorState::CACHE_ATTACH_MAIN ? SELECT_ALL_SYNC_ENTRIES_FROM_CACHEHANDLE : SELECT_ALL_SYNC_ENTRIES); errCode = SQLiteUtils::GetStatement(dbHandle_, sql, statement); @@ -1465,10 +1432,8 @@ int SQLiteSingleVerStorageExecutor::GetAllSyncedEntries(const std::string &devic return errCode; } - // When removing device data in cache mode, key is "remove", value is deviceID's hash string. - // Therefore, no need to transfer hash string when migrating. - std::string devName = isSyncMigrating_ ? deviceName : DBCommon::TransferHashString(deviceName); - std::vector devVect(devName.begin(), devName.end()); + // deviceName always hash string + std::vector devVect(hashDev.begin(), hashDev.end()); errCode = SQLiteUtils::BindBlobToStatement(statement, 1, devVect, true); // bind the 1st to device. if (errCode != E_OK) { LOGE("Failed to bind the synced device for all entries:%d", errCode); @@ -1514,34 +1479,6 @@ int SQLiteSingleVerStorageExecutor::GetAllEntries(sqlite3_stmt *statement, std:: return errCode; } -int SQLiteSingleVerStorageExecutor::GetAllKeys(sqlite3_stmt *statement, std::vector &keys) const -{ - if (statement == nullptr) { - return -E_INVALID_DB; - } - int errCode; - do { - errCode = SQLiteUtils::StepWithRetry(statement, isMemDb_); - if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) { - Key key; - errCode = SQLiteUtils::GetColumnBlobValue(statement, 0, key); - if (errCode != E_OK) { - break; - } - - keys.push_back(std::move(key)); - } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) { - errCode = E_OK; - break; - } else { - LOGE("SQLite step for getting all keys failed:%d", errCode); - break; - } - } while (true); - - return errCode; -} - int SQLiteSingleVerStorageExecutor::BindSavedSyncData(sqlite3_stmt *statement, const DataItem &dataItem, const Key &hashKey, const SyncDataDevices &devices, bool isUpdate) { @@ -1796,9 +1733,8 @@ int SQLiteSingleVerStorageExecutor::RemoveDeviceData(const std::string &deviceNa goto ERROR; } } else { - // Transfer the device name. - std::string devName = DBCommon::TransferHashString(deviceName); - std::vector devVect(devName.begin(), devName.end()); + // device name always hash string. + std::vector devVect(deviceName.begin(), deviceName.end()); errCode = SQLiteUtils::GetStatement(dbHandle_, REMOVE_DEV_DATA_SQL, statement); if (errCode != E_OK) { goto ERROR; @@ -2236,20 +2172,90 @@ uint64_t SQLiteSingleVerStorageExecutor::GetLogFileSize() const int SQLiteSingleVerStorageExecutor::GetExistsDevicesFromMeta(std::set &devices) { - int errCode = GetMetaKeysByKeyPrefix(DBConstant::DEVICEID_PREFIX_KEY, devices); + return SqliteMetaExecutor::GetExistsDevicesFromMeta(dbHandle_, + attachMetaMode_ ? SqliteMetaExecutor::MetaMode::KV_ATTACH : SqliteMetaExecutor::MetaMode::KV, + isMemDb_, devices); +} + +int SQLiteSingleVerStorageExecutor::UpdateKey(const UpdateKeyCallback &callback) +{ + if (dbHandle_ == nullptr) { + return -E_INVALID_DB; + } + UpdateContext context; + context.callback = callback; + int errCode = CreateFuncUpdateKey(context, &Translate, &CalHashKey); if (errCode != E_OK) { - LOGE("Get meta data key failed. err=%d", errCode); return errCode; } - errCode = GetMetaKeysByKeyPrefix(DBConstant::QUERY_SYNC_PREFIX_KEY, devices); + int executeErrCode = SQLiteUtils::ExecuteRawSQL(dbHandle_, UPDATE_SYNC_DATA_KEY_SQL); + context.callback = nullptr; + errCode = CreateFuncUpdateKey(context, nullptr, nullptr); + if (context.errCode != E_OK) { + return context.errCode; + } + if (executeErrCode != E_OK) { + return executeErrCode; + } if (errCode != E_OK) { - LOGE("Get meta data key failed. err=%d", errCode); return errCode; } - errCode = GetMetaKeysByKeyPrefix(DBConstant::DELETE_SYNC_PREFIX_KEY, devices); - if (errCode != E_OK) { - LOGE("Get meta data key failed. err=%d", errCode); + return E_OK; +} + +int SQLiteSingleVerStorageExecutor::CreateFuncUpdateKey(UpdateContext &context, + void(*translateFunc)(sqlite3_context *ctx, int argc, sqlite3_value **argv), + void(*calHashFunc)(sqlite3_context *ctx, int argc, sqlite3_value **argv)) const +{ + int errCode = sqlite3_create_function_v2(dbHandle_, FUNC_NAME_TRANSLATE_KEY, 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, + &context, translateFunc, nullptr, nullptr, nullptr); + if (errCode != SQLITE_OK) { + LOGE("[SqlSinExe][UpdateKey] Create func=translate_key failed=%d", errCode); + return SQLiteUtils::MapSQLiteErrno(errCode); } - return errCode; + errCode = sqlite3_create_function_v2(dbHandle_, FUNC_NAME_CAL_HASH_KEY, 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, + &context, calHashFunc, nullptr, nullptr, nullptr); + if (errCode != SQLITE_OK) { + LOGE("[SqlSinExe][UpdateKey] Create func=translate_key failed=%d", errCode); + return SQLiteUtils::MapSQLiteErrno(errCode); + } + return E_OK; +} + +void SQLiteSingleVerStorageExecutor::Translate(sqlite3_context *ctx, int argc, sqlite3_value **argv) +{ + if (ctx == nullptr || argc != 1 || argv == nullptr) { // i parameters, which are key + LOGW("[SqlSinExe][Translate] invalid param=%d", argc); + return; + } + auto context = static_cast(sqlite3_user_data(ctx)); + auto keyBlob = static_cast(sqlite3_value_blob(argv[0])); + int keyBlobLen = sqlite3_value_bytes(argv[0]); + Key oldKey; + if (keyBlob != nullptr && keyBlobLen > 0) { + oldKey = Key(keyBlob, keyBlob + keyBlobLen); + } + Key newKey; + context->callback(oldKey, newKey); + if (newKey.size() >= DBConstant::MAX_KEY_SIZE || newKey.empty()) { + LOGE("[SqlSinExe][Translate] invalid key len=%zu", newKey.size()); + context->errCode = -E_INVALID_ARGS; + sqlite3_result_error(ctx, "Update key is invalid", -1); + return; + } + context->newKey = newKey; + sqlite3_result_blob(ctx, newKey.data(), static_cast(newKey.size()), SQLITE_TRANSIENT); +} + +void SQLiteSingleVerStorageExecutor::CalHashKey(sqlite3_context *ctx, int argc, sqlite3_value **argv) +{ + if (ctx == nullptr || argc != 1 || argv == nullptr) { + LOGW("[SqlSinExe][Translate] invalid param=%d", argc); + return; + } + auto context = static_cast(sqlite3_user_data(ctx)); + Key hashKey; + DBCommon::CalcValueHash(context->newKey, hashKey); + sqlite3_result_blob(ctx, hashKey.data(), static_cast(hashKey.size()), SQLITE_TRANSIENT); } } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.h index 255792ccb48051f3c7775b39f74de686c2216298..57a3a1623ffb9c62edfa555cdb19848e66aba8f9 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor.h @@ -121,9 +121,8 @@ public: // Get all the meta keys. int GetAllMetaKeys(std::vector &keys) const; - int GetMetaKeysByKeyPrefix(const std::string &keyPre, std::set &outKeys) const; - int GetAllSyncedEntries(const std::string &deviceName, std::vector &entries) const; + int GetAllSyncedEntries(const std::string &hashDev, std::vector &entries) const; int SaveSyncDataItem(DataItem &dataItem, const DeviceInfo &deviceInfo, Timestamp &maxStamp, SingleVerNaturalStoreCommitNotifyData *committedData, bool isPermitForceWrite = true); @@ -136,7 +135,7 @@ public: int RemoveDeviceData(const std::string &deviceName); - int RemoveDeviceDataInCacheMode(const std::string &deviceName, bool isNeedNotify, uint64_t recordVersion) const; + int RemoveDeviceDataInCacheMode(const std::string &hashDev, bool isNeedNotify, uint64_t recordVersion) const; void InitCurrentMaxStamp(Timestamp &maxStamp); @@ -251,6 +250,8 @@ public: int GetExistsDevicesFromMeta(std::set &devices); + int UpdateKey(const UpdateKeyCallback &callback); + private: struct SaveRecordStatements { sqlite3_stmt *queryStatement = nullptr; @@ -265,6 +266,12 @@ private: } }; + struct UpdateContext { + int errCode = E_OK; + Key newKey; + UpdateKeyCallback callback; + }; + void PutIntoCommittedData(const DataItem &itemPut, const DataItem &itemGet, const DataOperStatus &status, SingleVerNaturalStoreCommitNotifyData *committedData); @@ -301,8 +308,6 @@ private: int InitResultSet(QueryObject &queryObj, sqlite3_stmt *&countStmt); - int GetAllKeys(sqlite3_stmt *statement, std::vector &keys) const; - int GetAllEntries(sqlite3_stmt *statement, std::vector &entries) const; int BindPutKvData(sqlite3_stmt *statement, const Key &key, const Value &value, Timestamp timestamp, @@ -396,6 +401,14 @@ private: int CheckMissQueryDataItem(sqlite3_stmt *stmt, const std::string &deviceName, DataItem &item); + int CreateFuncUpdateKey(UpdateContext &context, + void(*translateFunc)(sqlite3_context *ctx, int argc, sqlite3_value **argv), + void(*calHashFunc)(sqlite3_context *ctx, int argc, sqlite3_value **argv)) const; + + static void Translate(sqlite3_context *ctx, int argc, sqlite3_value **argv); + + static void CalHashKey(sqlite3_context *ctx, int argc, sqlite3_value **argv); + sqlite3_stmt *getSyncStatement_; sqlite3_stmt *getResultRowIdStatement_; sqlite3_stmt *getResultEntryStatement_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_cache.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_cache.cpp index af15b3710944e41e87f230360e78f20e03ebe371..82ec7a98750b49bd6f931892342f334bc05452d3 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_cache.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_cache.cpp @@ -77,12 +77,11 @@ int SQLiteSingleVerStorageExecutor::ResetForMigrateCacheData() return CheckCorruptedStatus(errCode); } -int SQLiteSingleVerStorageExecutor::RemoveDeviceDataInCacheMode(const std::string &deviceName, +int SQLiteSingleVerStorageExecutor::RemoveDeviceDataInCacheMode(const std::string &hashDev, bool isNeedNotify, uint64_t recordVersion) const { - // Transfer the device name. - std::string devName = DBCommon::TransferHashString(deviceName); - std::vector devVect(devName.begin(), devName.end()); + // device name always hash string. + std::vector devVect(hashDev.begin(), hashDev.end()); Key hashKey; int errCode = DBCommon::CalcValueHash(REMOVE_DEVICE_DATA_KEY, hashKey); diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_sql.h b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_sql.h index 5fceeaebb415b255acb25d90ebc0c97dd261b5da..17ad51839d86f031a4685599c0d77de19e4a5289 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_sql.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_single_ver_storage_executor_sql.h @@ -230,6 +230,13 @@ namespace DistributedDB { const std::string GET_SYNC_DATA_TIRGGER_SQL = "SELECT name FROM SQLITE_MASTER WHERE TYPE = 'trigger' AND TBL_NAME = 'sync_data' AND name like ?;"; + constexpr const char *UPDATE_SYNC_DATA_KEY_SQL = + "UPDATE sync_data SET key=translate_key(key), hash_key=cal_hash_key(key) WHERE flag&0x01=0"; + + constexpr const char *FUNC_NAME_TRANSLATE_KEY = "translate_key"; + + constexpr const char *FUNC_NAME_CAL_HASH_KEY = "cal_hash_key"; + const int BIND_KV_KEY_INDEX = 1; const int BIND_KV_VAL_INDEX = 2; const int BIND_LOCAL_TIMESTAMP_INDEX = 3; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp index 687b40b4aad9b3a652e0550b0db53df18b5c0403..f37ee25a784d72cf4bb7fa3f9787abf84bb48473 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sqlite/sqlite_utils.cpp @@ -248,12 +248,6 @@ int SQLiteUtils::BindTextToStatement(sqlite3_stmt *statement, int index, const s return -E_INVALID_ARGS; } - // Check empty value. - if (str.empty()) { - sqlite3_bind_null(statement, index); - return E_OK; - } - int errCode = sqlite3_bind_text(statement, index, str.c_str(), str.length(), SQLITE_TRANSIENT); if (errCode != SQLITE_OK) { LOGE("[SQLiteUtil][Bind text]Failed to bind the value:%d", errCode); @@ -1097,20 +1091,31 @@ int SQLiteUtils::SetUserVer(sqlite3 *db, int version) int SQLiteUtils::MapSQLiteErrno(int errCode) { - if (errCode == SQLITE_OK) { - return E_OK; - } else if (errCode == SQLITE_IOERR) { - if (errno == EKEYREVOKED) { - return -E_EKEYREVOKED; - } - } else if (errCode == SQLITE_CORRUPT || errCode == SQLITE_NOTADB) { - return -E_INVALID_PASSWD_OR_CORRUPTED_DB; - } else if (errCode == SQLITE_LOCKED || errCode == SQLITE_BUSY) { - return -E_BUSY; - } else if (errCode == SQLITE_ERROR && errno == EKEYREVOKED) { - return -E_EKEYREVOKED; - } else if (errCode == SQLITE_AUTH) { - return -E_DENIED_SQL; + switch (errCode) { + case SQLITE_OK: + return E_OK; + case SQLITE_IOERR: + if (errno == EKEYREVOKED) { + return -E_EKEYREVOKED; + } + break; + case SQLITE_CORRUPT: + case SQLITE_NOTADB: + return -E_INVALID_PASSWD_OR_CORRUPTED_DB; + case SQLITE_LOCKED: + case SQLITE_BUSY: + return -E_BUSY; + case SQLITE_ERROR: + if (errno == EKEYREVOKED) { + return -E_EKEYREVOKED; + } + break; + case SQLITE_AUTH: + return -E_DENIED_SQL; + case SQLITE_CONSTRAINT: + return -E_CONSTRAINT; + default: + break; } return -errCode; } @@ -2260,7 +2265,7 @@ int SQLiteUtils::SetKeyInner(sqlite3 *db, CipherType type, const CipherPassword int SQLiteUtils::BindDataValueByType(sqlite3_stmt *statement, const std::optional &data, int cid) { int errCode = E_OK; - StorageType type = data.value().GetType(); + StorageType type = data.value_or(DataValue()).GetType(); switch (type) { case StorageType::STORAGE_TYPE_INTEGER: { int64_t intData = 0; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp index 8a8e8cda3efc6d58c2733f94367c8c96f6dadf15..84e6cb817f7b10f7abb404f1bae1dbe6cbecd549 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.cpp @@ -42,61 +42,67 @@ StorageEngine::~StorageEngine() CloseExecutor(); } -int StorageEngine::Init() +int StorageEngine::InitReadWriteExecutors() { - if (isInitialized_.load()) { - LOGD("Storage engine has been initialized!"); - return E_OK; - } - int errCode = E_OK; - { - std::scoped_lock initLock(writeMutex_, readMutex_); - // only for create the database avoid the minimum number is 0. - StorageExecutor *handle = nullptr; - if (engineAttr_.minReadNum == 0 && engineAttr_.minWriteNum == 0) { - errCode = CreateNewExecutor(true, handle); - if (errCode != E_OK) { - goto END; - } - - if (handle != nullptr) { - delete handle; - handle = nullptr; - } + std::scoped_lock initLock(writeMutex_, readMutex_); + // only for create the database avoid the minimum number is 0. + StorageExecutor *handle = nullptr; + if (engineAttr_.minReadNum == 0 && engineAttr_.minWriteNum == 0) { + errCode = CreateNewExecutor(true, handle); + if (errCode != E_OK) { + return errCode; } - for (uint32_t i = 0; i < engineAttr_.minWriteNum; i++) { + if (handle != nullptr) { + delete handle; handle = nullptr; - errCode = CreateNewExecutor(true, handle); - if (errCode != E_OK) { - goto END; - } - AddStorageExecutor(handle); } + } - for (uint32_t i = 0; i < engineAttr_.minReadNum; i++) { - handle = nullptr; - errCode = CreateNewExecutor(false, handle); - if (errCode != E_OK) { - goto END; - } - AddStorageExecutor(handle); + for (uint32_t i = 0; i < engineAttr_.minWriteNum; i++) { + handle = nullptr; + errCode = CreateNewExecutor(true, handle); + if (errCode != E_OK) { + return errCode; } + AddStorageExecutor(handle); } -END: + for (uint32_t i = 0; i < engineAttr_.minReadNum; i++) { + handle = nullptr; + errCode = CreateNewExecutor(false, handle); + if (errCode != E_OK) { + return errCode; + } + AddStorageExecutor(handle); + } + return E_OK; +} + + +int StorageEngine::Init() +{ + if (isInitialized_.load()) { + LOGD("Storage engine has been initialized!"); + return E_OK; + } + + int errCode = InitReadWriteExecutors(); if (errCode == E_OK) { isInitialized_.store(true); + initCondition_.notify_all(); return E_OK; } else if (errCode == -E_EKEYREVOKED) { // Assumed file system has classification function, can only get one write handle std::unique_lock lock(writeMutex_); if (!writeIdleList_.empty() || !writeUsingList_.empty()) { isInitialized_.store(true); + initCondition_.notify_all(); return E_OK; } } + initCondition_.notify_all(); Release(); return errCode; } @@ -109,10 +115,16 @@ StorageExecutor *StorageEngine::FindExecutor(bool writable, OperatePerm perm, in return nullptr; } - if (!isInitialized_.load()) { - LOGE("Storage engine is not initialized"); - errCode = -E_BUSY; // Usually in reinitialize engine, return BUSY - return nullptr; + { + std::unique_lock lock(initMutex_); + bool result = initCondition_.wait_for(lock, std::chrono::seconds(waitTime), [this]() { + return isInitialized_.load(); + }); + if (!result || !isInitialized_.load()) { + LOGE("Storage engine is not initialized"); + errCode = -E_BUSY; // Usually in reinitialize engine, return BUSY + return nullptr; + } } if (writable) { diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.h b/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.h index 1a9dd227a735d5b6168b8fd11b5fd694dec31c15..cb9a7d21a8cbdcfbebfdb8aa52b11f4a8c74d331 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/storage_engine.h @@ -89,6 +89,8 @@ protected: static bool CheckEngineAttr(const StorageEngineAttr &poolSize); + int InitReadWriteExecutors(); + StorageEngineAttr engineAttr_; bool isUpdated_; std::atomic isMigrating_; @@ -114,6 +116,8 @@ private: static const int MAX_WRITE_SIZE; static const int MAX_READ_SIZE; + std::mutex initMutex_; + std::condition_variable initCondition_; std::atomic isInitialized_; OperatePerm perm_; bool operateAbort_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.cpp index 0c5e86ca0b66ba6fddd98be67027eb8fd6ff144c..e6540734765c9fbee9aec5a6f7b3496f48c61f27 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.cpp @@ -66,7 +66,7 @@ void SyncAbleEngine::Close() void SyncAbleEngine::EnableAutoSync(bool enable) { - if (!started_) { + if (NeedStartSyncer()) { StartSyncer(); } return syncer_.EnableAutoSync(enable); @@ -85,7 +85,7 @@ int SyncAbleEngine::DisableManualSync(void) // Get The current virtual timestamp uint64_t SyncAbleEngine::GetTimestamp() { - if (!started_) { + if (NeedStartSyncer()) { StartSyncer(); } return syncer_.GetTimestamp(); @@ -93,7 +93,7 @@ uint64_t SyncAbleEngine::GetTimestamp() int SyncAbleEngine::EraseDeviceWaterMark(const std::string &deviceId, bool isNeedHash, const std::string &tableName) { - if (!started_) { + if (NeedStartSyncer()) { StartSyncer(); } return syncer_.EraseDeviceWaterMark(deviceId, isNeedHash, tableName); @@ -176,6 +176,15 @@ void SyncAbleEngine::StopSyncerWithNoLock(bool isClosedOperation) void SyncAbleEngine::UserChangeHandle() { + if (store_ == nullptr) { + LOGD("[SyncAbleEngine] RDB got null sync interface in userChange."); + return; + } + bool isSyncDualTupleMode = store_->GetDbProperties().GetBoolProp(DBProperties::SYNC_DUAL_TUPLE_MODE, false); + if (!isSyncDualTupleMode) { + LOGD("[SyncAbleEngine] no use syncDualTupleMode, abort userChange"); + return; + } std::unique_lock lock(syncerOperateLock_); if (closed_) { LOGI("RDB is already closed"); @@ -270,4 +279,19 @@ int SyncAbleEngine::RemoteQuery(const std::string &device, const RemoteCondition } return syncer_.RemoteQuery(device, condition, timeout, connectionId, result); } + +bool SyncAbleEngine::NeedStartSyncer() const +{ + // don't start when check callback got not active + // equivalent to !(!isSyncNeedActive_ && isSyncModuleActiveCheck_) + return !started_ && (isSyncNeedActive_ || !isSyncModuleActiveCheck_); +} + +int SyncAbleEngine::GetHashDeviceId(const std::string &clientId, std::string &hashDevId) +{ + if (NeedStartSyncer()) { + StartSyncer(); + } + return syncer_.GetHashDeviceId(clientId, hashDevId); +} } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.h b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.h index 9afc0ff9c969cef01e135b2fc91aa6a9d06dac09..3b45461fc082d74719e7c671f6cdc7da77f92629 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_engine.h @@ -54,6 +54,8 @@ public: int RemoteQuery(const std::string &device, const RemoteCondition &condition, uint64_t timeout, uint64_t connectionId, std::shared_ptr &result); + + int GetHashDeviceId(const std::string &clientId, std::string &hashDevId); private: // Start syncer int StartSyncer(bool isCheckSyncActive = false, bool isNeedActive = true); @@ -75,6 +77,8 @@ private: void ChangeUserListener(); + bool NeedStartSyncer() const; + SyncerProxy syncer_; // use for sync Interactive std::atomic started_; std::atomic closed_; diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.cpp b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.cpp index 711621e3ce1071c8752ce9b4e4b4bc398894aeee..b16a280728850fe2fa91090f3d368e9b09c58989 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.cpp +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.cpp @@ -92,7 +92,7 @@ int SyncAbleKvDB::Sync(const ISyncer::SyncParma &parma, uint64_t connectionId) void SyncAbleKvDB::EnableAutoSync(bool enable) { - if (!started_) { + if (NeedStartSyncer()) { StartSyncer(); } return syncer_.EnableAutoSync(enable); @@ -100,7 +100,7 @@ void SyncAbleKvDB::EnableAutoSync(bool enable) void SyncAbleKvDB::WakeUpSyncer() { - if (!started_) { + if (NeedStartSyncer()) { StartSyncer(); } } @@ -232,6 +232,12 @@ void SyncAbleKvDB::UserChangeHandle() LOGF("KvDB got null sync interface."); return; } + bool isSyncDualTupleMode = syncInterface->GetDbProperties(). + GetBoolProp(KvDBProperties::SYNC_DUAL_TUPLE_MODE, false); + if (!isSyncDualTupleMode) { + LOGD("[SyncAbleKvDB] no use syncDualTupleMode, abort userChange"); + return; + } std::unique_lock lock(syncerOperateLock_); if (closed_) { LOGI("kvDB is already closed"); @@ -264,7 +270,7 @@ void SyncAbleKvDB::ChangeUserListener() // Get The current virtual timestamp uint64_t SyncAbleKvDB::GetTimestamp() { - if (!started_ && !isSyncModuleActiveCheck_) { + if (NeedStartSyncer()) { StartSyncer(); } return syncer_.GetTimestamp(); @@ -278,7 +284,7 @@ uint32_t SyncAbleKvDB::GetAppendedLen() const int SyncAbleKvDB::EraseDeviceWaterMark(const std::string &deviceId, bool isNeedHash) { - if (!started_) { + if (NeedStartSyncer()) { StartSyncer(); } return syncer_.EraseDeviceWaterMark(deviceId, isNeedHash); @@ -378,11 +384,17 @@ void SyncAbleKvDB::NotifyRemotePushFinishedInner(const std::string &targetId) co int SyncAbleKvDB::SetSyncRetry(bool isRetry) { + if (NeedStartSyncer()) { + StartSyncer(); + } return syncer_.SetSyncRetry(isRetry); } int SyncAbleKvDB::SetEqualIdentifier(const std::string &identifier, const std::vector &targets) { + if (NeedStartSyncer()) { + StartSyncer(); + } return syncer_.SetEqualIdentifier(identifier, targets); } @@ -401,4 +413,19 @@ int SyncAbleKvDB::GetSyncDataSize(const std::string &device, size_t &size) const { return syncer_.GetSyncDataSize(device, size); } + +bool SyncAbleKvDB::NeedStartSyncer() const +{ + // don't start when check callback got not active + // equivalent to !(!isSyncNeedActive_ && isSyncModuleActiveCheck_) + return !started_ && (isSyncNeedActive_ || !isSyncModuleActiveCheck_); +} + +int SyncAbleKvDB::GetHashDeviceId(const std::string &clientId, std::string &hashDevId) +{ + if (NeedStartSyncer()) { + StartSyncer(); + } + return syncer_.GetHashDeviceId(clientId, hashDevId); +} } diff --git a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.h b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.h index 86171bbac587c69ec2fb505d3d1231dad8e20a51..c5e08092dceafd1ad5ea55a08c17f02127075010 100644 --- a/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.h +++ b/kv_store/frameworks/libs/distributeddb/storage/src/sync_able_kvdb.h @@ -87,6 +87,8 @@ public: int GetSyncDataSize(const std::string &device, size_t &size) const; + int GetHashDeviceId(const std::string &clientId, std::string &hashDevId); + protected: virtual IKvDBSyncInterface *GetSyncInterface() = 0; @@ -119,6 +121,8 @@ protected: private: int RegisterEventType(EventType type); + bool NeedStartSyncer() const; + SyncerProxy syncer_; std::atomic started_; std::atomic closed_; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/include/isyncer.h b/kv_store/frameworks/libs/distributeddb/syncer/include/isyncer.h index 42a3320d9c6badfa0b916eb5440a20c179759143..6f9706398eba1d8735d900e1dc780b613be52b01 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/include/isyncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/include/isyncer.h @@ -123,6 +123,8 @@ public: uint64_t timeout, uint64_t connectionId, std::shared_ptr &result) = 0; virtual int GetSyncDataSize(const std::string &device, size_t &size) const = 0; + + virtual int GetHashDeviceId(const std::string &clientId, std::string &hashDevId) = 0; }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/syncer/include/syncer_proxy.h b/kv_store/frameworks/libs/distributeddb/syncer/include/syncer_proxy.h index 1d6294af478547c6360d7ea5146d08a438587f15..2725237ae52671efb41e0a17db308f0958e15b68 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/include/syncer_proxy.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/include/syncer_proxy.h @@ -107,6 +107,7 @@ public: int GetSyncDataSize(const std::string &device, size_t &size) const override; + int GetHashDeviceId(const std::string &clientId, std::string &hashDevId) override; private: std::mutex syncerLock_; std::shared_ptr syncer_; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp index 8227f3c29e28f45645da4bfee396cd75ea6bc2d0..e018e014fccdd506daf7b181b8ce8812317ce889 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.cpp @@ -284,10 +284,26 @@ int GenericSyncer::StopSync(uint64_t connectionId) uint64_t GenericSyncer::GetTimestamp() { - if (timeHelper_ == nullptr) { + std::shared_ptr timeHelper = nullptr; + ISyncInterface *storage = nullptr; + { + std::lock_guard lock(syncerLock_); + timeHelper = timeHelper_; + if (syncInterface_ != nullptr) { + storage = syncInterface_; + storage->IncRefCount(); + } + } + if (storage == nullptr) { + return TimeHelper::GetSysCurrentTime(); + } + if (timeHelper == nullptr) { + storage->DecRefCount(); return TimeHelper::GetSysCurrentTime(); } - return timeHelper_->GetTime(); + uint64_t timestamp = timeHelper->GetTime(); + storage->DecRefCount(); + return timestamp; } void GenericSyncer::QueryAutoSync(const InternalSyncParma ¶m) @@ -446,13 +462,11 @@ bool GenericSyncer::IsValidMode(int mode) const return true; } -int GenericSyncer::SyncConditionCheck(QuerySyncObject &query, int mode, bool isQuerySync, - const std::vector &devices) const +int GenericSyncer::SyncConditionCheck(const SyncParma ¶m, const ISyncEngine *engine, ISyncInterface *storage) const { - (void)query; - (void)mode; - (void)isQuerySync; - (void)(devices); + (void)param; + (void)engine; + (void)storage; return E_OK; } @@ -785,20 +799,34 @@ int GenericSyncer::StatusCheck() const int GenericSyncer::SyncPreCheck(const SyncParma ¶m) const { - std::lock_guard lock(syncerLock_); - int errCode = StatusCheck(); - if (errCode != E_OK) { - return errCode; - } - if (!IsValidDevices(param.devices) || !IsValidMode(param.mode)) { - return -E_INVALID_ARGS; - } - if (IsQueuedManualSyncFull(param.mode, param.wait)) { - LOGE("[Syncer] -E_BUSY"); - return -E_BUSY; + ISyncEngine *engine = nullptr; + ISyncInterface *storage = nullptr; + int errCode = E_OK; + { + std::lock_guard lock(syncerLock_); + errCode = StatusCheck(); + if (errCode != E_OK) { + return errCode; + } + if (!IsValidDevices(param.devices) || !IsValidMode(param.mode)) { + return -E_INVALID_ARGS; + } + if (IsQueuedManualSyncFull(param.mode, param.wait)) { + LOGE("[Syncer] -E_BUSY"); + return -E_BUSY; + } + storage = syncInterface_; + engine = syncEngine_; + if (storage == nullptr || engine == nullptr) { + return -E_BUSY; + } + storage->IncRefCount(); + RefObject::IncObjRef(engine); } - QuerySyncObject syncQuery = param.syncQuery; - return SyncConditionCheck(syncQuery, param.mode, param.isQuerySync, param.devices); + errCode = SyncConditionCheck(param, engine, storage); + storage->DecRefCount(); + RefObject::DecObjRef(engine); + return errCode; } void GenericSyncer::InitSyncOperation(SyncOperation *operation, const SyncParma ¶m) @@ -1023,4 +1051,9 @@ bool GenericSyncer::IsNeedActive(ISyncInterface *syncInterface) } return true; } + +int GenericSyncer::GetHashDeviceId(const std::string &clientId, std::string &hashDevId) +{ + return -E_NOT_SUPPORT; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.h b/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.h index 7d89adbfa14df566dbd95886b4fbfe81b21c538f..f2146216e36d3c0703793bf8a83b2de2212ea79f 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/generic_syncer.h @@ -104,6 +104,7 @@ public: int GetSyncDataSize(const std::string &device, size_t &size) const override; + int GetHashDeviceId(const std::string &clientId, std::string &hashDevId) override; protected: // trigger query auto sync or auto subscribe @@ -143,8 +144,7 @@ protected: // Check if the mode arg is valid bool IsValidMode(int mode) const; - virtual int SyncConditionCheck(QuerySyncObject &query, int mode, bool isQuerySync, - const std::vector &devices) const; + virtual int SyncConditionCheck(const SyncParma ¶m, const ISyncEngine *engine, ISyncInterface *storage) const; // Check if the devices arg is valid bool IsValidDevices(const std::vector &devices) const; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/isync_task_context.h b/kv_store/frameworks/libs/distributeddb/syncer/src/isync_task_context.h index 3c51184b44a40afe66c7b8f0d4e67182669904f6..e489afd54955979faa31aee5c22ac15ca8d6a356 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/isync_task_context.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/isync_task_context.h @@ -68,7 +68,7 @@ public: // Move to next target to sync virtual void MoveToNextTarget() = 0; - virtual int GetNextTarget(bool isNeedSetFinished) = 0; + virtual int GetNextTarget() = 0; // Get the current task syncId virtual uint32_t GetSyncId() const = 0; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.cpp index 5bfc2b5a232fda015508cef07a63841a0730214d..ffbad817c07eed5f0eceb850c2f62940a28edd3a 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.cpp @@ -30,6 +30,7 @@ namespace { const int STR_TO_LL_BY_DEVALUE = 10; // store local timeoffset;this is a special key; const std::string LOCALTIME_OFFSET_KEY = "localTimeOffset"; + const char *CLIENT_ID_PREFIX_KEY = "clientId"; } Metadata::Metadata() @@ -124,7 +125,7 @@ int Metadata::SavePeerWaterMark(const DeviceID &deviceId, uint64_t inValue, bool GetMetaDataValue(deviceId, metadata, isNeedHash); metadata.peerWaterMark = inValue; LOGD("Metadata::SavePeerWaterMark = %" PRIu64, inValue); - return SaveMetaDataValue(deviceId, metadata); + return SaveMetaDataValue(deviceId, metadata, isNeedHash); } int Metadata::SaveLocalTimeOffset(TimeOffset timeOffset) @@ -160,9 +161,9 @@ int Metadata::EraseDeviceWaterMark(const std::string &deviceId, bool isNeedHash, // try to erase all the waterMark // erase deleteSync recv waterMark WaterMark waterMark = 0; - int errCodeDeleteSync = SetRecvDeleteSyncWaterMark(deviceId, waterMark); + int errCodeDeleteSync = SetRecvDeleteSyncWaterMark(deviceId, waterMark, isNeedHash); // erase querySync recv waterMark - int errCodeQuerySync = ResetRecvQueryWaterMark(deviceId, tableName); + int errCodeQuerySync = ResetRecvQueryWaterMark(deviceId, tableName, isNeedHash); // peerWaterMark must be erased at last int errCode = SavePeerWaterMark(deviceId, 0, isNeedHash); if (errCode != E_OK) { @@ -194,7 +195,7 @@ Timestamp Metadata::GetLastLocalTime() const return lastLocalTime_; } -int Metadata::SaveMetaDataValue(const DeviceID &deviceId, const MetaDataValue &inValue) +int Metadata::SaveMetaDataValue(const DeviceID &deviceId, const MetaDataValue &inValue, bool isNeedHash) { std::vector value; int errCode = SerializeMetaData(inValue, value); @@ -203,7 +204,7 @@ int Metadata::SaveMetaDataValue(const DeviceID &deviceId, const MetaDataValue &i } DeviceID hashDeviceId; - GetHashDeviceId(deviceId, hashDeviceId, true); + GetHashDeviceId(deviceId, hashDeviceId, isNeedHash); std::vector key; DBCommon::StringToVector(hashDeviceId, key); errCode = SetMetadataToDb(key, value); @@ -232,12 +233,11 @@ int Metadata::SerializeMetaData(const MetaDataValue &inValue, std::vector &inValue, MetaDataValue &outValue) const +int Metadata::DeSerializeMetaData(const std::vector &inValue, MetaDataValue &outValue) { if (inValue.empty()) { return -E_INVALID_ARGS; } - errno_t err = memcpy_s(&outValue, sizeof(MetaDataValue), inValue.data(), inValue.size()); if (err != EOK) { return -E_SECUREC_ERROR; @@ -457,14 +457,14 @@ int Metadata::GetRecvDeleteSyncWaterMark(const DeviceID &deviceId, WaterMark &wa return E_OK; } -int Metadata::SetRecvDeleteSyncWaterMark(const DeviceID &deviceId, const WaterMark &waterMark) +int Metadata::SetRecvDeleteSyncWaterMark(const DeviceID &deviceId, const WaterMark &waterMark, bool isNeedHash) { - return querySyncWaterMarkHelper_.SetRecvDeleteSyncWaterMark(deviceId, waterMark); + return querySyncWaterMarkHelper_.SetRecvDeleteSyncWaterMark(deviceId, waterMark, isNeedHash); } -int Metadata::ResetRecvQueryWaterMark(const DeviceID &deviceId, const std::string &tableName) +int Metadata::ResetRecvQueryWaterMark(const DeviceID &deviceId, const std::string &tableName, bool isNeedHash) { - return querySyncWaterMarkHelper_.ResetRecvQueryWaterMark(deviceId, tableName); + return querySyncWaterMarkHelper_.ResetRecvQueryWaterMark(deviceId, tableName, isNeedHash); } void Metadata::GetDbCreateTime(const DeviceID &deviceId, uint64_t &outValue) @@ -511,7 +511,7 @@ int Metadata::ResetMetaDataAfterRemoveData(const DeviceID &deviceId) GetHashDeviceId(deviceId, hashDeviceId, true); if (metadataMap_.find(hashDeviceId) != metadataMap_.end()) { metadata = metadataMap_[hashDeviceId]; - metadata.clearDeviceDataMark = 0; + metadata.clearDeviceDataMark = 0; // clear mark return SaveMetaDataValue(deviceId, metadata); } return -E_NOT_FOUND; @@ -570,4 +570,50 @@ void Metadata::RemoveQueryFromRecordSet(const DeviceID &deviceId, const std::str iter->second.erase(hashqueryId); } } + +int Metadata::SaveClientId(const std::string &deviceId, const std::string &clientId) +{ + { + // already save in cache + std::lock_guard autoLock(clientIdLock_); + if (clientIdCache_[deviceId] == clientId) { + return E_OK; + } + } + std::string keyStr; + keyStr.append(CLIENT_ID_PREFIX_KEY).append(clientId); + std::string valueStr = DBCommon::TransferHashString(deviceId); + Key key; + DBCommon::StringToVector(keyStr, key); + Value value; + DBCommon::StringToVector(valueStr, value); + int errCode = SetMetadataToDb(key, value); + if (errCode != E_OK) { + return errCode; + } + std::lock_guard autoLock(clientIdLock_); + clientIdCache_[deviceId] = clientId; + return E_OK; +} + +int Metadata::GetHashDeviceId(const std::string &clientId, std::string &hashDevId) +{ + // don't use cache here avoid invalid cache + std::string keyStr; + keyStr.append(CLIENT_ID_PREFIX_KEY).append(clientId); + Key key; + DBCommon::StringToVector(keyStr, key); + Value value; + int errCode = GetMetadataFromDb(key, value); + if (errCode == -E_NOT_FOUND) { + LOGD("[Metadata] not found clientId"); + return -E_NOT_SUPPORT; + } + if (errCode != E_OK) { + LOGE("[Metadata] reload clientId failed %d", errCode); + return errCode; + } + DBCommon::VectorToString(value, hashDevId); + return E_OK; +} } // namespace DistributedDB \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h b/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h index 26e2287bf5fac7df735fe291101e80f38eb7eaac..a73d60fafb289e03a549b4336067354563bec78a 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/meta_data.h @@ -93,7 +93,7 @@ public: // if the sendWatermark less than device watermark int GetSendDeleteSyncWaterMark(const std::string &deviceId, WaterMark &waterMark, bool isAutoLift = true); - int SetRecvDeleteSyncWaterMark(const std::string &deviceId, const WaterMark &waterMark); + int SetRecvDeleteSyncWaterMark(const std::string &deviceId, const WaterMark &waterMark, bool isNeedHash = true); // the deleteSync's recvWatermark will increase by the device watermark // if the recvWatermark less than device watermark @@ -111,16 +111,20 @@ public: uint64_t GetQueryLastTimestamp(const DeviceID &deviceId, const std::string &queryId) const; void RemoveQueryFromRecordSet(const DeviceID &deviceId, const std::string &queryId); + + int SaveClientId(const std::string &deviceId, const std::string &clientId); + + int GetHashDeviceId(const std::string &clientId, std::string &hashDevId); private: - int SaveMetaDataValue(const DeviceID &deviceId, const MetaDataValue &inValue); + int SaveMetaDataValue(const DeviceID &deviceId, const MetaDataValue &inValue, bool isNeedHash = true); // sync module need hash devices id void GetMetaDataValue(const DeviceID &deviceId, MetaDataValue &outValue, bool isNeedHash); - int SerializeMetaData(const MetaDataValue &inValue, std::vector &outValue); + static int SerializeMetaData(const MetaDataValue &inValue, std::vector &outValue); - int DeSerializeMetaData(const std::vector &inValue, MetaDataValue &outValue) const; + static int DeSerializeMetaData(const std::vector &inValue, MetaDataValue &outValue); int GetMetadataFromDb(const std::vector &key, std::vector &outValue) const; @@ -143,7 +147,7 @@ private: int LoadDeviceIdDataToMap(const Key &key); // reset the waterMark to zero - int ResetRecvQueryWaterMark(const DeviceID &deviceId, const std::string &tableName = ""); + int ResetRecvQueryWaterMark(const DeviceID &deviceId, const std::string &tableName, bool isNeedHash); // store localTimeOffset in ram; if change, should add a lock first, change here and metadata, // then release lock @@ -167,6 +171,9 @@ private: // queryId is not in set while key is not found from db first time, and return lastTimestamp = INT64_MAX // if query is in set return 0 while not found from db, means already sync before, don't trigger again mutable std::map> queryIdMap_; + + std::mutex clientIdLock_; + std::map clientIdCache_; }; } // namespace DistributedDB #endif diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.cpp index 70c37ffa604f6a4a4d341705b9df7f80cf0035ce..575d8c233caa3aa5237b7add1e035c6d59a9062f 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.cpp @@ -301,6 +301,8 @@ DeviceID QuerySyncWaterMarkHelper::GetHashQuerySyncDeviceId(const DeviceID &devi int QuerySyncWaterMarkHelper::GetDeleteSyncWaterMark(const std::string &deviceId, DeleteWaterMark &deleteWaterMark) { std::string hashId = GetHashDeleteSyncDeviceId(deviceId); + // lock prevent different thread visit deleteSyncCache_ + std::lock_guard autoLock(deleteSyncLock_); return GetDeleteWaterMarkFromCache(hashId, deleteWaterMark); } @@ -308,19 +310,22 @@ int QuerySyncWaterMarkHelper::SetSendDeleteSyncWaterMark(const DeviceID &deviceI { std::string hashId = GetHashDeleteSyncDeviceId(deviceId); DeleteWaterMark deleteWaterMark; + // lock prevent different thread visit deleteSyncCache_ + std::lock_guard autoLock(deleteSyncLock_); GetDeleteWaterMarkFromCache(hashId, deleteWaterMark); deleteWaterMark.sendWaterMark = waterMark; - std::lock_guard autoLock(deleteSyncLock_); return UpdateDeleteSyncCacheAndSave(hashId, deleteWaterMark); } -int QuerySyncWaterMarkHelper::SetRecvDeleteSyncWaterMark(const DeviceID &deviceId, const WaterMark &waterMark) +int QuerySyncWaterMarkHelper::SetRecvDeleteSyncWaterMark(const DeviceID &deviceId, const WaterMark &waterMark, + bool isNeedHash) { - std::string hashId = GetHashDeleteSyncDeviceId(deviceId); + std::string hashId = GetHashDeleteSyncDeviceId(deviceId, isNeedHash); DeleteWaterMark deleteWaterMark; + // lock prevent different thread visit deleteSyncCache_ + std::lock_guard autoLock(deleteSyncLock_); GetDeleteWaterMarkFromCache(hashId, deleteWaterMark); deleteWaterMark.recvWaterMark = waterMark; - std::lock_guard autoLock(deleteSyncLock_); return UpdateDeleteSyncCacheAndSave(hashId, deleteWaterMark); } @@ -340,8 +345,6 @@ int QuerySyncWaterMarkHelper::UpdateDeleteSyncCacheAndSave(const std::string &db int QuerySyncWaterMarkHelper::GetDeleteWaterMarkFromCache(const DeviceID &hashDeviceId, DeleteWaterMark &deleteWaterMark) { - // lock prevent different thread visit deleteSyncCache_ - std::lock_guard autoLock(deleteSyncLock_); // if not found if (deleteSyncCache_.find(hashDeviceId) == deleteSyncCache_.end()) { DeleteWaterMark waterMark; @@ -396,12 +399,13 @@ int QuerySyncWaterMarkHelper::SaveDeleteWaterMarkToDB(const DeviceID &hashDevice return errCode; } -DeviceID QuerySyncWaterMarkHelper::GetHashDeleteSyncDeviceId(const DeviceID &deviceId) +DeviceID QuerySyncWaterMarkHelper::GetHashDeleteSyncDeviceId(const DeviceID &deviceId, bool isNeedHash) { DeviceID hashDeleteSyncId; std::lock_guard autoLock(deleteSyncLock_); if (deviceIdToHashDeleteSyncIdMap_.count(deviceId) == 0) { - hashDeleteSyncId = DBConstant::DELETE_SYNC_PREFIX_KEY + DBCommon::TransferHashString(deviceId); + hashDeleteSyncId = DBConstant::DELETE_SYNC_PREFIX_KEY + + (isNeedHash ? DBCommon::TransferHashString(deviceId) : deviceId); deviceIdToHashDeleteSyncIdMap_.insert(std::pair(deviceId, hashDeleteSyncId)); } else { hashDeleteSyncId = deviceIdToHashDeleteSyncIdMap_[deviceId]; @@ -506,11 +510,13 @@ int QuerySyncWaterMarkHelper::RemoveLeastUsedQuerySyncItems(const std::vector autoLock(queryWaterMarkLock_); - std::string prefixKeyStr = DBConstant::QUERY_SYNC_PREFIX_KEY + DBCommon::TransferHashString(deviceId); + std::string prefixKeyStr = DBConstant::QUERY_SYNC_PREFIX_KEY + + (isNeedHash ? DBCommon::TransferHashString(deviceId) : deviceId); if (!tableName.empty()) { std::string hashTableName = DBCommon::TransferHashString(tableName); std::string hexTableName = DBCommon::TransferStringToHex(hashTableName); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.h b/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.h index ab36f91eee88503a00ad43d30bc4c6488ce85e69..bb76a50319155f89453f18e96c30558b401791e5 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/query_sync_water_mark_helper.h @@ -66,7 +66,7 @@ public: int SetSendDeleteSyncWaterMark(const std::string &deviceId, const WaterMark &waterMark); - int SetRecvDeleteSyncWaterMark(const std::string &deviceId, const WaterMark &waterMark); + int SetRecvDeleteSyncWaterMark(const std::string &deviceId, const WaterMark &waterMark, bool isNeedHash); // this function will read deleteWaterMark from db by it's deleteWaterMarkKey // and then serialize it and put to cache @@ -76,7 +76,7 @@ public: int RemoveLeastUsedQuerySyncItems(const std::vector &querySyncIds); // reset the waterMark to zero - int ResetRecvQueryWaterMark(const DeviceID &deviceId, const std::string &tableName); + int ResetRecvQueryWaterMark(const DeviceID &deviceId, const std::string &tableName, bool isNeedHash); static std::string GetQuerySyncPrefixKey(); @@ -118,7 +118,7 @@ private: // get the deleteSync hashId in cache_ or generate one and then put it in to cache_ // the hashId is made up of "DELETE_SYNC_PREFIX_KEY" + hash(deviceId) - DeviceID GetHashDeleteSyncDeviceId(const DeviceID &deviceId); + DeviceID GetHashDeleteSyncDeviceId(const DeviceID &deviceId, bool isNeedHash = true); int SaveDeleteWaterMarkToDB(const DeviceID &hashDeviceId, const DeleteWaterMark &deleteWaterMark); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp index aedf9d19f3160cfb459173b77c213634c31dc3e0..5a72a11d934fcee46432d4848c37a780eb3aee19 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.cpp @@ -204,12 +204,12 @@ void RemoteExecutor::ParseOneRequestMessage(const std::string &device, Message * } int errCode = CheckPermissions(device); if (errCode != E_OK) { - ResponseFailed(errCode, inMsg->GetSessionId(), inMsg->GetSequenceId(), device); + (void)ResponseFailed(errCode, inMsg->GetSessionId(), inMsg->GetSequenceId(), device); return; } errCode = SendRemoteExecutorData(device, inMsg); if (errCode != E_OK) { - ResponseFailed(errCode, inMsg->GetSessionId(), inMsg->GetSequenceId(), device); + (void)ResponseFailed(errCode, inMsg->GetSessionId(), inMsg->GetSequenceId(), device); } } @@ -507,17 +507,17 @@ int RemoteExecutor::RequestStart(uint32_t sessionId) return errCode; } -void RemoteExecutor::ResponseFailed(int errCode, uint32_t sessionId, uint32_t sequenceId, +int RemoteExecutor::ResponseFailed(int errCode, uint32_t sessionId, uint32_t sequenceId, const std::string &device) { RemoteExecutorAckPacket *packet = new (std::nothrow) RemoteExecutorAckPacket(); if (packet == nullptr) { LOGE("[RemoteExecutor][ResponseFailed] new RemoteExecutorAckPacket error"); - return; + return -E_OUT_OF_MEMORY; } packet->SetAckCode(errCode); packet->SetLastAck(); - (void)ResponseStart(packet, sessionId, sequenceId, device); + return ResponseStart(packet, sessionId, sequenceId, device); } int RemoteExecutor::ResponseData(RelationalRowDataSet &&dataSet, const SendMessage &sendMessage, diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.h b/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.h index 68a878d5c7b2331fe1c9d3925d777377e75b4654..f7c1fdd8ee64a6158781b899bc4ad4bb1f891113 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/remote_executor.h @@ -77,7 +77,7 @@ protected: virtual bool IsPacketValid(uint32_t sessionId); - void ResponseFailed(int errCode, uint32_t sessionId, uint32_t sequenceId, const std::string &device); + int ResponseFailed(int errCode, uint32_t sessionId, uint32_t sequenceId, const std::string &device); private: struct SendMessage { diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp index c4c3272a93f8189387e26f396074b57dbc0a9649..736f78213fcc1ad6b5311e3265913c7b86341d38 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_data_sync.cpp @@ -395,6 +395,19 @@ int SingleVerDataSync::SaveData(const SingleVerSyncTaskContext *context, const s if (inData.empty()) { return E_OK; } + StoreInfo info = { + storage_->GetDbProperties().GetStringProp(DBProperties::USER_ID, ""), + storage_->GetDbProperties().GetStringProp(DBProperties::APP_ID, ""), + storage_->GetDbProperties().GetStringProp(DBProperties::STORE_ID, "") + }; + std::string clientId; + int errCode = E_OK; + if (RuntimeContext::GetInstance()->TranslateDeviceId(context->GetDeviceId(), info, clientId) == E_OK) { + errCode = metadata_->SaveClientId(context->GetDeviceId(), clientId); + if (errCode != E_OK) { + LOGW("[DataSync] record clientId failed %d", errCode); + } + } PerformanceAnalysis *performance = PerformanceAnalysis::GetInstance(); if (performance != nullptr) { performance->StepTimeRecordStart(PT_TEST_RECORDS::RECORD_SAVE_DATA); @@ -402,7 +415,6 @@ int SingleVerDataSync::SaveData(const SingleVerSyncTaskContext *context, const s const std::string localHashName = DBCommon::TransferHashString(GetLocalDeviceName()); SingleVerDataSyncUtils::TransSendDataItemToLocal(context, localHashName, inData); - int errCode = E_OK; // query only support prefix key and don't have query in packet in 104 version errCode = storage_->PutSyncDataWithQuery(query, inData, context->GetDeviceId()); if (performance != nullptr) { @@ -1691,6 +1703,10 @@ void SingleVerDataSync::FillRequestReSendPacket(const SingleVerSyncTaskContext * std::vector reserved {reSendInfo.packetId}; packet->SetReserved(reserved); } + if (reSendMode == SyncModeType::PULL) { + // resend pull packet dont set compress type + return; + } bool needCompressOnSync = false; uint8_t compressionRate = DBConstant::DEFAULT_COMPTRESS_RATE; (void)storage_->GetCompressionOption(needCompressOnSync, compressionRate); diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.cpp index 4f099ff91d5927f588baca1a17632e19380d2361..e7541fb568fe5deb19a4f0ddf3821b1670c94e70 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.cpp @@ -159,29 +159,30 @@ void SingleVerKVSyncer::RemoteDataChanged(const std::string &device) static_cast(syncEngine_)->PutUnfinishedSubQueries(device, syncQueries); } -int SingleVerKVSyncer::SyncConditionCheck(QuerySyncObject &query, int mode, bool isQuerySync, - const std::vector &devices) const +int SingleVerKVSyncer::SyncConditionCheck(const SyncParma ¶m, const ISyncEngine *engine, + ISyncInterface *storage) const { - if (!isQuerySync) { + if (!param.isQuerySync) { return E_OK; } - int errCode = static_cast(syncInterface_)->CheckAndInitQueryCondition(query); + QuerySyncObject query = param.syncQuery; + int errCode = static_cast(storage)->CheckAndInitQueryCondition(query); if (errCode != E_OK) { LOGE("[SingleVerKVSyncer] QuerySyncObject check failed"); return errCode; } - if (mode != SUBSCRIBE_QUERY) { + if (param.mode != SUBSCRIBE_QUERY) { return E_OK; } if (query.HasLimit() || query.HasOrderBy()) { LOGE("[SingleVerKVSyncer] subscribe query not support limit,offset or orderby"); return -E_NOT_SUPPORT; } - if (devices.size() > MAX_DEVICES_NUM) { + if (param.devices.size() > MAX_DEVICES_NUM) { LOGE("[SingleVerKVSyncer] devices is overlimit"); return -E_MAX_LIMITS; } - return syncEngine_->SubscribeLimitCheck(devices, query); + return engine->SubscribeLimitCheck(param.devices, query); } void SingleVerKVSyncer::TriggerSubscribe(const std::string &device, const QuerySyncObject &query) @@ -238,6 +239,17 @@ void SingleVerKVSyncer::TriggerSubQuerySync(const std::vector &devi LOGE("[Syncer] Syncer has not Init"); return; } + std::shared_ptr metadata = nullptr; + ISyncInterface *syncInterface = nullptr; + { + std::lock_guard lock(syncerLock_); + if (metadata_ == nullptr || syncInterface_ == nullptr) { + return; + } + metadata = metadata_; + syncInterface = syncInterface_; + syncInterface->IncRefCount(); + } int errCode; for (auto &device : devices) { std::vector queries; @@ -245,15 +257,8 @@ void SingleVerKVSyncer::TriggerSubQuerySync(const std::vector &devi for (auto &query : queries) { std::string queryId = query.GetIdentify(); WaterMark queryWaterMark = 0; - uint64_t lastTimestamp = 0; - { - std::lock_guard lock(syncerLock_); - if (metadata_ == nullptr) { - return; - } - lastTimestamp = metadata_->GetQueryLastTimestamp(device, queryId); - errCode = metadata_->GetSendQueryWaterMark(queryId, device, queryWaterMark, false); - } + uint64_t lastTimestamp = metadata->GetQueryLastTimestamp(device, queryId); + errCode = metadata->GetSendQueryWaterMark(queryId, device, queryWaterMark, false); if (errCode != E_OK) { LOGE("[Syncer] get queryId=%s,dev=%s watermark failed", STR_MASK(queryId), STR_MASK(device)); continue; @@ -273,6 +278,7 @@ void SingleVerKVSyncer::TriggerSubQuerySync(const std::vector &devi QueryAutoSync(param); } } + syncInterface->DecRefCount(); } SyncerBasicInfo SingleVerKVSyncer::DumpSyncerBasicInfo() diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.h b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.h index 60bf8f58941d1f2ac8d46ad5ca1e3eeca326dfad..6ca4a03fc35aad93d4bd27843fe169ce60d1fbe8 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_kv_syncer.h @@ -38,8 +38,7 @@ public: SyncerBasicInfo DumpSyncerBasicInfo() override; protected: - int SyncConditionCheck(QuerySyncObject &query, int mode, bool isQuerySync, - const std::vector &devices) const override; + int SyncConditionCheck(const SyncParma ¶m, const ISyncEngine *engine, ISyncInterface *storage) const override; private: // if trigger full sync, no need to trigger query sync again diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.cpp index 1daf4e20bce64c813ff4a3712476056f72c47be9..1b00d4e8f4564e26d9f89033d211e30c86f4fb3c 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.cpp @@ -167,18 +167,19 @@ void SingleVerRelationalSyncer::SchemaChangeCallback() syncEngine_->SchemaChange(); } -int SingleVerRelationalSyncer::SyncConditionCheck(QuerySyncObject &query, int mode, bool isQuerySync, - const std::vector &devices) const +int SingleVerRelationalSyncer::SyncConditionCheck(const SyncParma ¶m, const ISyncEngine *engine, + ISyncInterface *storage) const { - if (!isQuerySync) { + if (!param.isQuerySync) { return E_OK; } - int errCode = static_cast(syncInterface_)->CheckAndInitQueryCondition(query); + QuerySyncObject query = param.syncQuery; + int errCode = static_cast(storage)->CheckAndInitQueryCondition(query); if (errCode != E_OK) { LOGE("[SingleVerRelationalSyncer] QuerySyncObject check failed"); return errCode; } - if (mode == SUBSCRIBE_QUERY) { + if (param.mode == SUBSCRIBE_QUERY) { return -E_NOT_SUPPORT; } return E_OK; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.h b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.h index 8a733a064bbf9bc3b4fc0a0cf2101af9ab55218f..04102c8d95fe97e0f03e3b03dc751cd3a98cd20c 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_relational_syncer.h @@ -35,8 +35,7 @@ protected: int PrepareSync(const SyncParma ¶m, uint32_t syncId, uint64_t connectionId) override; - int SyncConditionCheck(QuerySyncObject &query, int mode, bool isQuerySync, - const std::vector &devices) const override; + int SyncConditionCheck(const SyncParma ¶m, const ISyncEngine *engine, ISyncInterface *storage) const override; private: diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_serialize_manager.h b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_serialize_manager.h index cb4035b1260d616eb3e8d53262eb31dfec749a22..33f19fc7b0a20aba16e3d2f6fb6f308395dd42f9 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_serialize_manager.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_serialize_manager.h @@ -16,6 +16,7 @@ #ifndef SINGLE_VER_SERIALIZE_MANAGER_NEW_H #define SINGLE_VER_SERIALIZE_MANAGER_NEW_H +#include #include "icommunicator.h" #include "isync_packet.h" #include "message_transform.h" diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.cpp index 278ff798adb1945653a24bbaa9e4317c08b48ebc..aa753b1d753a64a767a0f473df26abc2a7da0aac 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.cpp @@ -490,6 +490,7 @@ void SingleVerSyncTaskContext::SaveLastPushTaskExecStatus(int finalStatus) if (mode_ == SyncModeType::PUSH || mode_ == SyncModeType::PUSH_AND_PULL || mode_ == SyncModeType::RESPONSE_PULL) { lastFullSyncTaskStatus_ = finalStatus; } else if (mode_ == SyncModeType::QUERY_PUSH || mode_ == SyncModeType::QUERY_PUSH_PULL) { + std::lock_guard autoLock(queryTaskStatusMutex_); lastQuerySyncTaskStatusMap_[syncOperation_->GetQueryId()] = finalStatus; } } @@ -515,6 +516,7 @@ int SingleVerSyncTaskContext::GetCorrectedSendWaterMarkForCurrentTask(const Sync void SingleVerSyncTaskContext::ResetLastPushTaskStatus() { lastFullSyncTaskStatus_ = SyncOperation::OP_WAITING; + std::lock_guard autoLock(queryTaskStatusMutex_); lastQuerySyncTaskStatusMap_.clear(); } @@ -536,6 +538,7 @@ bool SingleVerSyncTaskContext::IsCurrentSyncTaskCanBeSkippedInner(const SyncOper if (operation == nullptr) { return true; } + std::lock_guard autoLock(queryTaskStatusMutex_); auto it = lastQuerySyncTaskStatusMap_.find(operation->GetQueryId()); if (it == lastQuerySyncTaskStatusMap_.end()) { // no last query_push and push diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.h b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.h index 4aff0679c6657f3a46355d1d41abcf85d5eb1fc6..19145a8baf08a58aacadcc26209977bf714845d3 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_sync_task_context.h @@ -145,7 +145,7 @@ protected: bool isQuerySync_ = false; // for merge sync task - int lastFullSyncTaskStatus_ = SyncOperation::Status::OP_WAITING; + volatile int lastFullSyncTaskStatus_ = SyncOperation::Status::OP_WAITING; private: int GetCorrectedSendWaterMarkForCurrentTask(const SyncOperation *operation, uint64_t &waterMark) const; @@ -172,6 +172,7 @@ private: // For subscribe manager std::shared_ptr subManager_; + mutable std::mutex queryTaskStatusMutex_; // std::unordered_map lastQuerySyncTaskStatusMap_; }; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.cpp index fd754fb4a96fbd4a5b91eff47500d90f205c532c..0e4223496e1fa261dcba665baf3db25b220b2887 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.cpp @@ -92,4 +92,17 @@ ISyncEngine *SingleVerSyncer::CreateSyncEngine() { return new (std::nothrow) SingleVerSyncEngine(); } + +int SingleVerSyncer::GetHashDeviceId(const std::string &clientId, std::string &hashDevId) +{ + std::shared_ptr metadata = nullptr; + { + std::lock_guard lock(syncerLock_); + if (metadata_ == nullptr) { + return -E_NOT_INIT; + } + metadata = metadata_; + } + return metadata->GetHashDeviceId(clientId, hashDevId); +} } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.h b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.h index 9dc5e0e1781185a7d96d9bedab6d5c8c7012d3b9..e352b2adfcc16cad74c1641d376912b9b0a236ad 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/single_ver_syncer.h @@ -34,6 +34,7 @@ public: int EraseDeviceWaterMark(const std::string &deviceId, bool isNeedHash, const std::string &tableName) override; + int GetHashDeviceId(const std::string &clientId, std::string &hashDevId) override; protected: // Create a sync engine, if has memory error, will return nullptr. ISyncEngine *CreateSyncEngine() override; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp index 61733a69c15e2de2de17ac3306ec14baa60cbdb4..938fcacf9ed05efd4d45ea96a20966c42f1b0f4a 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_engine.cpp @@ -661,36 +661,39 @@ int SyncEngine::ExecSyncTask(ISyncTaskContext *context) if (IsKilled()) { return -E_OBJ_IS_KILLED; } - AutoLock lockGuard(context); int status = context->GetTaskExecStatus(); if ((status == SyncTaskContext::RUNNING) || context->IsKilled()) { return -E_NOT_SUPPORT; } context->SetTaskExecStatus(ISyncTaskContext::RUNNING); - if (!context->IsTargetQueueEmpty()) { - int errCode = context->GetNextTarget(true); + while (!context->IsTargetQueueEmpty()) { + int errCode = context->GetNextTarget(); if (errCode != E_OK) { - return errCode; + // current task execute failed, try next task + context->ClearSyncOperation(); + continue; } if (context->IsCurrentSyncTaskCanBeSkipped()) { context->SetOperationStatus(SyncOperation::OP_FINISHED_ALL); context->ClearSyncOperation(); - context->SetTaskExecStatus(ISyncTaskContext::FINISHED); - return E_OK; + continue; } context->UnlockObj(); errCode = context->StartStateMachine(); context->LockObj(); if (errCode != E_OK) { - LOGE("[SyncEngine] machine StartSync failed"); + // machine start failed because timer start failed, try to execute next task + LOGW("[SyncEngine] machine StartSync failed"); context->SetOperationStatus(SyncOperation::OP_FAILED); - return errCode; + context->ClearSyncOperation(); + continue; } - } else { - LOGD("[SyncEngine] ExecSyncTask finished"); - context->SetTaskExecStatus(ISyncTaskContext::FINISHED); + // now task is running just return here + return errCode; } + LOGD("[SyncEngine] ExecSyncTask finished"); + context->SetTaskExecStatus(ISyncTaskContext::FINISHED); return E_OK; } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_state_machine.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_state_machine.cpp index 9115edd0e41144d4900a67f66f0486ebe10a19f2..374ce91535375d01188aaa578da5a90eca972d32 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_state_machine.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_state_machine.cpp @@ -174,18 +174,21 @@ int SyncStateMachine::ExecNextTask() { syncContext_->Clear(); while (!syncContext_->IsTargetQueueEmpty()) { - int errCode = syncContext_->GetNextTarget(false); + int errCode = syncContext_->GetNextTarget(); if (errCode != E_OK) { continue; } if (syncContext_->IsCurrentSyncTaskCanBeSkipped()) { syncContext_->SetOperationStatus(SyncOperation::OP_FINISHED_ALL); + syncContext_->Clear(); continue; } errCode = PrepareNextSyncTask(); if (errCode != E_OK) { LOGE("[SyncStateMachine] PrepareSync failed"); syncContext_->SetOperationStatus(SyncOperation::OP_FAILED); + syncContext_->Clear(); + continue; // try to execute next task } return errCode; } diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp index 97499394e7f1e68ab4ae5af16e657259f3d881d2..a615c38dacf383f6bc33e968658d48b1b36093c5 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.cpp @@ -89,13 +89,20 @@ int SyncTaskContext::AddSyncTarget(ISyncTarget *target) return -E_INVALID_ARGS; } } - CancelCurrentSyncRetryIfNeed(targetMode); + RefObject::IncObjRef(this); + int errCode = RuntimeContext::GetInstance()->ScheduleTask([this, targetMode]() { + CancelCurrentSyncRetryIfNeed(targetMode); + RefObject::DecObjRef(this); + }); + if (errCode != E_OK) { + RefObject::DecObjRef(this); + } if (taskExecStatus_ == RUNNING) { return E_OK; } if (onSyncTaskAdd_) { RefObject::IncObjRef(this); - int errCode = RuntimeContext::GetInstance()->ScheduleTask([this]() { + errCode = RuntimeContext::GetInstance()->ScheduleTask([this]() { onSyncTaskAdd_(); RefObject::DecObjRef(this); }); @@ -260,15 +267,12 @@ void SyncTaskContext::MoveToNextTarget() } } -int SyncTaskContext::GetNextTarget(bool isNeedSetFinished) +int SyncTaskContext::GetNextTarget() { MoveToNextTarget(); int checkErrCode = RunPermissionCheck(GetPermissionCheckFlag(IsAutoSync(), GetMode())); if (checkErrCode != E_OK) { SetOperationStatus(SyncOperation::OP_PERMISSION_CHECK_FAILED); - if (isNeedSetFinished) { - SetTaskExecStatus(ISyncTaskContext::FINISHED); - } return checkErrCode; } return E_OK; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.h b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.h index 1eb06538c2aaf55550a184329505fd3d12ca47e6..8ecf283755a7a1682c8b131b25f7c787e3c75096 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.h +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/sync_task_context.h @@ -70,7 +70,7 @@ public: // Move to next target to sync void MoveToNextTarget() override; - int GetNextTarget(bool isNeedSetFinished) override; + int GetNextTarget() override; // Get the current task syncId uint32_t GetSyncId() const override; diff --git a/kv_store/frameworks/libs/distributeddb/syncer/src/syncer_proxy.cpp b/kv_store/frameworks/libs/distributeddb/syncer/src/syncer_proxy.cpp index 324b4ea05cd667597ffed9046e84b04b3813175a..6d55a01bbb2eee1edb854c843de3f772087adf69 100644 --- a/kv_store/frameworks/libs/distributeddb/syncer/src/syncer_proxy.cpp +++ b/kv_store/frameworks/libs/distributeddb/syncer/src/syncer_proxy.cpp @@ -231,4 +231,12 @@ int SyncerProxy::GetSyncDataSize(const std::string &device, size_t &size) const } return syncer_->GetSyncDataSize(device, size); } + +int SyncerProxy::GetHashDeviceId(const std::string &clientId, std::string &hashDevId) +{ + if (syncer_ == nullptr) { + return -E_NOT_INIT; + } + return syncer_->GetHashDeviceId(clientId, hashDevId); +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/test/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/BUILD.gn index e812b2ab872641a43170de886020b26f06a20a64..8b8a3713153add8dcbecbfdc963f4832741c15bd 100644 --- a/kv_store/frameworks/libs/distributeddb/test/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/BUILD.gn @@ -63,6 +63,7 @@ config("module_private_config") { "USE_DFX_ABILITY", "TRACE_SQLITE_EXECUTE", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] } @@ -201,6 +202,7 @@ ohos_source_set("src_file") { "../storage/src/sqlite/sqlite_local_storage_engine.cpp", "../storage/src/sqlite/sqlite_local_storage_executor.cpp", "../storage/src/sqlite/sqlite_log_table_manager.cpp", + "../storage/src/sqlite/sqlite_meta_executor.cpp", "../storage/src/sqlite/sqlite_multi_ver_data_storage.cpp", "../storage/src/sqlite/sqlite_multi_ver_transaction.cpp", "../storage/src/sqlite/sqlite_query_helper.cpp", diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn index 14a11bbf01ae2af524fb20f1f3ab8b033f934698..efed0f982f7c1d66f4d725c60048b030e88623fb 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/BUILD.gn @@ -84,6 +84,7 @@ ohos_fuzztest("DelegateFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/delegate_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/delegate_fuzzer.cpp index fb3a4cb7f40e7c7d34cde2fdaf3791370ff1e569..c2e20ea205748212bfeae57ee4308946fd72cfab 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/delegate_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/delegate_fuzzer/delegate_fuzzer.cpp @@ -36,21 +36,29 @@ std::vector CreateEntries(const uint8_t* data, size_t size, std::vectorUnRegisterObserver(observer); + delete observer; return; } auto valueCallback = [&value] (DBStatus status, const Value &getValue) { @@ -82,9 +92,10 @@ void MultiCombineFuzzer(const uint8_t* data, size_t size, KvStoreDelegate::Optio kvDelegatePtr->DeleteBatch(keys); kvDelegatePtr->Clear(); kvDelegatePtr->UnRegisterObserver(observer); + delete observer; kvDelegatePtr->ReleaseKvStoreSnapshot(kvStoreSnapshotPtr); - kvManger.CloseKvStore(kvDelegatePtr); - kvManger.DeleteKvStore("distributed_delegate_test"); + g_kvManger.CloseKvStore(kvDelegatePtr); + g_kvManger.DeleteKvStore("distributed_delegate_test"); DistributedDBToolsTest::RemoveTestDbFiles(config.dataDir); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn index a73111fc9f53ee9847e5b1d3724db3259a9af9d9..825390ba1ec24d59e72440373cfc655cfdfb9060 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/fileoper_fuzzer/BUILD.gn @@ -93,6 +93,7 @@ ohos_fuzztest("FileOperFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] external_deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn index 15f738c1a9060553f58c169fc6a18ae5ae05b8b0..2d60cdfaa1cff0a967a37181f34c82f652a70169 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/importfile_fuzzer/BUILD.gn @@ -85,6 +85,7 @@ ohos_fuzztest("ImportFileFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn index a6a320ab6dc9f1924d30d20d4f6fde33560647a7..3fde06430d833d844099c9f19f75358ed7daccc7 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/iprocesscommunicator_fuzzer/BUILD.gn @@ -84,6 +84,7 @@ ohos_fuzztest("IProcessCommunicatorFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn index 2ff25d9b009fa52c7aac5ce45a627a61da6432b1..739b6f5114b12c018397c00ea205e74add054796 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvdelegatemanager_fuzzer/BUILD.gn @@ -85,6 +85,7 @@ ohos_fuzztest("KvDelegateManagerFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn index 52d66d871b0401f27529a5059b8f493e0cbbf77e..64023811db625dca5430c5833f4bc740786b601a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/kvstoreresultset_fuzzer/BUILD.gn @@ -85,6 +85,7 @@ ohos_fuzztest("KvStoreResultSetFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn index aa1dca951b3fb21db5d7cd2987a2c4385ddb5875..0741d160b7e928ce380a092626f546f6b5af7803 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/BUILD.gn @@ -84,6 +84,7 @@ ohos_fuzztest("NbDelegateFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/nbdelegate_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/nbdelegate_fuzzer.cpp index 983271bda04cc5d44e19f63658b5d91671d4d0cd..0766f5e96ca098a284e0e91e18034cfecb7cbff5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/nbdelegate_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/nbdelegate_fuzzer/nbdelegate_fuzzer.cpp @@ -144,6 +144,24 @@ void FuzzSetInterceptorTest(KvStoreNbDelegate *kvNbDelegatePtr) ); } +void TestCRUD(const Key &key, const Value &value, KvStoreNbDelegate *kvNbDelegatePtr) +{ + Value valueRead; + kvNbDelegatePtr->PutLocal(key, value); + kvNbDelegatePtr->GetLocal(key, valueRead); + kvNbDelegatePtr->DeleteLocal(key); + kvNbDelegatePtr->Put(key, value); + kvNbDelegatePtr->Put(key, value); + kvNbDelegatePtr->UpdateKey([](const Key &origin, Key &newKey) { + newKey = origin; + newKey.push_back('0'); + }); + std::vector vect; + kvNbDelegatePtr->GetEntries(key, vect); + kvNbDelegatePtr->Delete(key); + kvNbDelegatePtr->Get(key, valueRead); +} + void FuzzCURD(const uint8_t* data, size_t size, KvStoreNbDelegate *kvNbDelegatePtr) { auto observer = new (std::nothrow) KvStoreObserverFuzzTest; @@ -156,17 +174,7 @@ void FuzzCURD(const uint8_t* data, size_t size, KvStoreNbDelegate *kvNbDelegateP kvNbDelegatePtr->SetConflictNotifier(size, [](const KvStoreNbConflictData &data) { (void)data.GetType(); }); - - Value valueRead; - kvNbDelegatePtr->PutLocal(key, value); - kvNbDelegatePtr->GetLocal(key, valueRead); - kvNbDelegatePtr->DeleteLocal(key); - kvNbDelegatePtr->Put(key, value); - kvNbDelegatePtr->Put(key, value); - std::vector vect; - kvNbDelegatePtr->GetEntries(key, vect); - kvNbDelegatePtr->Delete(key); - kvNbDelegatePtr->Get(key, valueRead); + TestCRUD(key, value, kvNbDelegatePtr); std::vector keys; std::vector tmp = CreateEntries(data, size, keys); kvNbDelegatePtr->PutBatch(tmp); @@ -178,6 +186,8 @@ void FuzzCURD(const uint8_t* data, size_t size, KvStoreNbDelegate *kvNbDelegateP } kvNbDelegatePtr->DeleteBatch(keys); kvNbDelegatePtr->UnRegisterObserver(observer); + delete observer; + observer = nullptr; kvNbDelegatePtr->PutLocalBatch(tmp); kvNbDelegatePtr->DeleteLocalBatch(keys); std::string tmpStoreId = kvNbDelegatePtr->GetStoreId(); diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn index b2eb988b57c598d23c512a5c065e0b45ab0ce1d2..403c683d83dd32092a338857238e3862122f73fe 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/parseckeck_fuzzer/BUILD.gn @@ -85,6 +85,7 @@ ohos_fuzztest("ParseCkeckFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn index f8063cfec5646143ccd5ba24c29fdefda1241ec5..27e317f3de2a762090b2c6456091a87744eb073f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/query_fuzzer/BUILD.gn @@ -83,6 +83,7 @@ ohos_fuzztest("QueryFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn index 2c77f077ae0e552cf6a9e7d894e4772bf23f87db..d70da426cd64b58ab61e97c16812771d4cf6643b 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/rekey_fuzzer/BUILD.gn @@ -85,6 +85,7 @@ ohos_fuzztest("ReKeyFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn index 72df4d366c7ec319b76052f305c9d13efaff4b3d..c3f7947ee763ca837a89bb553237162f8b9f8763 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/BUILD.gn @@ -90,6 +90,7 @@ ohos_fuzztest("RelationalstoredelegateFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_EXPORT_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp index 9a3e1ecb8bd535fd8e617c94f59ceb42ca8e2c00..2cf32a8a5651b7d4cbfeef346ea21111fe5c3629 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoredelegate_fuzzer/relationalstoredelegate_fuzzer.cpp @@ -23,7 +23,7 @@ #include "virtual_communicator_aggregator.h" #include "query.h" #include "store_types.h" -#include "result_set.h" +#include "distributeddb/result_set.h" #include "runtime_context.h" namespace OHOS { @@ -118,6 +118,7 @@ void CombineTest(const uint8_t* data, size_t size) } g_delegate->Sync(device, mode, query, nullptr, len % 2); // 2 is mod num for wait parameter std::string deviceId = device.size() > 0 ? device[0] : tableName; + g_delegate->RemoveDeviceData(); g_delegate->RemoveDeviceData(deviceId); g_delegate->RemoveDeviceData(deviceId, tableName); diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn index dbd859f2b9a80dc4163cef4a90cabbeaa9e486da..652223af3da206f73ed3dd8f8263b7ed6259d205 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/BUILD.gn @@ -89,6 +89,7 @@ ohos_fuzztest("RelationalstoremanagerFuzzTest") { "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_EXPORT_SYMBOLS", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp index 5621535136dad18d134563499b1f569993d68d1e..c5fd1f9c82e0a40cb4e1a9d421b46d32816781c5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/relationalstoremanager_fuzzer/relationalstoremanager_fuzzer.cpp @@ -79,6 +79,9 @@ void CombineTest(const uint8_t* data, size_t size) g_mgr.OpenStore(g_dbDir + appId + DB_SUFFIX, storeId, {}, g_delegate); g_mgr.GetRelationalStoreIdentifier(userId, appId, storeId, instanceId % 2); // 2 is mod num for last parameter RuntimeConfig::SetProcessLabel(appId, userId); + RuntimeConfig::SetTranslateToDeviceIdCallback([](const std::string &oriDevId, const StoreInfo &info) { + return oriDevId + "_" + info.appId; + }); } } diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn index 8243f00a8e21bc52ba08077831bd175c4e6f3053..2b82a09c531096996e945ba68b87900201b3aad9 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/schemadelegate_fuzzer/BUILD.gn @@ -84,6 +84,7 @@ ohos_fuzztest("SchemaDelegateFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn index 89b451be10fcf0a5463351ca6cd9c78947f6c14a..197221a87c2ed1142d734d60746cc3a5b1966086 100644 --- a/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/fuzztest/sync_fuzzer/BUILD.gn @@ -90,6 +90,7 @@ ohos_fuzztest("SyncFuzzTest") { "RELATIONAL_STORE", "SQLITE_DISTRIBUTE_RELATIONAL", "SQLITE_ENABLE_DROPTABLE_CALLBACK", + "OPENSSL_SUPPRESS_DEPRECATED", ] deps = [ diff --git a/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn b/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn index eeb51b201b37a3e04334d951c402879e01e99177..d16cccf7fa95561b35a155d632df9c43ab645b2a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn +++ b/kv_store/frameworks/libs/distributeddb/test/moduletest/BUILD.gn @@ -59,6 +59,7 @@ config("module_private_config") { "RELEASE_MODE_V2", "RELEASE_MODE_V3", "OMIT_MULTI_VER", + "OPENSSL_SUPPRESS_DEPRECATED", ] ldflags = [ "-Wl,--exclude-libs,ALL" ] } diff --git a/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_kv_crud_test.cpp b/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_kv_crud_test.cpp index b9ee63b181c366c4dce38013bf65a8784769cacb..9623e8235b2151e1690111bddd49cfc029c0f6b2 100644 --- a/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_kv_crud_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_kv_crud_test.cpp @@ -651,21 +651,6 @@ HWTEST_F(DistributeddbKvCrudTest, ComplexDataTest006, TestSize.Level1) EXPECT_TRUE(valueResult.size() == 0); } -/* - * @tc.name: ComplexDataTest 007 - * @tc.desc: Verify that can operate chinese string key and value. - * @tc.type: FUNC - * @tc.require: SR000BUH3J - * @tc.author: luqianfu - */ -HWTEST_F(DistributeddbKvCrudTest, ComplexDataTest007, TestSize.Level1) -{ - /* - * @tc.steps: step1. create kv db and put(k,OK_VALUE_1) that k="中文"and get. - * @tc.expected: step1. put successfully and get the value of k is OK_VALUE_1. - */ -} - /* * @tc.name: ReadWritePerformance 001 * @tc.desc: calculate the time of put-get in 16b-100b/16b-100kb, 1k times' random-put&get. @@ -710,12 +695,12 @@ HWTEST_F(DistributeddbKvCrudTest, ReadWritePerformance001, TestSize.Level3) }; for (int ps = 0; ps < PERFORMANCE_SIZE; ++ps) { - DistributedTestTools::CalculateOpenPerformance(performanceData[ps]); - DistributedTestTools::CalculateInsertPerformance(performanceData[ps]); - DistributedTestTools::CalculateGetPutPerformance(performanceData[ps]); - DistributedTestTools::CalculateUpdatePerformance(performanceData[ps]); - DistributedTestTools::CalculateGetUpdatePerformance(performanceData[ps]); - DistributedTestTools::CalculateUseClearPerformance(performanceData[ps]); + EXPECT_TRUE(DistributedTestTools::CalculateOpenPerformance(performanceData[ps])); + EXPECT_TRUE(DistributedTestTools::CalculateInsertPerformance(performanceData[ps])); + EXPECT_TRUE(DistributedTestTools::CalculateGetPutPerformance(performanceData[ps])); + EXPECT_TRUE(DistributedTestTools::CalculateUpdatePerformance(performanceData[ps])); + EXPECT_TRUE(DistributedTestTools::CalculateGetUpdatePerformance(performanceData[ps])); + EXPECT_TRUE(DistributedTestTools::CalculateUseClearPerformance(performanceData[ps])); } } } diff --git a/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_nb_create_test.cpp b/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_nb_create_test.cpp index ed024c7c4f9f8dc915aa1b143d38a846bd7f1631..649dc9f577e1a05f7509e7cd6010af7e1c2e787c 100644 --- a/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_nb_create_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/moduletest/src/distributeddb_nb_create_test.cpp @@ -71,27 +71,6 @@ void DistributeddbNbCreateTest::TearDown(void) { } -void WaitingDeletingDB() -{ - KvStoreDelegateManager *manager = nullptr; - KvStoreNbDelegate *result = nullptr; - /** - * @tc.steps: step2. delete db when kill the process manually. - * @tc.expected: step2. delete success. - */ - result = DistributedDBNbTestTools::GetNbDelegateSuccess(manager, g_dbParameter2, g_option); - ASSERT_TRUE(manager != nullptr && result != nullptr); - EXPECT_EQ(manager->CloseKvStore(result), OK); - result = nullptr; - if (!g_option.isMemoryDb) { - EXPECT_EQ(manager->DeleteKvStore(STORE_ID_2), OK); - } - MST_LOG("please kill the testing process..."); - std::this_thread::sleep_for(std::chrono::seconds(TWENTY_SECONDS)); - delete manager; - manager = nullptr; -} - /* * @tc.name: ManagerDb 001 * @tc.desc: Verify that can create distributed db normally. @@ -986,24 +965,6 @@ HWTEST_F(DistributeddbNbCreateTest, ManagerDb029, TestSize.Level0) manager = nullptr; } -/* - * @tc.name: ManagerDb 030 - * @tc.desc: verify that can delete the db success even if the deleting process is killed when it is deleting the db. - * @tc.type: FUNC - * @tc.require: SR000CCPOI - * @tc.author: luqianfu - */ -HWTEST_F(DistributeddbNbCreateTest, ManagerDb030, TestSize.Level2) -{ - /** - * @tc.steps: step1. start thread. - * @tc.expected: step1. success. - */ - std::thread th(WaitingDeletingDB); - th.detach(); - std::this_thread::sleep_for(std::chrono::seconds(UNIQUE_SECOND)); -} - /* * @tc.name: MemoryDb 001 * @tc.desc: verify that can create memory db successfully. diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp index e5a96775640805b4dc8b7f8e87bb3d02968f565f..652b94146abd4391ffd92a853ef9bba804bcf77f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/communicator/distributeddb_communicator_deep_test.cpp @@ -146,11 +146,16 @@ HWTEST_F(DistributedDBCommunicatorDeepTest, WaitAndRetrySend001, TestSize.Level2 g_commBB->RegOnMessageCallback([&msgForBB](const std::string &srcTarget, Message *inMsg) { msgForBB = inMsg; }, nullptr); + Message *msgForCA = nullptr; + g_commCA->RegOnMessageCallback([&msgForCA](const std::string &srcTarget, Message *inMsg) { + msgForCA = inMsg; + }, nullptr); /** * @tc.steps: step1. connect device A with device B */ AdapterStub::ConnectAdapterStub(g_envDeviceA.adapterHandle, g_envDeviceB.adapterHandle); + AdapterStub::ConnectAdapterStub(g_envDeviceA.adapterHandle, g_envDeviceC.adapterHandle); std::this_thread::sleep_for(std::chrono::milliseconds(200)); // Wait 200 ms to make sure quiet /** @@ -167,8 +172,16 @@ HWTEST_F(DistributedDBCommunicatorDeepTest, WaitAndRetrySend001, TestSize.Level2 SendConfig conf = {true, false, 0}; int errCode = g_commAB->SendMessage(DEVICE_NAME_B, msgForAB, conf); EXPECT_EQ(errCode, E_OK); + + Message *msgForAA = BuildRegedTinyMessage(); + ASSERT_NE(msgForAA, nullptr); + errCode = g_commAA->SendMessage(DEVICE_NAME_C, msgForAA, conf); + EXPECT_EQ(errCode, E_OK); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Wait 100 ms EXPECT_EQ(msgForBB, nullptr); + EXPECT_NE(msgForCA, nullptr); + delete msgForCA; + msgForCA = nullptr; /** * @tc.steps: step4. device A simulate sendable feedback diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_database_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_database_test.cpp index c8a083ca6ea15e4c193554574569080934a23b69..62b665f3528151e2bcd9b5201999dcabaf5f8cc3 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_database_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_database_test.cpp @@ -1303,6 +1303,35 @@ namespace { } LOGD("Succeed %d times", totalNum); } + + void FreqOpenClose001() + { + std::string storeId = "FrqOpenClose001"; + std::thread t1(OpenCloseDatabase, storeId); + std::thread t2(OpenCloseDatabase, storeId); + std::thread t3(OpenCloseDatabase, storeId); + std::thread t4(OpenCloseDatabase, storeId); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK); + } + + void FreqOpenCloseDel001() + { + std::string storeId = "FrqOpenCloseDelete001"; + std::thread t1(OpenCloseDatabase, storeId); + std::thread t2([&]() { + for (int i = 0; i < 10000; i++) { // loop 10000 times + DBStatus status = g_mgr.DeleteKvStore(storeId); + LOGI("delete res %d", status); + EXPECT_TRUE(status == OK || status == BUSY || status == NOT_FOUND); + } + }); + t1.join(); + t2.join(); + } } /** @@ -1314,15 +1343,7 @@ namespace { */ HWTEST_F(DistributedDBInterfacesDatabaseTest, FreqOpenCloseDel001, TestSize.Level2) { - std::string storeId = "FrqOpenCloseDelete001"; - std::thread t1(OpenCloseDatabase, storeId); - std::thread t2([&]() { - for (int i = 0; i < 10000; i++) { - g_mgr.DeleteKvStore(storeId); - } - }); - t1.join(); - t2.join(); + ASSERT_NO_FATAL_FAILURE(FreqOpenCloseDel001()); } /** @@ -1334,16 +1355,7 @@ HWTEST_F(DistributedDBInterfacesDatabaseTest, FreqOpenCloseDel001, TestSize.Leve */ HWTEST_F(DistributedDBInterfacesDatabaseTest, FreqOpenClose001, TestSize.Level2) { - std::string storeId = "FrqOpenClose001"; - std::thread t1(OpenCloseDatabase, storeId); - std::thread t2(OpenCloseDatabase, storeId); - std::thread t3(OpenCloseDatabase, storeId); - std::thread t4(OpenCloseDatabase, storeId); - t1.join(); - t2.join(); - t3.join(); - t4.join(); - EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK); + ASSERT_NO_FATAL_FAILURE(FreqOpenClose001()); } /** @@ -1407,6 +1419,56 @@ HWTEST_F(DistributedDBInterfacesDatabaseTest, CompressionRate1, TestSize.Level1) EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK); } +/** + * @tc.name: CompressionRate2 + * @tc.desc: Open the kv store with again with different compression option. + * @tc.type: FUNC + * @tc.require: + * @tc.author: lianhuix + */ +HWTEST_F(DistributedDBInterfacesDatabaseTest, CompressionRate2, TestSize.Level1) +{ + /** + * @tc.steps: step1. Open the kv store with the option that comressionRate is invalid. + * @tc.expected: step1. Open kv store successfully. Returns OK. + */ + KvStoreNbDelegate::Option option; + option.isNeedCompressOnSync = true; + option.compressionRate = 70; // 70 compression rate. + const std::string storeId("CompressionRate1"); + g_mgr.GetKvStore(storeId, option, g_kvNbDelegateCallback); + ASSERT_TRUE(g_kvNbDelegatePtr != nullptr); + EXPECT_TRUE(g_kvDelegateStatus == OK); + + /** + * @tc.steps: step2. Open again with different compression option + * @tc.expected: step2. Open kv store failed. Returns INVALID_ARGS. + */ + DBStatus status; + KvStoreNbDelegate *delegate = nullptr; + auto callback = bind(&DistributedDBToolsUnitTest::KvStoreNbDelegateCallback, + placeholders::_1, placeholders::_2, std::ref(status), std::ref(delegate)); + + option.compressionRate = 80; // 80 compression rate. + g_mgr.GetKvStore(storeId, option, callback); + ASSERT_TRUE(delegate == nullptr); + EXPECT_TRUE(status == INVALID_ARGS); + + option.isNeedCompressOnSync = false; + option.compressionRate = 70; // 70 compression rate. + g_mgr.GetKvStore(storeId, option, callback); + ASSERT_TRUE(delegate == nullptr); + EXPECT_TRUE(status == INVALID_ARGS); + + /** + * @tc.steps: step3. Close kv store + * @tc.expected: step3. OK. + */ + g_mgr.CloseKvStore(g_kvNbDelegatePtr); + g_kvNbDelegatePtr = nullptr; + EXPECT_EQ(g_mgr.DeleteKvStore(storeId), OK); +} + HWTEST_F(DistributedDBInterfacesDatabaseTest, DataInterceptor1, TestSize.Level1) { /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp index 7cb509e4f0150809ed108dc3edcf40aee1544215..b670fdbaf4b60089b5d877b5db67525904158967 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_device_identifier_test.cpp @@ -519,6 +519,18 @@ HWTEST_F(DistributedDBDeviceIdentifierTest, StorageEngineTest001, TestSize.Level storageEngine->Release(); } +namespace { +void StorageEngineTest002() +{ + std::string exportFileName = g_testDir + "/" + STORE_ID + ".dump"; + int fd = open(exportFileName.c_str(), (O_WRONLY | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP)); + ASSERT_TRUE(fd >= 0); + g_store->Dump(fd); + close(fd); + OS::RemoveDBDirectory(exportFileName); +} +} + /** * @tc.name: StorageEngineTest002 * @tc.desc: Test the interface of Dump @@ -528,12 +540,7 @@ HWTEST_F(DistributedDBDeviceIdentifierTest, StorageEngineTest001, TestSize.Level */ HWTEST_F(DistributedDBDeviceIdentifierTest, StorageEngineTest002, TestSize.Level1) { - std::string exportFileName = g_testDir + "/" + STORE_ID + ".dump"; - int fd = open(exportFileName.c_str(), (O_WRONLY | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP)); - ASSERT_TRUE(fd >= 0); - g_store->Dump(fd); - close(fd); - OS::RemoveDBDirectory(exportFileName); + ASSERT_NO_FATAL_FAILURE(StorageEngineTest002()); } /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_encrypt_delegate_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_encrypt_delegate_test.cpp index 938c0ff852f21eec23946b681901f7159fe1419b..1d15ede5232339600ddaff7041cb8196866f3263 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_encrypt_delegate_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_encrypt_delegate_test.cpp @@ -542,17 +542,6 @@ HWTEST_F(DistributedDBInterfacesEncryptDelegateTest, EncryptedDbSwitch004, TestS EXPECT_EQ(g_mgr.DeleteKvStore(STORE_ID1), OK); } -/** - * @tc.name: EncryptedDbSwitch008 - * @tc.desc: Test the multi version db Rekey function return BUSY because of Snapshot not close. - * @tc.type: FUNC - * @tc.require: AR000CQDT7 - * @tc.author: wumin - */ -HWTEST_F(DistributedDBInterfacesEncryptDelegateTest, EncryptedDbSwitch008, TestSize.Level1) -{ -} - /** * @tc.name: EncryptedDbSwitch009 * @tc.desc: Test the single version db Rekey function from password1 to password2. diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp index 367c74658bdc7d53ec372d1c57c339518ce1e673..4b33abb796effc469de1786e649aef6a9b74f554 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_nb_delegate_test.cpp @@ -177,7 +177,7 @@ namespace { return false; } - static const std::string selectSQL = "select timestamp from sync_data order by rowid;"; + std::string selectSQL = "select timestamp from sync_data order by rowid;"; sqlite3_stmt *statement = nullptr; EXPECT_EQ(sqlite3_prepare(db, selectSQL.c_str(), -1, &statement, NULL), SQLITE_OK); std::vector timeVect; @@ -2409,6 +2409,58 @@ HWTEST_F(DistributedDBInterfacesNBDelegateTest, LocalStore002, TestSize.Level1) EXPECT_EQ(syncDelegate, nullptr); EXPECT_EQ(openStatus, INVALID_ARGS); EXPECT_EQ(mgr.CloseKvStore(localDelegate), OK); + EXPECT_EQ(mgr.DeleteKvStore(STORE_ID_1), OK); +} + +/** + * @tc.name: PutSync001 + * @tc.desc: put data and sync at same time + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesNBDelegateTest, PutSync001, TestSize.Level3) +{ + /** + * @tc.steps:step1. Create database with localOnly. + * @tc.expected: step1. Returns a non-null store. + */ + KvStoreDelegateManager mgr(APP_ID, USER_ID); + mgr.SetKvStoreConfig(g_config); + const KvStoreNbDelegate::Option option = {true, false, false}; + mgr.GetKvStore(STORE_ID_1, option, g_kvNbDelegateCallback); + ASSERT_TRUE(g_kvNbDelegatePtr != nullptr); + EXPECT_EQ(g_kvDelegateStatus, OK); + /** + * @tc.steps:step2. Put data async. + * @tc.expected: step2. Always returns OK. + */ + std::atomic finish = false; + std::thread putThread([&finish]() { + while (!finish) { + EXPECT_EQ(g_kvNbDelegatePtr->Put(KEY_1, VALUE_1), OK); + } + }); + /** + * @tc.steps:step3. Call sync async. + * @tc.expected: step3. Always returns OK. + */ + std::thread syncThread([]() { + std::vector devices; + devices.emplace_back(""); + Key key = {'k'}; + for (int i = 0; i < 100; ++i) { // sync 100 times + Query query = Query::Select().PrefixKey(key); + DBStatus status = g_kvNbDelegatePtr->Sync(devices, SYNC_MODE_PULL_ONLY, nullptr, query, true); + EXPECT_EQ(status, OK); + } + }); + syncThread.join(); + finish = true; + putThread.join(); + EXPECT_EQ(mgr.CloseKvStore(g_kvNbDelegatePtr), OK); + g_kvNbDelegatePtr = nullptr; + EXPECT_EQ(mgr.DeleteKvStore(STORE_ID_1), OK); } /** @@ -2467,4 +2519,164 @@ HWTEST_F(DistributedDBInterfacesNBDelegateTest, ResultSetLimitTest001, TestSize. EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); EXPECT_EQ(g_mgr.DeleteKvStore("ResultSetLimitTest001"), OK); g_kvNbDelegatePtr = nullptr; +} + +/** + * @tc.name: UpdateKey001 + * @tc.desc: Test update key + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesNBDelegateTest, UpdateKey001, TestSize.Level0) +{ + /** + * @tc.steps:step1. Create database. + * @tc.expected: step1. Returns a non-null kvstore. + */ + KvStoreNbDelegate::Option option; + g_mgr.GetKvStore("UpdateKey001", option, g_kvNbDelegateCallback); + ASSERT_TRUE(g_kvNbDelegatePtr != nullptr); + EXPECT_TRUE(g_kvDelegateStatus == OK); + /** + * @tc.steps:step2. Put (k1, v1) into the database. + * @tc.expected: step2. Returns OK. + */ + Key k1 = {'k', '1'}; + EXPECT_EQ(g_kvNbDelegatePtr->Put(k1, VALUE_1), OK); + /** + * @tc.steps:step3. Update (k1, v1) to (k10, v1). + * @tc.expected: step3. Returns OK and get k1 return not found. + */ + g_kvNbDelegatePtr->UpdateKey([](const Key &originKey, Key &newKey) { + newKey = originKey; + newKey.push_back('0'); + }); + Value actualValue; + EXPECT_EQ(g_kvNbDelegatePtr->Get(k1, actualValue), NOT_FOUND); + k1.push_back('0'); + EXPECT_EQ(g_kvNbDelegatePtr->Get(k1, actualValue), OK); + EXPECT_EQ(actualValue, VALUE_1); + /** + * @tc.steps:step4. Close store. + * @tc.expected: step4. Returns OK. + */ + EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); + EXPECT_EQ(g_mgr.DeleteKvStore("UpdateKey001"), OK); + g_kvNbDelegatePtr = nullptr; +} + +/** + * @tc.name: UpdateKey002 + * @tc.desc: Test update key with transaction + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesNBDelegateTest, UpdateKey002, TestSize.Level0) +{ + /** + * @tc.steps:step1. Create database. + * @tc.expected: step1. Returns a non-null kvstore. + */ + KvStoreNbDelegate::Option option; + g_mgr.GetKvStore("UpdateKey002", option, g_kvNbDelegateCallback); + ASSERT_TRUE(g_kvNbDelegatePtr != nullptr); + EXPECT_TRUE(g_kvDelegateStatus == OK); + /** + * @tc.steps:step2. Put (k1, v1) into the database . + * @tc.expected: step2. Returns OK. + */ + Key k1 = {'k', '1'}; + EXPECT_EQ(g_kvNbDelegatePtr->Put(k1, VALUE_1), OK); + g_kvNbDelegatePtr->StartTransaction(); + /** + * @tc.steps:step3. Update (k1, v1) to (k10, v1). + * @tc.expected: step3. Returns OK and get k1 return not found. + */ + g_kvNbDelegatePtr->UpdateKey([](const Key &originKey, Key &newKey) { + newKey = originKey; + newKey.push_back('0'); + }); + Value actualValue; + EXPECT_EQ(g_kvNbDelegatePtr->Get(k1, actualValue), NOT_FOUND); + Key k10 = {'k', '1', '0'}; + EXPECT_EQ(g_kvNbDelegatePtr->Get(k10, actualValue), OK); + EXPECT_EQ(actualValue, VALUE_1); + /** + * @tc.steps:step5. Rollback Transaction. + * @tc.expected: step5. k10 not exist in db. + */ + g_kvNbDelegatePtr->Rollback(); + EXPECT_EQ(g_kvNbDelegatePtr->Get(k10, actualValue), NOT_FOUND); + EXPECT_EQ(g_kvNbDelegatePtr->Get(k1, actualValue), OK); + /** + * @tc.steps:step5. Commit transaction. + * @tc.expected: step5. data exist in db. + */ + g_kvNbDelegatePtr->StartTransaction(); + g_kvNbDelegatePtr->UpdateKey([](const Key &originKey, Key &newKey) { + newKey = originKey; + newKey.push_back('0'); + }); + g_kvNbDelegatePtr->Commit(); + EXPECT_EQ(g_kvNbDelegatePtr->Get(k10, actualValue), OK); + /** + * @tc.steps:step6. Close store. + * @tc.expected: step6. Returns OK. + */ + EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); + EXPECT_EQ(g_mgr.DeleteKvStore("UpdateKey002"), OK); + g_kvNbDelegatePtr = nullptr; +} + +/** + * @tc.name: UpdateKey003 + * @tc.desc: Test update key with invalid args + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesNBDelegateTest, UpdateKey003, TestSize.Level0) +{ + /** + * @tc.steps:step1. Create database. + * @tc.expected: step1. Returns a non-null kvstore. + */ + KvStoreNbDelegate::Option option; + g_mgr.GetKvStore("UpdateKey003", option, g_kvNbDelegateCallback); + ASSERT_TRUE(g_kvNbDelegatePtr != nullptr); + EXPECT_TRUE(g_kvDelegateStatus == OK); + /** + * @tc.steps:step2. Put (k1, v1) into the database . + * @tc.expected: step2. Returns OK. + */ + Key k1 = {'k', '1'}; + Key k2 = {'k', '2'}; + EXPECT_EQ(g_kvNbDelegatePtr->Put(k1, VALUE_1), OK); + EXPECT_EQ(g_kvNbDelegatePtr->Put(k2, VALUE_1), OK); + /** + * @tc.steps:step3. Update key with nullptr or invalid key. + * @tc.expected: step3. Returns INVALID_ARGS. + */ + EXPECT_EQ(g_kvNbDelegatePtr->UpdateKey(nullptr), INVALID_ARGS); + DBStatus status = g_kvNbDelegatePtr->UpdateKey([](const Key &originKey, Key &newKey) { + newKey.clear(); + }); + EXPECT_EQ(status, INVALID_ARGS); + status = g_kvNbDelegatePtr->UpdateKey([](const Key &originKey, Key &newKey) { + newKey.assign(2048u, '0'); // 2048 is invalid len + }); + EXPECT_EQ(status, INVALID_ARGS); + status = g_kvNbDelegatePtr->UpdateKey([](const Key &originKey, Key &newKey) { + newKey = {'k', '3'}; + }); + EXPECT_EQ(status, CONSTRAINT); + /** + * @tc.steps:step4. Close store. + * @tc.expected: step4. Returns OK. + */ + EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); + EXPECT_EQ(g_mgr.DeleteKvStore("UpdateKey003"), OK); + g_kvNbDelegatePtr = nullptr; } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_sync_test.cpp index 6fb13ca526bd26a9b5deca188e6b615eea923106..a974f4a722600bfebcc39a2752a7ecc7d986c6ad 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_sync_test.cpp @@ -71,6 +71,15 @@ namespace { level INTEGER ))""; + const std::string ALL_FIELD_TYPE_TABLE_SQL = R""(CREATE TABLE IF NOT EXISTS tbl_all_type( + id INTEGER PRIMARY KEY, + f_int INT, + f_real REAL, + f_text TEXT, + f_blob BLOB, + f_none + ))""; + void FakeOldVersionDB(sqlite3 *db) { std::string dropTrigger = "DROP TRIGGER IF EXISTS naturalbase_rdb_student_1_ON_UPDATE;"; @@ -851,4 +860,166 @@ HWTEST_F(DistributedDBInterfacesRelationalSyncTest, TableFieldsOrderTest002, Tes EXPECT_EQ(sqlite3_column_int64(stmt, 3), 91); // 91 score return OK; }); +} + +/** + * @tc.name: SyncZeroBlobTest001 + * @tc.desc: Sync device with zero blob + * @tc.type: FUNC + * @tc.require: + * @tc.author: lianhuix + */ +HWTEST_F(DistributedDBInterfacesRelationalSyncTest, SyncZeroBlobTest001, TestSize.Level1) +{ + EXPECT_EQ(RelationalTestUtils::ExecSql(db, ALL_FIELD_TYPE_TABLE_SQL), SQLITE_OK); + EXPECT_EQ(delegate->CreateDistributedTable("tbl_all_type"), OK); + AddDeviceSchema(g_deviceB, db, "tbl_all_type"); + + // prepare with zero blob data + std::string insertSql = "INSERT INTO tbl_all_type VALUES(?, ?, ?, ?, ?, ?)"; + int ret = RelationalTestUtils::ExecSql(db, insertSql, [] (sqlite3_stmt *stmt) { + sqlite3_bind_int64(stmt, 1, 1001); // 1, 1001 bind index, bind value + sqlite3_bind_int64(stmt, 2, 12344); // 2, 12344 bind index, bind value + sqlite3_bind_double(stmt, 3, 1.234); // 3, 1.234 bind index, bind value + SQLiteUtils::BindTextToStatement(stmt, 4, ""); // 4, bind index + SQLiteUtils::BindBlobToStatement(stmt, 5, {}); // 5,bind index + return E_OK; + }, nullptr); + EXPECT_EQ(ret, E_OK); + + std::vector devices = {DEVICE_B}; + Query query = Query::Select("tbl_all_type"); + int errCode = delegate->Sync(devices, SyncMode::SYNC_MODE_PUSH_ONLY, query, + [&devices](const std::map> &devicesMap) { + EXPECT_EQ(devicesMap.size(), devices.size()); + for (const auto &itDev : devicesMap) { + for (const auto &itTbl : itDev.second) { + EXPECT_EQ(itTbl.status, OK); + } + } + }, true); + EXPECT_EQ(errCode, OK); + + std::vector data; + g_deviceB->GetAllSyncData("tbl_all_type", data); + EXPECT_EQ(data.size(), 1U); + for (const auto &it : data) { + DataValue val; + it.objectData.GetDataValue("id", val); + EXPECT_EQ(val.GetType(), StorageType::STORAGE_TYPE_INTEGER); + it.objectData.GetDataValue("f_int", val); + EXPECT_EQ(val.GetType(), StorageType::STORAGE_TYPE_INTEGER); + it.objectData.GetDataValue("f_real", val); + EXPECT_EQ(val.GetType(), StorageType::STORAGE_TYPE_REAL); + it.objectData.GetDataValue("f_text", val); + EXPECT_EQ(val.GetType(), StorageType::STORAGE_TYPE_TEXT); + it.objectData.GetDataValue("f_blob", val); + EXPECT_EQ(val.GetType(), StorageType::STORAGE_TYPE_BLOB); + it.objectData.GetDataValue("f_none", val); + EXPECT_EQ(val.GetType(), StorageType::STORAGE_TYPE_NULL); + } +} + +namespace { +struct TblAllType { + DataValue id_; + DataValue fInt_; + DataValue fReal_; + DataValue fText_; + DataValue fBlob_; + DataValue fNone_; + + TblAllType(int64_t id, int64_t fInt, double fReal, const std::string &fText, const Blob &fBlob) + { + id_ = id; + fInt_ = fInt; + fReal_ = fReal; + fText_ = fText; + fBlob_ = fBlob; + } + + VirtualRowData operator() () const + { + VirtualRowData virtualRowData; + virtualRowData.objectData.PutDataValue("id", id_); + virtualRowData.objectData.PutDataValue("f_int", fInt_); + virtualRowData.objectData.PutDataValue("f_real", fReal_); + virtualRowData.objectData.PutDataValue("f_text", fText_); + virtualRowData.objectData.PutDataValue("f_blob", fBlob_); + virtualRowData.objectData.PutDataValue("f_none", fNone_); + + virtualRowData.logInfo.dataKey = 4; // 4 fake datakey + virtualRowData.logInfo.device = DEVICE_B; + virtualRowData.logInfo.originDev = DEVICE_B; + virtualRowData.logInfo.timestamp = 3170194300891338180; // 3170194300891338180 fake timestamp + virtualRowData.logInfo.wTimestamp = 3170194300891338180; // 3170194300891338180 fake timestamp + virtualRowData.logInfo.flag = 2; // 2 fake flag + + std::vector hashKey; + DBCommon::CalcValueHash({}, hashKey); + virtualRowData.logInfo.hashKey = hashKey; + return virtualRowData; + } +}; +} + +/** + * @tc.name: SyncZeroBlobTest002 + * @tc.desc: Sync device with zero blob + * @tc.type: FUNC + * @tc.require: + * @tc.author: lianhuix + */ +HWTEST_F(DistributedDBInterfacesRelationalSyncTest, SyncZeroBlobTest002, TestSize.Level1) +{ + EXPECT_EQ(RelationalTestUtils::ExecSql(db, ALL_FIELD_TYPE_TABLE_SQL), SQLITE_OK); + EXPECT_EQ(delegate->CreateDistributedTable("tbl_all_type"), OK); + AddDeviceSchema(g_deviceB, db, "tbl_all_type"); + + std::vector dataList; + g_deviceB->PutDeviceData("tbl_all_type", + std::vector {{1001, 12344, 1.234, "", {}}}); // 1001, 12344, 1.234 : fake data + + std::vector devices = {DEVICE_B}; + Query query = Query::Select("tbl_all_type"); + int errCode = delegate->Sync(devices, SyncMode::SYNC_MODE_PULL_ONLY, query, + [&devices](const std::map> &devicesMap) { + EXPECT_EQ(devicesMap.size(), devices.size()); + for (const auto &itDev : devicesMap) { + for (const auto &itTbl : itDev.second) { + EXPECT_EQ(itTbl.status, OK); + } + } + }, true); + EXPECT_EQ(errCode, OK); + + std::string devictTbl = RelationalStoreManager::GetDistributedTableName(DEVICE_B, "tbl_all_type"); + std::string insertSql = "SELECT * FROM " + devictTbl; + int resCnt = 0; + int ret = RelationalTestUtils::ExecSql(db, insertSql, nullptr, [&resCnt](sqlite3_stmt *stmt) { + EXPECT_EQ(sqlite3_column_type(stmt, 0), SQLITE_INTEGER); + EXPECT_EQ(sqlite3_column_int(stmt, 0), 1001); // 1001: fake data + + EXPECT_EQ(sqlite3_column_type(stmt, 1), SQLITE_INTEGER); // 1: column index + EXPECT_EQ(sqlite3_column_int(stmt, 1), 12344); // 1: column index; 12344: fake data + + EXPECT_EQ(sqlite3_column_type(stmt, 2), SQLITE_FLOAT); // 2: column index + EXPECT_EQ(sqlite3_column_double(stmt, 2), 1.234); // 2: column index; 1.234: fake data + + EXPECT_EQ(sqlite3_column_type(stmt, 3), SQLITE_TEXT); // 3: column index + std::string strVal; + SQLiteUtils::GetColumnTextValue(stmt, 3, strVal); // 3: column index + EXPECT_EQ(strVal, ""); + + EXPECT_EQ(sqlite3_column_type(stmt, 4), SQLITE_BLOB); // 4: column index + std::vector blobVal; + SQLiteUtils::GetColumnBlobValue(stmt, 4, blobVal); // 4: column index + EXPECT_EQ(blobVal, std::vector {}); + + EXPECT_EQ(sqlite3_column_type(stmt, 5), SQLITE_NULL); // 5: column index + resCnt++; + return E_OK; + }); + EXPECT_EQ(resCnt, 1); + EXPECT_EQ(ret, E_OK); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp index dacc87d20b7594dc1eb11569981d257d31b9b0d0..52e3b789b5b947d6c7b2de01d805cec25fb8fabc 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/distributeddb_interfaces_relational_test.cpp @@ -729,9 +729,15 @@ HWTEST_F(DistributedDBInterfacesRelationalTest, RelationalRemoveDeviceDataTest00 * @tc.steps:step3. Remove device data * @tc.expected: step3. ok */ + EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_A"), DISTRIBUTED_SCHEMA_NOT_FOUND); + EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_D"), DISTRIBUTED_SCHEMA_NOT_FOUND); + EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_A", "sync_data"), DISTRIBUTED_SCHEMA_NOT_FOUND); + EXPECT_EQ(delegate->CreateDistributedTable("sync_data"), OK); EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_A"), OK); EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_B"), OK); EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_C", "sync_data"), OK); + EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_D"), OK); + EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_A", "sync_data_A"), DISTRIBUTED_SCHEMA_NOT_FOUND); /** * @tc.steps:step4. Remove device data with invalid args @@ -830,7 +836,7 @@ HWTEST_F(DistributedDBInterfacesRelationalTest, RelationalRemoveDeviceDataTest00 EXPECT_EQ(delegate->RemoveDeviceData(DEVICE_B), OK); int logCnt = -1; - std::string checkLogSql = "SELECT count(*) FROM naturalbase_rdb_aux_t1_log WHERE device = '" + DEVICE_B + "'"; + std::string checkLogSql = "SELECT count(*) FROM naturalbase_rdb_aux_t1_log"; RelationalTestUtils::ExecSql(db, checkLogSql, nullptr, [&logCnt](sqlite3_stmt *stmt) { logCnt = sqlite3_column_int(stmt, 0); return E_OK; @@ -839,7 +845,7 @@ HWTEST_F(DistributedDBInterfacesRelationalTest, RelationalRemoveDeviceDataTest00 int dataCnt = -1; std::string deviceTable = g_mgr.GetDistributedTableName(DEVICE_B, "t1"); - std::string checkDataSql = "SELECT count(*) FROM " + deviceTable + " WHERE device = '" + DEVICE_B + "'"; + std::string checkDataSql = "SELECT count(*) FROM " + deviceTable; RelationalTestUtils::ExecSql(db, checkDataSql, nullptr, [&dataCnt](sqlite3_stmt *stmt) { dataCnt = sqlite3_column_int(stmt, 0); return E_OK; @@ -851,6 +857,138 @@ HWTEST_F(DistributedDBInterfacesRelationalTest, RelationalRemoveDeviceDataTest00 EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); } +void TestRemoveDeviceDataWithCallback(bool removeAll) +{ + /** + * @tc.steps:step1. Prepare db and data + * @tc.expected: step1. Return OK. + */ + RuntimeConfig::SetTranslateToDeviceIdCallback([](const std::string &oriDevId, const StoreInfo &info) { + return oriDevId + "_" + info.appId; + }); + sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); + ASSERT_NE(db, nullptr); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, SIMPLE_CREATE_TABLE_SQL), SQLITE_OK); + AddDeviceSchema(g_deviceB, db, "t1"); + RelationalStoreDelegate *delegate = nullptr; + DBStatus status = g_mgr.OpenStore(g_dbDir + STORE_ID + DB_SUFFIX, STORE_ID, {}, delegate); + EXPECT_EQ(status, OK); + ASSERT_NE(delegate, nullptr); + EXPECT_EQ(delegate->CreateDistributedTable("t1"), OK); + g_deviceB->PutDeviceData("t1", std::vector { + {1, "111", 1, 0, 1} // test data + }); + std::vector devices = {DEVICE_B}; + Query query = Query::Select("t1").EqualTo("a", 1); + status = delegate->Sync(devices, SyncMode::SYNC_MODE_PULL_ONLY, query, + [&devices](const std::map> &devicesMap) { + ASSERT_EQ(devicesMap.size(), devices.size()); + EXPECT_EQ(devicesMap.at(DEVICE_B)[0].status, OK); + }, true); + EXPECT_EQ(status, OK); + /** + * @tc.steps:step2. remove device data and check table + * @tc.expected: step2. dev table not exist and log not exist device b. + */ + std::this_thread::sleep_for(std::chrono::seconds(1)); + if (removeAll) { + EXPECT_EQ(delegate->RemoveDeviceData(), OK); + } else { + EXPECT_EQ(delegate->RemoveDeviceData(DEVICE_B + "_" + APP_ID), OK); + } + int logCnt = -1; + std::string checkLogSql = "SELECT count(*) FROM naturalbase_rdb_aux_t1_log"; + RelationalTestUtils::ExecSql(db, checkLogSql, nullptr, [&logCnt](sqlite3_stmt *stmt) { + logCnt = sqlite3_column_int(stmt, 0); + return E_OK; + }); + EXPECT_EQ(logCnt, 0); + std::string deviceTable = RelationalStoreManager::GetDistributedTableName(DEVICE_B + "_" + APP_ID, "t1"); + std::string checkDataSql = "SELECT count(*) FROM " + deviceTable; + EXPECT_NE(RelationalTestUtils::ExecSql(db, checkDataSql, nullptr, nullptr), SQLITE_OK); + /** + * @tc.steps:step3. close db + * @tc.expected: step3. Return OK. + */ + status = g_mgr.CloseStore(delegate); + EXPECT_EQ(status, OK); + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); + RuntimeConfig::SetTranslateToDeviceIdCallback(nullptr); +} +/** + * @tc.name: RelationalRemoveDeviceDataTest003 + * @tc.desc: Test remove all device data and sync again + * @tc.type: FUNC + * @tc.require: AR000GK58F + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesRelationalTest, RelationalRemoveDeviceDataTest003, TestSize.Level1) +{ + TestRemoveDeviceDataWithCallback(true); +} + +/** + * @tc.name: RelationalRemoveDeviceDataTest004 + * @tc.desc: Test remove one device data and sync again + * @tc.type: FUNC + * @tc.require: AR000GK58F + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesRelationalTest, RelationalRemoveDeviceDataTest004, TestSize.Level1) +{ + TestRemoveDeviceDataWithCallback(false); +} + +/** + * @tc.name: RelationalRemoveDeviceDataTest005 + * @tc.desc: Test remove device data with invalid param + * @tc.type: FUNC + * @tc.require: AR000GK58F + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesRelationalTest, RelationalRemoveDeviceDataTest005, TestSize.Level1) +{ + /** + * @tc.steps:step1. Prepare db file + * @tc.expected: step1. Return OK. + */ + sqlite3 *db = RelationalTestUtils::CreateDataBase(g_dbDir + STORE_ID + DB_SUFFIX); + ASSERT_NE(db, nullptr); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, "PRAGMA journal_mode=WAL;"), SQLITE_OK); + EXPECT_EQ(RelationalTestUtils::ExecSql(db, NORMAL_CREATE_TABLE_SQL), SQLITE_OK); + RelationalTestUtils::CreateDeviceTable(db, "sync_data", "DEVICE_A"); + AddDeviceSchema(g_deviceB, db, "sync_data"); + /** + * @tc.steps:step2. Open store + * @tc.expected: step2. return OK + */ + RelationalStoreDelegate *delegate = nullptr; + DBStatus status = g_mgr.OpenStore(g_dbDir + STORE_ID + DB_SUFFIX, STORE_ID, {}, delegate); + EXPECT_EQ(status, OK); + ASSERT_NE(delegate, nullptr); + int count = 0; + RuntimeConfig::SetTranslateToDeviceIdCallback([&count](const std::string &oriDevId, const StoreInfo &info) { + count++; + return oriDevId + "_" + info.appId; + }); + /** + * @tc.steps:step3. Remove not exist device data + * @tc.expected: step3. ok + */ + EXPECT_EQ(delegate->CreateDistributedTable("sync_data"), OK); + EXPECT_EQ(delegate->RemoveDeviceData("DEVICE_C", "sync_data"), OK); + EXPECT_EQ(count, 0); + /** + * @tc.steps:step4. Close store + * @tc.expected: step4 Return OK. + */ + status = g_mgr.CloseStore(delegate); + EXPECT_EQ(status, OK); + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); + RuntimeConfig::SetTranslateToDeviceIdCallback(nullptr); +} + /** * @tc.name: RelationalOpenStorePathCheckTest001 * @tc.desc: Test open store with same label but different path. @@ -1067,4 +1205,30 @@ HWTEST_F(DistributedDBInterfacesRelationalTest, SqliteKeyWordTest001, TestSize.L EXPECT_EQ(status, OK); delegate = nullptr; EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); +} + +/** + * @tc.name: GetDistributedTableName001 + * @tc.desc: Test get distributed table name + * @tc.type: FUNC + * @tc.require: AR000GK58F + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBInterfacesRelationalTest, GetDistributedTableName001, TestSize.Level1) +{ + const std::string deviceName = "DEVICES_A"; + const std::string tableName = "TABLE"; + const std::string hashDev = DBCommon::TransferStringToHex(DBCommon::TransferHashString(deviceName)); + + std::string devTableName = RelationalStoreManager::GetDistributedTableName(deviceName, tableName); + EXPECT_EQ(devTableName, DBConstant::RELATIONAL_PREFIX + tableName + "_" + hashDev); + RuntimeConfig::SetTranslateToDeviceIdCallback([](const std::string &oriDevId, const StoreInfo &info) { + EXPECT_EQ(info.appId, ""); + return oriDevId; + }); + devTableName = RelationalStoreManager::GetDistributedTableName(deviceName, tableName); + EXPECT_EQ(devTableName, DBConstant::RELATIONAL_PREFIX + tableName + "_" + deviceName); + devTableName = RelationalStoreManager::GetDistributedTableName("", tableName); + EXPECT_EQ(devTableName, DBConstant::RELATIONAL_PREFIX + tableName + "_"); + RuntimeConfig::SetTranslateToDeviceIdCallback(nullptr); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/runtime_context_process_system_api_adapter_impl_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/runtime_context_process_system_api_adapter_impl_test.cpp index efc54f8b65e8dfa30bfbfeb27c1533b9c399400e..92b14a3333605c64f8d2c065e6941275ae561553 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/runtime_context_process_system_api_adapter_impl_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/interfaces/runtime_context_process_system_api_adapter_impl_test.cpp @@ -241,20 +241,13 @@ void FuncCheckDeviceSecurityAbility() RuntimeContext::GetInstance()->CheckDeviceSecurityAbility("", SecurityOption()); return; } -} -/** - * @tc.name: CheckDeviceSecurityAbility002 - * @tc.desc: Check device security ability with getkvstore frequency. - * @tc.type: FUNC - * @tc.require: AR000EV1G2 - */ -HWTEST_F(RuntimeContextProcessSystemApiAdapterImplTest, CheckDeviceSecurityAbility002, TestSize.Level1) +void CheckDeviceSecurityAbility002() { g_config.dataDir = g_testDir; - g_mgr.SetKvStoreConfig(g_config); + EXPECT_EQ(g_mgr.SetKvStoreConfig(g_config), OK); - RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(g_adapter); + EXPECT_EQ(RuntimeContext::GetInstance()->SetProcessSystemApiAdapter(g_adapter), E_OK); g_adapter->SetNeedCreateDb(true); const std::string storeId = "CheckDeviceSecurityAbility002"; @@ -264,14 +257,24 @@ HWTEST_F(RuntimeContextProcessSystemApiAdapterImplTest, CheckDeviceSecurityAbili LOGI("open store!!"); KvStoreNbDelegate::Option option1 = {true, false, false}; g_mgr.GetKvStore(storeId, option1, g_kvNbDelegateCallback); - g_mgr.CloseKvStore(g_kvNbDelegatePtr); + EXPECT_EQ(g_mgr.CloseKvStore(g_kvNbDelegatePtr), OK); } }); - std::thread t3(FuncCheckDeviceSecurityAbility); t1.join(); t2.join(); - t3.join(); +} +} + +/** + * @tc.name: CheckDeviceSecurityAbility002 + * @tc.desc: Check device security ability with getkvstore frequency. + * @tc.type: FUNC + * @tc.require: AR000EV1G2 + */ +HWTEST_F(RuntimeContextProcessSystemApiAdapterImplTest, CheckDeviceSecurityAbility002, TestSize.Level1) +{ + ASSERT_NO_FATAL_FAILURE(CheckDeviceSecurityAbility002()); } /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp index 28c64083d83c19594e5a87df54f9d6a59ea6f79a..96c3498d1f2ceb523678ef5cf33a896f8906a83a 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_relational_get_data_test.cpp @@ -261,6 +261,23 @@ void SetRemoteSchema(const RelationalSyncAbleStorage *store, const std::string & uint8_t remoteSchemaType = static_cast(store->GetSchemaInfo().GetSchemaType()); const_cast(store)->SaveRemoteDeviceSchema(deviceID, remoteSchema, remoteSchemaType); } + +void SetNextBeginTime001() +{ + QueryObject query(Query::Select(g_tableName)); + std::unique_ptr token = + std::make_unique(SyncTimeRange {}, query); + ASSERT_TRUE(token != nullptr); + + DataItem dataItem; + dataItem.timestamp = INT64_MAX; + token->SetNextBeginTime(dataItem); + + dataItem.flag = DataItem::DELETE_FLAG; + token->FinishGetData(); + EXPECT_EQ(token->IsGetAllDataFinished(), false); + token->SetNextBeginTime(dataItem); +} } class DistributedDBRelationalGetDataTest : public testing::Test { @@ -1596,18 +1613,7 @@ HWTEST_F(DistributedDBRelationalGetDataTest, SetSchema1, TestSize.Level1) */ HWTEST_F(DistributedDBRelationalGetDataTest, SetNextBeginTime001, TestSize.Level1) { - QueryObject query(Query::Select(g_tableName)); - std::unique_ptr token = - std::make_unique(SyncTimeRange {}, query); - ASSERT_TRUE(token != nullptr); - - DataItem dataItem; - dataItem.timestamp = INT64_MAX; - token->SetNextBeginTime(dataItem); - - dataItem.flag = DataItem::DELETE_FLAG; - token->FinishGetData(); - token->SetNextBeginTime(dataItem); + ASSERT_NO_FATAL_FAILURE(SetNextBeginTime001()); } /** diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_single_ver_natural_store_testcase.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_single_ver_natural_store_testcase.h index 72c514e56258a65c25bdd683b405616f9ff5d1b7..0846199cd3d9c2509140cd108396eb69d5b2e548 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_single_ver_natural_store_testcase.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_single_ver_natural_store_testcase.h @@ -12,6 +12,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#ifndef DISTRIBUTEDDB_STORAGE_SINGLE_VER_NATURAL_STORE_TESTCASE_H +#define DISTRIBUTEDDB_STORAGE_SINGLE_VER_NATURAL_STORE_TESTCASE_H #include #include "db_errno.h" @@ -23,8 +25,6 @@ #include "sqlite_single_ver_natural_store_connection.h" #include "sqlite_utils.h" -#ifndef DISTRIBUTEDDB_STORAGE_SINGLE_VER_NATURAL_STORE_TESTCASE_H -#define DISTRIBUTEDDB_STORAGE_SINGLE_VER_NATURAL_STORE_TESTCASE_H struct SyncData { std::vector hashKey; std::vector key; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp index 6467e541b53ef582d01bb49f6c1fb6ac3c48e954..71805b5f245250c2c7073ee4226629def807fad5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_sqlite_single_ver_natural_executor_test.cpp @@ -54,7 +54,7 @@ public: void DistributedDBStorageSQLiteSingleVerNaturalExecutorTest::SetUpTestCase(void) { DistributedDBToolsUnitTest::TestDirInit(g_testDir); - LOGD("DistributedDBStorageSQLiteSingleVerNaturalExecutorTest dir is %s", g_testDir.c_str()); + LOGI("DistributedDBStorageSQLiteSingleVerNaturalExecutorTest dir is %s", g_testDir.c_str()); std::string oriIdentifier = APP_ID + "-" + USER_ID + "-" + "TestGeneralNBExecutor"; std::string identifier = DBCommon::TransferHashString(oriIdentifier); g_identifier = DBCommon::TransferStringToHex(identifier); @@ -454,7 +454,8 @@ HWTEST_F(DistributedDBStorageSQLiteSingleVerNaturalExecutorTest, InvalidParam011 uint64_t version = 0u; EXPECT_EQ(executor->GetMinVersionCacheData(vec, version), E_OK); EXPECT_EQ(executor->GetMaxVersionInCacheDb(version), E_OK); - EXPECT_EQ(executor->RemoveDeviceDataInCacheMode("device1", true, 0u), E_OK); + std::string hashDev = DBCommon::TransferHashString("device1"); + EXPECT_EQ(executor->RemoveDeviceDataInCacheMode(hashDev, true, 0u), E_OK); sqlite3_close_v2(sqlHandle); sqlHandle = nullptr; } @@ -878,7 +879,8 @@ HWTEST_F(DistributedDBStorageSQLiteSingleVerNaturalExecutorTest, ExecutorCache00 std::vector keys; EXPECT_EQ(g_handle->DeleteMetaData(keys), SQL_STATE_ERR); EXPECT_EQ(g_handle->PrepareForSavingCacheData(SingleVerDataType::LOCAL_TYPE), SQL_STATE_ERR); - EXPECT_EQ(g_handle->RemoveDeviceDataInCacheMode("device1", true, 0u), SQL_STATE_ERR); + std::string hashDev = DBCommon::TransferHashString("device1"); + EXPECT_EQ(g_handle->RemoveDeviceDataInCacheMode(hashDev, true, 0u), SQL_STATE_ERR); Timestamp timestamp; EXPECT_EQ(g_handle->GetMaxTimestampDuringMigrating(timestamp), -E_NOT_INIT); EXPECT_EQ(g_handle->ResetForSavingCacheData(SingleVerDataType::LOCAL_TYPE), E_OK); @@ -926,7 +928,6 @@ HWTEST_F(DistributedDBStorageSQLiteSingleVerNaturalExecutorTest, ExecutorCache00 /** * @tc.steps: step3. Change executor to MAIN_ATTACH_CACHE - * @tc.expected: step3. Expect SQL_STATE_ERR */ auto executor2 = std::make_unique( sqlHandle, false, false, ExecutorState::MAIN_ATTACH_CACHE); diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp index 7248ae2f766ce8c1f8d46792f630ad7fdb7fe92e..c485778696ad0c5ab8c817bcbf500241e2cda948 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/storage/distributeddb_storage_subscribe_query_test.cpp @@ -815,4 +815,50 @@ HWTEST_F(DistributedDBStorageSubscribeQueryTest, AddSubscribeTest003, TestSize.L */ RefObject::KillAndDecObjRef(store); KvDBManager::ReleaseDatabaseConnection(conn); +} + +/** + * @tc.name: AddSubscribeTest004 + * @tc.desc: Add subscribe with query by prefixKey + * @tc.type: FUNC + * @tc.require: + * @tc.author: xulianhui + */ +HWTEST_F(DistributedDBStorageSubscribeQueryTest, AddSubscribeTest004, TestSize.Level1) +{ + /** + * @tc.steps:step1. Create a json schema db, get the natural store instance. + * @tc.expected: Get results OK and non-null store. + */ + SQLiteSingleVerNaturalStoreConnection *conn = nullptr; + SQLiteSingleVerNaturalStore *store = nullptr; + CreateAndGetStore("SubscribeTest02", "", conn, store); + + /** + * @tc.steps:step2. Add subscribe with query by prefixKey + * @tc.expected: step2. add success + */ + Query query = Query::Select().PrefixKey(NULL_KEY_1); + QueryObject queryObj(query); + int errCode = store->AddSubscribe(SUBSCRIBE_ID, queryObj, false); + EXPECT_EQ(errCode, E_OK); + + IOption syncIOpt {IOption::SYNC_DATA}; + EXPECT_EQ(conn->Put(syncIOpt, KEY_1, {}), E_OK); + + Value valGot; + EXPECT_EQ(conn->Get(syncIOpt, KEY_1, valGot), E_OK); + EXPECT_EQ(valGot, Value {}); + + std::string subKey = DBConstant::SUBSCRIBE_QUERY_PREFIX + DBCommon::TransferHashString(SUBSCRIBE_ID); + Key metaKey(subKey.begin(), subKey.end()); + EXPECT_EQ(store->GetMetaData(metaKey, valGot), E_OK); + EXPECT_NE(valGot.size(), 0u); + + /** + * @tc.steps:step3. Close natural store + * @tc.expected: step3. Close ok + */ + RefObject::KillAndDecObjRef(store); + KvDBManager::ReleaseDatabaseConnection(conn); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp index 9e688a50dbdf7f530bf3938c3341da4c9af696c7..5ab5ce608d8967ef472610657055ba4a72db9eb5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_mock_sync_module_test.cpp @@ -62,9 +62,9 @@ public: { syncer_.LocalDataChanged(static_cast(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT)); } - void Close() + int Close() { - syncer_.Close(true); + return syncer_.Close(true); } private: SyncerProxy syncer_; @@ -117,6 +117,7 @@ void Init(MockSingleVerStateMachine &stateMachine, MockSyncTaskContext *syncTask MockCommunicator &communicator, VirtualSingleVerSyncDBInterface *dbSyncInterface) { std::shared_ptr metadata = std::make_shared(); + ASSERT_EQ(metadata->Initialize(dbSyncInterface), E_OK); (void)syncTaskContext->Initialize("device", dbSyncInterface, metadata, &communicator); (void)stateMachine.Initialize(syncTaskContext, dbSyncInterface, metadata, &communicator); } @@ -166,6 +167,218 @@ void ConstructPacel(Parcel &parcel, uint32_t conditionCount, const std::string & parcel.WriteString(key); parcel.WriteString(value); } + +void StateMachineCheck013() +{ + MockSingleVerStateMachine stateMachine; + auto *syncTaskContext = new (std::nothrow) MockSyncTaskContext(); + auto *dbSyncInterface = new (std::nothrow) VirtualSingleVerSyncDBInterface(); + ASSERT_NE(syncTaskContext, nullptr); + EXPECT_NE(dbSyncInterface, nullptr); + if (dbSyncInterface == nullptr) { + RefObject::KillAndDecObjRef(syncTaskContext); + return; + } + MockCommunicator communicator; + Init(stateMachine, syncTaskContext, communicator, dbSyncInterface); + int count = 0; + EXPECT_CALL(*syncTaskContext, Clear()).WillRepeatedly([&count]() { + count++; + }); + syncTaskContext->RegForkGetDeviceIdFunc([]() { + std::this_thread::sleep_for(std::chrono::seconds(2)); // sleep 2s + }); + auto token = new VirtualContinueToken(); + syncTaskContext->SetContinueToken(static_cast(token)); + RefObject::KillAndDecObjRef(syncTaskContext); + delete dbSyncInterface; + std::this_thread::sleep_for(std::chrono::seconds(5)); // sleep 5s and wait for task exist + EXPECT_EQ(count, 1); +} + +void AutoLaunchCheck001() +{ + MockAutoLaunch mockAutoLaunch; + /** + * @tc.steps: step1. put AutoLaunchItem in cache to simulate a connection was auto launched + */ + std::string id = "TestAutoLaunch"; + std::string userId = "userId"; + AutoLaunchItem item; + mockAutoLaunch.SetAutoLaunchItem(id, userId, item); + EXPECT_CALL(mockAutoLaunch, TryCloseConnection(_)).WillOnce(Return()); + /** + * @tc.steps: step2. send close signal to simulate a connection was unused in 1 min + * @tc.expected: 10 thread try to close the connection and one thread close success + */ + const int loopCount = 10; + int finishCount = 0; + std::mutex mutex; + std::unique_lock lock(mutex); + std::condition_variable cv; + for (int i = 0; i < loopCount; i++) { + std::thread t = std::thread([&finishCount, &mockAutoLaunch, &id, &userId, &mutex, &cv] { + mockAutoLaunch.CallExtConnectionLifeCycleCallbackTask(id, userId); + finishCount++; + if (finishCount == loopCount) { + std::unique_lock lockInner(mutex); + cv.notify_one(); + } + }); + t.detach(); + } + cv.wait(lock, [&finishCount, &loopCount]() { return finishCount == loopCount; }); +} + +void AbilitySync004() +{ + /** + * @tc.steps: step1. set table TEST is permitSync + */ + auto *context = new (std::nothrow) SingleVerKvSyncTaskContext(); + ASSERT_NE(context, nullptr); + /** + * @tc.steps: step2. test context recv dbAbility in diff thread + */ + const int loopCount = 1000; + std::atomic finishCount = 0; + std::mutex mutex; + std::unique_lock lock(mutex); + std::condition_variable cv; + for (int i = 0; i < loopCount; i++) { + std::thread t = std::thread([&context, &finishCount, &cv] { + DbAbility dbAbility; + context->SetDbAbility(dbAbility); + finishCount++; + if (finishCount == loopCount) { + cv.notify_one(); + } + }); + t.detach(); + } + cv.wait(lock, [&]() { return finishCount == loopCount; }); + EXPECT_EQ(context->GetRemoteCompressAlgoStr(), "none"); + RefObject::KillAndDecObjRef(context); +} + +void SyncLifeTest001() +{ + std::shared_ptr syncer = std::make_shared(); + VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); + ASSERT_NE(virtualCommunicatorAggregator, nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); + VirtualSingleVerSyncDBInterface *syncDBInterface = new VirtualSingleVerSyncDBInterface(); + ASSERT_NE(syncDBInterface, nullptr); + EXPECT_EQ(syncer->Initialize(syncDBInterface, true), -E_INVALID_ARGS); + syncer->EnableAutoSync(true); + for (int i = 0; i < 1000; i++) { // trigger 1000 times auto sync check + syncer->LocalDataChanged(static_cast(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT)); + } + EXPECT_EQ(virtualCommunicatorAggregator->GetOnlineDevices().size(), 0u); + syncer = nullptr; + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + delete syncDBInterface; +} + +void SyncLifeTest002() +{ + std::shared_ptr syncer = std::make_shared(); + VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); + ASSERT_NE(virtualCommunicatorAggregator, nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); + const std::string DEVICE_B = "deviceB"; + VirtualSingleVerSyncDBInterface *syncDBInterface = new VirtualSingleVerSyncDBInterface(); + ASSERT_NE(syncDBInterface, nullptr); + std::string userId = "userid_0"; + std::string storeId = "storeId_0"; + std::string appId = "appid_0"; + std::string identifier = KvStoreDelegateManager::GetKvStoreIdentifier(userId, appId, storeId); + std::vector identifierVec(identifier.begin(), identifier.end()); + syncDBInterface->SetIdentifier(identifierVec); + for (int i = 0; i < 100; i++) { // run 100 times + EXPECT_EQ(syncer->Initialize(syncDBInterface, true), E_OK); + syncer->EnableAutoSync(true); + virtualCommunicatorAggregator->OnlineDevice(DEVICE_B); + std::thread writeThread([syncer]() { + syncer->LocalDataChanged( + static_cast(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT)); + }); + std::thread closeThread([syncer, &syncDBInterface]() { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + EXPECT_EQ(syncer->Close(true), E_OK); + }); + closeThread.join(); + writeThread.join(); + } + syncer = nullptr; + std::this_thread::sleep_for(std::chrono::seconds(1)); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + delete syncDBInterface; +} + +void SyncLifeTest003() +{ + VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); + ASSERT_NE(virtualCommunicatorAggregator, nullptr); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); + TestInterface *syncDBInterface = new TestInterface(); + ASSERT_NE(syncDBInterface, nullptr); + const std::string DEVICE_B = "deviceB"; + std::string userId = "userId_0"; + std::string storeId = "storeId_0"; + std::string appId = "appId_0"; + std::string identifier = KvStoreDelegateManager::GetKvStoreIdentifier(userId, appId, storeId); + std::vector identifierVec(identifier.begin(), identifier.end()); + syncDBInterface->TestSetIdentifier(identifierVec); + syncDBInterface->Initialize(); + virtualCommunicatorAggregator->OnlineDevice(DEVICE_B); + syncDBInterface->TestLocalChange(); + virtualCommunicatorAggregator->OfflineDevice(DEVICE_B); + EXPECT_EQ(syncDBInterface->Close(), E_OK); + RefObject::KillAndDecObjRef(syncDBInterface); + RuntimeContext::GetInstance()->StopTaskPool(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); +} + +void MockRemoteQuery002() +{ + MockRemoteExecutor *executor = new (std::nothrow) MockRemoteExecutor(); + ASSERT_NE(executor, nullptr); + EXPECT_EQ(executor->CallResponseFailed(0, 0, 0, "DEVICE"), -E_BUSY); + RefObject::KillAndDecObjRef(executor); +} + +void SyncerCheck001() +{ + std::shared_ptr syncer = std::make_shared(); + EXPECT_EQ(syncer->SetSyncRetry(true), -E_NOT_INIT); + syncer = nullptr; +} + +void TimeSync001() +{ + auto *communicator = new(std::nothrow) MockCommunicator(); + ASSERT_NE(communicator, nullptr); + auto *storage = new(std::nothrow) VirtualSingleVerSyncDBInterface(); + ASSERT_NE(storage, nullptr); + std::shared_ptr metadata = std::make_shared(); + + EXPECT_CALL(*communicator, SendMessage(_, _, _, _)).WillRepeatedly(Return(DB_ERROR)); + const int loopCount = 100; + const int timeDriverMs = 100; + for (int i = 0; i < loopCount; ++i) { + MockTimeSync timeSync; + EXPECT_EQ(timeSync.Initialize(communicator, metadata, storage, "DEVICES_A"), E_OK); + timeSync.ModifyTimer(timeDriverMs); + std::this_thread::sleep_for(std::chrono::milliseconds(timeDriverMs)); + timeSync.Close(); + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + metadata = nullptr; + delete storage; + delete communicator; +} } class DistributedDBMockSyncModuleTest : public testing::Test { @@ -346,7 +559,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, StateMachineCheck006, TestSize.Level1) // we expect machine don't change context status when queue not empty EXPECT_CALL(syncTaskContext, SetOperationStatus(_)).WillOnce(Return()); EXPECT_CALL(syncTaskContext, SetTaskExecStatus(_)).WillOnce(Return()); - EXPECT_CALL(syncTaskContext, Clear()).WillOnce(Return()); + EXPECT_CALL(syncTaskContext, Clear()).WillRepeatedly(Return()); EXPECT_EQ(stateMachine.CallExecNextTask(), -E_NO_SYNC_TASK); } @@ -489,28 +702,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, StateMachineCheck012, TestSize.Level1) */ HWTEST_F(DistributedDBMockSyncModuleTest, StateMachineCheck013, TestSize.Level1) { - MockSingleVerStateMachine stateMachine; - auto *syncTaskContext = new (std::nothrow) MockSyncTaskContext(); - auto *dbSyncInterface = new (std::nothrow) VirtualSingleVerSyncDBInterface(); - ASSERT_NE(syncTaskContext, nullptr); - EXPECT_NE(dbSyncInterface, nullptr); - if (dbSyncInterface == nullptr) { - RefObject::KillAndDecObjRef(syncTaskContext); - return; - } - MockCommunicator communicator; - Init(stateMachine, syncTaskContext, communicator, dbSyncInterface); - EXPECT_CALL(*syncTaskContext, Clear()).WillRepeatedly(Return()); - syncTaskContext->RegForkGetDeviceIdFunc([]() { - std::this_thread::sleep_for(std::chrono::seconds(2)); // sleep 2s - }); - int token = 1; - int *tokenPtr = &token; - syncTaskContext->SetContinueToken(tokenPtr); - RefObject::KillAndDecObjRef(syncTaskContext); - delete dbSyncInterface; - std::this_thread::sleep_for(std::chrono::seconds(5)); // sleep 5s and wait for task exist - tokenPtr = nullptr; + ASSERT_NO_FATAL_FAILURE(StateMachineCheck013()); } /** @@ -600,6 +792,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, DataSyncCheck003, TestSize.Level1) delete message; } #endif + /** * @tc.name: AutoLaunchCheck001 * @tc.desc: Test autoLaunch close connection. @@ -609,36 +802,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, DataSyncCheck003, TestSize.Level1) */ HWTEST_F(DistributedDBMockSyncModuleTest, AutoLaunchCheck001, TestSize.Level1) { - MockAutoLaunch mockAutoLaunch; - /** - * @tc.steps: step1. put AutoLaunchItem in cache to simulate a connection was auto launched - */ - std::string id = "TestAutoLaunch"; - std::string userId = "userId"; - AutoLaunchItem item; - mockAutoLaunch.SetAutoLaunchItem(id, userId, item); - EXPECT_CALL(mockAutoLaunch, TryCloseConnection(_)).WillOnce(Return()); - /** - * @tc.steps: step2. send close signal to simulate a connection was unused in 1 min - * @tc.expected: 10 thread try to close the connection and one thread close success - */ - const int loopCount = 10; - int finishCount = 0; - std::mutex mutex; - std::unique_lock lock(mutex); - std::condition_variable cv; - for (int i = 0; i < loopCount; i++) { - std::thread t = std::thread([&finishCount, &mockAutoLaunch, &id, &userId, &mutex, &cv] { - mockAutoLaunch.CallExtConnectionLifeCycleCallbackTask(id, userId); - finishCount++; - if (finishCount == loopCount) { - std::unique_lock lockInner(mutex); - cv.notify_one(); - } - }); - t.detach(); - } - cv.wait(lock, [&finishCount, &loopCount]() { return finishCount == loopCount; }); + ASSERT_NO_FATAL_FAILURE(AutoLaunchCheck001()); } /** @@ -833,32 +997,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, AbilitySync003, TestSize.Level1) */ HWTEST_F(DistributedDBMockSyncModuleTest, AbilitySync004, TestSize.Level1) { - /** - * @tc.steps: step1. set table TEST is permitSync - */ - auto *context = new (std::nothrow) SingleVerKvSyncTaskContext(); - ASSERT_NE(context, nullptr); - /** - * @tc.steps: step2. test context recv dbAbility in diff thread - */ - const int loopCount = 1000; - std::atomic finishCount = 0; - std::mutex mutex; - std::unique_lock lock(mutex); - std::condition_variable cv; - for (int i = 0; i < loopCount; i++) { - std::thread t = std::thread([&] { - DbAbility dbAbility; - context->SetDbAbility(dbAbility); - finishCount++; - if (finishCount == loopCount) { - cv.notify_one(); - } - }); - t.detach(); - } - cv.wait(lock, [&]() { return finishCount == loopCount; }); - RefObject::KillAndDecObjRef(context); + ASSERT_NO_FATAL_FAILURE(AbilitySync004()); } /** @@ -870,18 +1009,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, AbilitySync004, TestSize.Level1) */ HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest001, TestSize.Level3) { - std::shared_ptr syncer = std::make_shared(); - VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); - RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); - VirtualSingleVerSyncDBInterface *syncDBInterface = new VirtualSingleVerSyncDBInterface(); - syncer->Initialize(syncDBInterface, true); - syncer->EnableAutoSync(true); - for (int i = 0; i < 1000; i++) { // trigger 1000 times auto sync check - syncer->LocalDataChanged(static_cast(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT)); - } - syncer = nullptr; - RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); - delete syncDBInterface; + ASSERT_NO_FATAL_FAILURE(SyncLifeTest001()); } /** @@ -893,36 +1021,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest001, TestSize.Level3) */ HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest002, TestSize.Level3) { - std::shared_ptr syncer = std::make_shared(); - VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); - RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); - const std::string DEVICE_B = "deviceB"; - VirtualSingleVerSyncDBInterface *syncDBInterface = new VirtualSingleVerSyncDBInterface(); - std::string userId = "userid_0"; - std::string storeId = "storeId_0"; - std::string appId = "appid_0"; - std::string identifier = KvStoreDelegateManager::GetKvStoreIdentifier(userId, appId, storeId); - std::vector identifierVec(identifier.begin(), identifier.end()); - syncDBInterface->SetIdentifier(identifierVec); - for (int i = 0; i < 100; i++) { // run 100 times - syncer->Initialize(syncDBInterface, true); - syncer->EnableAutoSync(true); - virtualCommunicatorAggregator->OnlineDevice(DEVICE_B); - std::thread writeThread([syncer]() { - syncer->LocalDataChanged( - static_cast(SQLiteGeneralNSNotificationEventType::SQLITE_GENERAL_NS_PUT_EVENT)); - }); - std::thread closeThread([syncer, &syncDBInterface]() { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - syncer->Close(true); - }); - closeThread.join(); - writeThread.join(); - } - syncer = nullptr; - std::this_thread::sleep_for(std::chrono::seconds(1)); - RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); - delete syncDBInterface; + ASSERT_NO_FATAL_FAILURE(SyncLifeTest002()); } /** @@ -934,25 +1033,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest002, TestSize.Level3) */ HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest003, TestSize.Level3) { - VirtualCommunicatorAggregator *virtualCommunicatorAggregator = new VirtualCommunicatorAggregator(); - RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); - TestInterface *syncDBInterface = new TestInterface(); - const std::string DEVICE_B = "deviceB"; - std::string userId = "userId_0"; - std::string storeId = "storeId_0"; - std::string appId = "appId_0"; - std::string identifier = KvStoreDelegateManager::GetKvStoreIdentifier(userId, appId, storeId); - std::vector identifierVec(identifier.begin(), identifier.end()); - syncDBInterface->TestSetIdentifier(identifierVec); - syncDBInterface->Initialize(); - virtualCommunicatorAggregator->OnlineDevice(DEVICE_B); - syncDBInterface->TestLocalChange(); - virtualCommunicatorAggregator->OfflineDevice(DEVICE_B); - syncDBInterface->Close(); - RefObject::KillAndDecObjRef(syncDBInterface); - RuntimeContext::GetInstance()->StopTaskPool(); - std::this_thread::sleep_for(std::chrono::seconds(1)); - RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + ASSERT_NO_FATAL_FAILURE(SyncLifeTest003()); } /** @@ -979,8 +1060,8 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncLifeTest004, TestSize.Level3) syncer->EnableAutoSync(true); incRefCount = 0; syncer->RemoteDataChanged(""); - EXPECT_EQ(incRefCount, 1); // refCount is 1 std::this_thread::sleep_for(std::chrono::seconds(1)); + EXPECT_EQ(incRefCount, 2); // refCount is 2 syncer = nullptr; RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); delete syncDBInterface; @@ -1431,10 +1512,7 @@ HWTEST_F(DistributedDBMockSyncModuleTest, MockRemoteQuery001, TestSize.Level3) */ HWTEST_F(DistributedDBMockSyncModuleTest, MockRemoteQuery002, TestSize.Level3) { - MockRemoteExecutor *executor = new (std::nothrow) MockRemoteExecutor(); - ASSERT_NE(executor, nullptr); - executor->CallResponseFailed(0, 0, 0, "DEVICE"); - RefObject::KillAndDecObjRef(executor); + ASSERT_NO_FATAL_FAILURE(MockRemoteQuery002()); } /** @@ -1456,6 +1534,62 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SyncTaskContextCheck001, TestSize.Leve EXPECT_EQ(syncTaskContext.CallIsCurrentSyncTaskCanBeSkipped(), true); } +/** + * @tc.name: SyncTaskContextCheck002 + * @tc.desc: test context check task can be skipped in push mode. + * @tc.type: FUNC + * @tc.require: AR000CCPOM + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncTaskContextCheck002, TestSize.Level1) +{ + /** + * @tc.steps: step1. create context and operation + */ + auto syncTaskContext = new(std::nothrow) MockSyncTaskContext(); + ASSERT_NE(syncTaskContext, nullptr); + auto operation = new SyncOperation(1u, {}, static_cast(SyncModeType::QUERY_PUSH), nullptr, false); + ASSERT_NE(operation, nullptr); + QuerySyncObject querySyncObject; + operation->SetQuery(querySyncObject); + syncTaskContext->SetSyncOperation(operation); + syncTaskContext->SetLastFullSyncTaskStatus(SyncOperation::Status::OP_FAILED); + syncTaskContext->CallSetSyncMode(static_cast(SyncModeType::QUERY_PUSH)); + EXPECT_CALL(*syncTaskContext, IsTargetQueueEmpty()).WillRepeatedly(Return(false)); + + const int loopCount = 1000; + /** + * @tc.steps: step2. loop 1000 times for writing data into lastQuerySyncTaskStatusMap_ async + */ + std::thread writeThread([&syncTaskContext]() { + for (int i = 0; i < loopCount; ++i) { + syncTaskContext->SaveLastPushTaskExecStatus(static_cast(SyncOperation::Status::OP_FAILED)); + } + }); + /** + * @tc.steps: step3. loop 100000 times for clear lastQuerySyncTaskStatusMap_ async + */ + std::thread clearThread([&syncTaskContext]() { + for (int i = 0; i < 100000; ++i) { // loop 100000 times + syncTaskContext->ResetLastPushTaskStatus(); + } + }); + /** + * @tc.steps: step4. loop 1000 times for read data from lastQuerySyncTaskStatusMap_ async + */ + std::thread readThread([&syncTaskContext]() { + for (int i = 0; i < loopCount; ++i) { + EXPECT_EQ(syncTaskContext->CallIsCurrentSyncTaskCanBeSkipped(), false); + } + }); + writeThread.join(); + clearThread.join(); + readThread.join(); + RefObject::KillAndDecObjRef(operation); + syncTaskContext->SetSyncOperation(nullptr); + RefObject::KillAndDecObjRef(syncTaskContext); +} + #ifdef RUN_AS_ROOT /** * @tc.name: TimeChangeListenerTest001 @@ -1531,9 +1665,52 @@ HWTEST_F(DistributedDBMockSyncModuleTest, TimeChangeListenerTest002, TestSize.Le */ HWTEST_F(DistributedDBMockSyncModuleTest, SyncerCheck001, TestSize.Level1) { + ASSERT_NO_FATAL_FAILURE(SyncerCheck001()); +} + +/** + * @tc.name: SyncerCheck002 + * @tc.desc: Test syncer call get timestamp with close and open. + * @tc.type: FUNC + * @tc.require: AR000CCPOM + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBMockSyncModuleTest, SyncerCheck002, TestSize.Level1) +{ + /** + * @tc.steps: step1. create context and syncer + */ std::shared_ptr syncer = std::make_shared(); - syncer->SetSyncRetry(true); + auto virtualCommunicatorAggregator = new(std::nothrow) VirtualCommunicatorAggregator(); + ASSERT_NE(virtualCommunicatorAggregator, nullptr); + auto syncDBInterface = new VirtualSingleVerSyncDBInterface(); + ASSERT_NE(syncDBInterface, nullptr); + std::vector identifier(COMM_LABEL_LENGTH, 1u); + syncDBInterface->SetIdentifier(identifier); + RuntimeContext::GetInstance()->SetCommunicatorAggregator(virtualCommunicatorAggregator); + /** + * @tc.steps: step2. get timestamp by syncer over and over again + */ + std::atomic finish = false; + std::thread t([&finish, &syncer]() { + while (!finish) { + (void) syncer->GetTimestamp(); + } + }); + /** + * @tc.steps: step3. re init syncer over and over again + * @tc.expected: step3. dont crash here. + */ + for (int i = 0; i < 100; ++i) { // loop 100 times + syncer->Initialize(syncDBInterface, false); + syncer->Close(true); + } + finish = true; + t.join(); + delete syncDBInterface; syncer = nullptr; + RuntimeContext::GetInstance()->SetCommunicatorAggregator(nullptr); + RuntimeContext::GetInstance()->StopTaskPool(); } /** @@ -1562,24 +1739,5 @@ HWTEST_F(DistributedDBMockSyncModuleTest, SessionId001, TestSize.Level1) */ HWTEST_F(DistributedDBMockSyncModuleTest, TimeSync001, TestSize.Level1) { - auto *communicator = new(std::nothrow) MockCommunicator(); - ASSERT_NE(communicator, nullptr); - auto *storage = new(std::nothrow) VirtualSingleVerSyncDBInterface(); - ASSERT_NE(storage, nullptr); - std::shared_ptr metadata = std::make_shared(); - - EXPECT_CALL(*communicator, SendMessage(_, _, _, _)).WillRepeatedly(Return(DB_ERROR)); - const int loopCount = 100; - const int timeDriverMs = 100; - for (int i = 0; i < loopCount; ++i) { - MockTimeSync timeSync; - timeSync.Initialize(communicator, metadata, storage, "DEVICES_A"); - timeSync.ModifyTimer(timeDriverMs); - std::this_thread::sleep_for(std::chrono::milliseconds(timeDriverMs)); - timeSync.Close(); - } - std::this_thread::sleep_for(std::chrono::seconds(1)); - metadata = nullptr; - delete storage; - delete communicator; + ASSERT_NO_FATAL_FAILURE(TimeSync001()); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp index e8824554bcd8aae6ff5d32e6827e772fe648ada4..15917ba4dd2d1528f388224575a3c6c0cdccd6ac 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_multi_user_test.cpp @@ -878,7 +878,7 @@ HWTEST_F(DistributedDBRelationalMultiUserTest, RdbMultiUser010, TestSize.Level1) }); /** * @tc.steps: step2. openstore1 in dual tuple sync mode - * @tc.expected: step2. it should be activity finally + * @tc.expected: step2. it should be activated finally */ OpenStore1(true); /** @@ -913,4 +913,61 @@ HWTEST_F(DistributedDBRelationalMultiUserTest, RdbMultiUser011, TestSize.Level1) EXPECT_EQ(rdbDeletegatePtr, nullptr); CloseStore(); } +} + +/** + * @tc.name: multi user 012 + * @tc.desc: test dont check sync active when open store with normal store + * @tc.type: FUNC + * @tc.require: AR000GK58G + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBRelationalMultiUserTest, RdbMultiUser012, TestSize.Level1) +{ + uint32_t callCount = 0u; + /** + * @tc.steps: step1. set SyncActivationCheckCallback and record call count + */ + RuntimeConfig::SetSyncActivationCheckCallback([&callCount] (const std::string &userId, const std::string &appId, + const std::string &storeId) -> bool { + callCount++; + return true; + }); + /** + * @tc.steps: step2. openStore in no dual tuple sync mode + * @tc.expected: step2. it should be activated finally, and callCount should be zero + */ + OpenStore1(false); + EXPECT_EQ(callCount, 0u); + CloseStore(); +} + +/** + * @tc.name: multi user 013 + * @tc.desc: test dont check sync active when open store with normal store + * @tc.type: FUNC + * @tc.require: AR000GK58G + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBRelationalMultiUserTest, RdbMultiUser013, TestSize.Level1) +{ + uint32_t callCount = 0u; + /** + * @tc.steps: step1. set SyncActivationCheckCallback and record call count + */ + RuntimeConfig::SetSyncActivationCheckCallback([&callCount] (const std::string &userId, const std::string &appId, + const std::string &storeId) -> bool { + callCount++; + return true; + }); + /** + * @tc.steps: step2. openStore in dual tuple sync mode + * @tc.expected: step2. it should not be activated finally, and callCount should be 2 + */ + OpenStore1(true); + EXPECT_EQ(callCount, 2u); + callCount = 0u; + EXPECT_EQ(g_rdbDelegatePtr1->RemoveDeviceData("DEVICE"), OK); + EXPECT_EQ(callCount, 0u); + CloseStore(); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp index 1ab5d57cc6009a585589dc315aa80d14cdc4ff8f..6ba4b686e779566a7594cb2185a92b3f584635f4 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_relational_ver_p2p_sync_test.cpp @@ -1082,6 +1082,7 @@ HWTEST_F(DistributedDBRelationalVerP2PSyncTest, NormalSync008, TestSize.Level0) std::vector targetData; g_deviceB->GetAllSyncData(g_tableName, targetData); ASSERT_EQ(targetData.size(), 0u); + EXPECT_EQ(sqlite3_close_v2(db), SQLITE_OK); } /** @@ -1204,94 +1205,6 @@ HWTEST_F(DistributedDBRelationalVerP2PSyncTest, AutoLaunchSync001, TestSize.Leve EXPECT_EQ(currentStatus, AutoLaunchStatus::WRITE_CLOSED); } -/** -* @tc.name: AutoLaunchSyncAfterRekey_001 -* @tc.desc: Test auto launch sync ok after rekey. -* @tc.type: FUNC -* @tc.require: AR000H68LL -* @tc.author: lidongwei -*/ -#ifndef OMIT_ENCRYPT -HWTEST_F(DistributedDBRelationalVerP2PSyncTest, AutoLaunchSyncAfterRekey_001, TestSize.Level3) -{ - /** - * @tc.steps: step1. open rdb store, create distribute table and insert data - */ - std::map dataMap; - PrepareVirtualEnvironment(dataMap, {g_deviceB}); - - /** - * @tc.steps: step2. set auto launch callBack - */ - AutoLaunchParam encryptedParam { USER_ID, APP_ID, STORE_ID_1, AutoLaunchOption {}, nullptr, g_dbDir }; - encryptedParam.option.isEncryptedDb = true; - encryptedParam.option.cipher = CipherType::DEFAULT; - encryptedParam.option.passwd = g_correctPasswd; - encryptedParam.option.iterateTimes = DEFAULT_ITER; - AutoLaunchRequestCallback callback = [&encryptedParam](const std::string &identifier, AutoLaunchParam ¶m) { - if (g_id != identifier) { - return false; - } - param = encryptedParam; - return true; - }; - g_mgr.SetAutoLaunchRequestCallback(callback); - /** - * @tc.steps: step3. close store ensure communicator has closed - */ - g_mgr.CloseStore(g_rdbDelegatePtr); - g_rdbDelegatePtr = nullptr; - /** - * @tc.steps: step4. RunCommunicatorLackCallback to autolaunch store - */ - LabelType labelType(g_id.begin(), g_id.end()); - g_communicatorAggregator->RunCommunicatorLackCallback(labelType); - std::this_thread::sleep_for(std::chrono::seconds(1)); - - /** - * @tc.steps: step5. Rekey - */ - sqlite3 *db = nullptr; - EXPECT_EQ(GetDB(db), SQLITE_OK); - std::thread t1([&db] { - std::string sql = "PARGMA rekey=" + REKEY_KEY; - EXPECT_EQ(sqlite3_rekey(db, REKEY_KEY.data(), REKEY_KEY.size()), SQLITE_OK); - }); - t1.join(); - g_isAfterRekey = true; - - /** - * @tc.steps: step6. Call sync expect sync failed - */ - Query query = Query::Select(g_tableName); - EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); - size_t count = 0; - GetCount(db, "SELECT count(*) FROM sqlite_master WHERE name='" + GetDeviceTableName(g_tableName) + "';", count); - EXPECT_EQ(count, 0u); - - /** - * @tc.steps: step7. Set callback. - */ - encryptedParam.option.passwd = g_rekeyPasswd; - g_mgr.SetAutoLaunchRequestCallback(callback); - g_communicatorAggregator->RunCommunicatorLackCallback(labelType); - std::this_thread::sleep_for(std::chrono::seconds(2)); - - /** - * @tc.steps: step8. Call sync expect sync success - */ - EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); - GetCount(db, "SELECT count(*) FROM sqlite_master WHERE name='" + GetDeviceTableName(g_tableName) + "';", count); - EXPECT_EQ(count, 1u); - GetSyncData(db, dataMap, g_tableName, g_fieldInfoList); - EXPECT_EQ(dataMap.size(), 3u); - OpenStore(); - std::this_thread::sleep_for(std::chrono::minutes(1)); - sqlite3_close(db); - db = nullptr; -} -#endif - /** * @tc.name: AutoLaunchSync 002 * @tc.desc: Test rdb autoLaunch failed when callback return false. @@ -2381,4 +2294,164 @@ HWTEST_F(DistributedDBRelationalVerP2PSyncTest, EncryptedAlgoUpgrade001, TestSiz g_deviceB->GenericVirtualDevice::Sync(DistributedDB::SYNC_MODE_PULL_ONLY, query, true); CheckVirtualData(dataMap); } + +#ifndef OMIT_ENCRYPT +/** +* @tc.name: AutoLaunchSyncAfterRekey_001 +* @tc.desc: Test auto launch sync ok after rekey. +* @tc.type: FUNC +* @tc.require: AR000H68LL +* @tc.author: lidongwei +*/ +HWTEST_F(DistributedDBRelationalVerP2PSyncTest, AutoLaunchSyncAfterRekey_001, TestSize.Level3) +{ + /** + * @tc.steps: step1. open rdb store, create distribute table and insert data + */ + std::map dataMap; + PrepareVirtualEnvironment(dataMap, {g_deviceB}); + + /** + * @tc.steps: step2. set auto launch callBack + */ + AutoLaunchParam encryptedParam { USER_ID, APP_ID, STORE_ID_1, AutoLaunchOption {}, nullptr, g_dbDir }; + encryptedParam.option.isEncryptedDb = true; + encryptedParam.option.cipher = CipherType::DEFAULT; + encryptedParam.option.passwd = g_correctPasswd; + encryptedParam.option.iterateTimes = DEFAULT_ITER; + AutoLaunchRequestCallback callback = [&encryptedParam](const std::string &identifier, AutoLaunchParam ¶m) { + if (g_id != identifier) { + return false; + } + param = encryptedParam; + return true; + }; + g_mgr.SetAutoLaunchRequestCallback(callback); + /** + * @tc.steps: step3. close store ensure communicator has closed + */ + g_mgr.CloseStore(g_rdbDelegatePtr); + g_rdbDelegatePtr = nullptr; + /** + * @tc.steps: step4. RunCommunicatorLackCallback to autolaunch store + */ + LabelType labelType(g_id.begin(), g_id.end()); + g_communicatorAggregator->RunCommunicatorLackCallback(labelType); + std::this_thread::sleep_for(std::chrono::seconds(1)); + + /** + * @tc.steps: step5. Rekey + */ + sqlite3 *db = nullptr; + EXPECT_EQ(GetDB(db), SQLITE_OK); + std::thread t1([&db] { + std::string sql = "PARGMA rekey=" + REKEY_KEY; + EXPECT_EQ(sqlite3_rekey(db, REKEY_KEY.data(), REKEY_KEY.size()), SQLITE_OK); + }); + t1.join(); + g_isAfterRekey = true; + + /** + * @tc.steps: step6. Call sync expect sync failed + */ + Query query = Query::Select(g_tableName); + EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); + size_t count = 0; + GetCount(db, "SELECT count(*) FROM sqlite_master WHERE name='" + GetDeviceTableName(g_tableName) + "';", count); + EXPECT_EQ(count, 0u); + + /** + * @tc.steps: step7. Set callback. + */ + encryptedParam.option.passwd = g_rekeyPasswd; + g_mgr.SetAutoLaunchRequestCallback(callback); + g_communicatorAggregator->RunCommunicatorLackCallback(labelType); + std::this_thread::sleep_for(std::chrono::seconds(2)); + + /** + * @tc.steps: step8. Call sync expect sync success + */ + EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); + GetCount(db, "SELECT count(*) FROM sqlite_master WHERE name='" + GetDeviceTableName(g_tableName) + "';", count); + EXPECT_EQ(count, 1u); + GetSyncData(db, dataMap, g_tableName, g_fieldInfoList); + EXPECT_EQ(dataMap.size(), 3u); + OpenStore(); + std::this_thread::sleep_for(std::chrono::minutes(1)); + sqlite3_close(db); + db = nullptr; +} + +/** +* @tc.name: AutoLaunchSyncAfterRekey_002 +* @tc.desc: Test auto launch close check after rekey. +* @tc.type: FUNC +* @tc.require: AR000H68LL +* @tc.author: zhangqiquan +*/ +HWTEST_F(DistributedDBRelationalVerP2PSyncTest, AutoLaunchSyncAfterRekey_002, TestSize.Level3) +{ + /** + * @tc.steps: step1. open rdb store, create distribute table and insert data + */ + std::map dataMap; + PrepareVirtualEnvironment(dataMap, {g_deviceB}); + /** + * @tc.steps: step2. set auto launch callBack + */ + AutoLaunchParam encryptedParam { USER_ID, APP_ID, STORE_ID_1, AutoLaunchOption {}, nullptr, g_dbDir }; + encryptedParam.option.isEncryptedDb = true; + encryptedParam.option.cipher = CipherType::DEFAULT; + encryptedParam.option.passwd = g_correctPasswd; + encryptedParam.option.iterateTimes = DEFAULT_ITER; + AutoLaunchRequestCallback callback = [&encryptedParam](const std::string &identifier, AutoLaunchParam ¶m) { + param = encryptedParam; + return true; + }; + RelationalStoreManager::SetAutoLaunchRequestCallback(callback); + /** + * @tc.steps: step3. close store ensure communicator has closed + */ + g_mgr.CloseStore(g_rdbDelegatePtr); + g_rdbDelegatePtr = nullptr; + /** + * @tc.steps: step4. RunCommunicatorLackCallback to autolaunch store + */ + LabelType labelType(g_id.begin(), g_id.end()); + g_communicatorAggregator->RunCommunicatorLackCallback(labelType); + std::this_thread::sleep_for(std::chrono::seconds(2)); // wait 2s for auto launch + /** + * @tc.steps: step5. Rekey + */ + sqlite3 *db = nullptr; + EXPECT_EQ(GetDB(db), SQLITE_OK); + std::string sql = "PARGMA rekey=" + REKEY_KEY; + EXPECT_EQ(sqlite3_rekey(db, REKEY_KEY.data(), REKEY_KEY.size()), SQLITE_OK); + g_isAfterRekey = true; + + RelationalDBProperties properties; + properties.SetStringProp(DBProperties::USER_ID, USER_ID); + properties.SetStringProp(DBProperties::APP_ID, APP_ID); + properties.SetStringProp(DBProperties::STORE_ID, STORE_ID_1); + const string &id = RelationalStoreManager::GetRelationalStoreIdentifier(USER_ID, APP_ID, STORE_ID_1); + properties.SetStringProp(DBProperties::IDENTIFIER_DATA, id); + RuntimeContext::GetInstance()->CloseAutoLaunchConnection(DBType::DB_RELATION, properties); + + encryptedParam.option.passwd = g_rekeyPasswd; + RelationalStoreManager::SetAutoLaunchRequestCallback(callback); + g_communicatorAggregator->RunCommunicatorLackCallback(labelType); + std::this_thread::sleep_for(std::chrono::seconds(2)); // wait 2s for auto launch + + Query query = Query::Select(g_tableName); + EXPECT_EQ(g_deviceB->GenericVirtualDevice::Sync(SYNC_MODE_PUSH_ONLY, query, true), E_OK); + size_t count = 0; + GetCount(db, "SELECT count(*) FROM sqlite_master WHERE name='" + GetDeviceTableName(g_tableName) + "';", count); + EXPECT_EQ(count, 0u); + + OpenStore(); + std::this_thread::sleep_for(std::chrono::minutes(1)); + sqlite3_close(db); + db = nullptr; +} +#endif #endif \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp index 515150a2a4fae97d126a1beb9494f770af15475c..3676e58e5fc1807252e6e577d0cb73287df52364 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_multi_user_test.cpp @@ -795,7 +795,7 @@ HWTEST_F(DistributedDBSingleVerMultiUserTest, MultiUser011, TestSize.Level1) }); /** * @tc.steps: step2. openstore1 in dual tuple sync mode - * @tc.expected: step2. it should be activity finally + * @tc.expected: step2. it should be activated finally */ OpenStore1(true); /** @@ -843,4 +843,61 @@ HWTEST_F(DistributedDBSingleVerMultiUserTest, MultiUser012, TestSize.Level1) std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_3_SECONDS)); subThread.join(); CloseStore(); +} + +/** + * @tc.name: MultiUser013 + * @tc.desc: test dont check sync active when open store with normal store + * @tc.type: FUNC + * @tc.require: AR000E8S2T + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBSingleVerMultiUserTest, MultiUser013, TestSize.Level1) +{ + uint32_t callCount = 0u; + /** + * @tc.steps: step1. set SyncActivationCheckCallback and record call count + */ + KvStoreDelegateManager::SetSyncActivationCheckCallback( + [&callCount] (const std::string &userId, const std::string &appId, const std::string &storeId) -> bool { + callCount++; + return true; + }); + /** + * @tc.steps: step2. openStore in no dual tuple sync mode + * @tc.expected: step2. it should be activated finally, and callCount should be zero + */ + OpenStore1(false); + EXPECT_EQ(callCount, 0u); + CloseStore(); +} + +/** + * @tc.name: MultiUser014 + * @tc.desc: test active callback call count + * @tc.type: FUNC + * @tc.require: AR000E8S2T + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBSingleVerMultiUserTest, MultiUser014, TestSize.Level1) +{ + uint32_t callCount = 0u; + /** + * @tc.steps: step1. set SyncActivationCheckCallback and record call count + */ + KvStoreDelegateManager::SetSyncActivationCheckCallback( + [&callCount] (const std::string &userId, const std::string &appId, const std::string &storeId) -> bool { + callCount++; + return false; + }); + /** + * @tc.steps: step2. openStore in dual tuple sync mode + * @tc.expected: step2. it should not be activated finally, and callCount should be 2 + */ + OpenStore1(true); + EXPECT_EQ(callCount, 2u); // 2 is call count + callCount = 0u; + EXPECT_EQ(g_kvDelegatePtr1->RemoveDeviceData(), OK); + EXPECT_EQ(callCount, 0u); + CloseStore(); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_complex_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_complex_sync_test.cpp index dfa5b3c64e1ab1e0b97ddb63dfa896941ec1b6eb..e8887801c435d5081b76ab700245aebfbee7bac5 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_complex_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_complex_sync_test.cpp @@ -23,6 +23,7 @@ #include "distributeddb_tools_unit_test.h" #include "kv_store_nb_delegate.h" #include "kv_virtual_device.h" +#include "mock_sync_task_context.h" #include "platform_specific.h" #include "single_ver_data_sync.h" #include "single_ver_kv_sync_task_context.h" @@ -125,6 +126,58 @@ namespace { EXPECT_TRUE(resultvalue == value); } } + + void DataSync005() + { + ASSERT_NE(g_communicatorAggregator, nullptr); + SingleVerDataSync *dataSync = new (std::nothrow) SingleVerDataSync(); + ASSERT_TRUE(dataSync != nullptr); + dataSync->SendSaveDataNotifyPacket(nullptr, 0, 0, 0, TIME_SYNC_MESSAGE); + EXPECT_EQ(g_communicatorAggregator->GetOnlineDevices().size(), 3u); // 3 online dev + delete dataSync; + } + + void DataSync008() + { + SingleVerDataSync *dataSync = new (std::nothrow) SingleVerDataSync(); + ASSERT_TRUE(dataSync != nullptr); + auto context = new (std::nothrow) MockSyncTaskContext(); + dataSync->PutDataMsg(nullptr); + bool isNeedHandle = false; + bool isContinue = false; + EXPECT_EQ(dataSync->MoveNextDataMsg(context, isNeedHandle, isContinue), nullptr); + EXPECT_EQ(isNeedHandle, false); + EXPECT_EQ(isContinue, false); + delete dataSync; + delete context; + } + + void ReSetWaterDogTest001() + { + /** + * @tc.steps: step1. put 10 key/value + * @tc.expected: step1, put return OK. + */ + for (int i = 0; i < 5; i++) { // put 5 key + Key key = DistributedDBToolsUnitTest::GetRandPrefixKey({'a', 'b'}, 1024); // rand num 1024 for test + Value value; + DistributedDBToolsUnitTest::GetRandomKeyValue(value, 10 * 50 * 1024u); // 10 * 50 * 1024 = 500k + EXPECT_EQ(g_kvDelegatePtr->Put(key, value), OK); + } + /** + * @tc.steps: step2. SetDeviceMtuSize + * @tc.expected: step2, return OK. + */ + g_communicatorAggregator->SetDeviceMtuSize(DEVICE_A, 50 * 1024u); // 50 * 1024u = 50k + g_communicatorAggregator->SetDeviceMtuSize(DEVICE_B, 50 * 1024u); // 50 * 1024u = 50k + /** + * @tc.steps: step3. deviceA,deviceB sync to each other at same time + * @tc.expected: step3. sync should return OK. + */ + EXPECT_EQ(g_deviceB->Sync(DistributedDB::SYNC_MODE_PULL_ONLY, true), E_OK); + g_communicatorAggregator->SetDeviceMtuSize(DEVICE_A, 5 * 1024u * 1024u); // 5 * 1024u * 1024u = 5m + g_communicatorAggregator->SetDeviceMtuSize(DEVICE_B, 5 * 1024u * 1024u); // 5 * 1024u * 1024u = 5m + } } class DistributedDBSingleVerP2PComplexSyncTest : public testing::Test { @@ -977,10 +1030,7 @@ HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, DataSync004, TestSize.Level1) */ HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, DataSync005, TestSize.Level1) { - SingleVerDataSync *dataSync = new (std::nothrow) SingleVerDataSync(); - ASSERT_TRUE(dataSync != nullptr); - dataSync->SendSaveDataNotifyPacket(nullptr, 0, 0, 0, TIME_SYNC_MESSAGE); - delete dataSync; + ASSERT_NO_FATAL_FAILURE(DataSync005()); } /** @@ -1040,10 +1090,7 @@ HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, DataSync007, TestSize.Level1) */ HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, DataSync008, TestSize.Level1) { - SingleVerDataSync *dataSync = new (std::nothrow) SingleVerDataSync(); - ASSERT_TRUE(dataSync != nullptr); - dataSync->PutDataMsg(nullptr); - delete dataSync; + ASSERT_NO_FATAL_FAILURE(DataSync008()); } /** @@ -1240,37 +1287,68 @@ HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, SyncRetry004, TestSize.Level3 } /** - * @tc.name: ReSetWatchDogTest001 - * @tc.desc: trigger resetWatchDog while pull + * @tc.name: SyncRetry005 + * @tc.desc: use sync retry sync use pull by compress * @tc.type: FUNC * @tc.require: AR000CKRTD AR000CQE0E - * @tc.author: zhuwentao + * @tc.author: zhangqiquan */ -HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, ReSetWaterDogTest001, TestSize.Level3) +HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, SyncRetry005, TestSize.Level3) { + if (g_kvDelegatePtr != nullptr) { + ASSERT_EQ(g_mgr.CloseKvStore(g_kvDelegatePtr), OK); + g_kvDelegatePtr = nullptr; + } /** - * @tc.steps: step1. put 10 key/value - * @tc.expected: step1, put return OK. + * @tc.steps: step1. open db use Compress + * @tc.expected: step1, Pragma return OK. */ - for (int i = 0; i < 5; i++) { - Key key = DistributedDBToolsUnitTest::GetRandPrefixKey({'a', 'b'}, 1024); // rand num 1024 for test - Value value; - DistributedDBToolsUnitTest::GetRandomKeyValue(value, 10 * 50 * 1024u); - EXPECT_EQ(g_kvDelegatePtr->Put(key, value), OK); - } + KvStoreNbDelegate::Option option; + option.isNeedCompressOnSync = true; + g_mgr.GetKvStore(STORE_ID, option, g_kvDelegateCallback); + ASSERT_TRUE(g_kvDelegateStatus == OK); + ASSERT_TRUE(g_kvDelegatePtr != nullptr); + + g_communicatorAggregator->SetDropMessageTypeByDevice(DEVICE_B, DATA_SYNC_MESSAGE); + std::vector devices; + devices.push_back(g_deviceB->GetDeviceId()); + + /** + * @tc.steps: step2. set sync retry + * @tc.expected: step2, Pragma return OK. + */ + int pragmaData = 1; + PragmaData input = static_cast(&pragmaData); + EXPECT_TRUE(g_kvDelegatePtr->Pragma(SET_SYNC_RETRY, input) == OK); + /** - * @tc.steps: step1. SetDeviceMtuSize - * @tc.expected: step1, return OK. + * @tc.steps: step3. deviceA call sync and wait + * @tc.expected: step3. sync should return OK. */ - g_communicatorAggregator->SetDeviceMtuSize(DEVICE_A, 50 * 1024u); // 4k - g_communicatorAggregator->SetDeviceMtuSize(DEVICE_B, 50 * 1024u); // 4k + std::map result; + ASSERT_TRUE(g_tool.SyncTest(g_kvDelegatePtr, devices, SYNC_MODE_PULL_ONLY, result) == OK); + /** - * @tc.steps: step2. deviceA,deviceB sync to each other at same time - * @tc.expected: step2. sync should return OK. + * @tc.expected: step4. onComplete should be called, and status is time_out */ - g_deviceB->Sync(DistributedDB::SYNC_MODE_PULL_ONLY, true); - g_communicatorAggregator->SetDeviceMtuSize(DEVICE_A, 5 * 1024u * 1024u); // 4k - g_communicatorAggregator->SetDeviceMtuSize(DEVICE_B, 5 * 1024u * 1024u); // 4k + ASSERT_TRUE(result.size() == devices.size()); + for (const auto &pair : result) { + LOGD("dev %s, status %d", pair.first.c_str(), pair.second); + EXPECT_EQ(pair.second, OK); + } + g_communicatorAggregator->SetDropMessageTypeByDevice(DEVICE_B, UNKNOW_MESSAGE); +} + +/** + * @tc.name: ReSetWatchDogTest001 + * @tc.desc: trigger resetWatchDog while pull + * @tc.type: FUNC + * @tc.require: AR000CKRTD AR000CQE0E + * @tc.author: zhuwentao + */ +HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, ReSetWaterDogTest001, TestSize.Level3) +{ + ASSERT_NO_FATAL_FAILURE(ReSetWaterDogTest001()); } /** @@ -1865,4 +1943,54 @@ HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, InterceptDataFail001, TestSiz } VirtualDataItem item; EXPECT_EQ(g_deviceB->GetData(key, item), -E_NOT_FOUND); +} + +/** + * @tc.name: UpdateKey001 + * @tc.desc: test update key can effect local data and sync data, without delete data + * @tc.type: FUNC + * @tc.require: + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBSingleVerP2PComplexSyncTest, UpdateKey001, TestSize.Level1) +{ + /** + * @tc.steps: step1. device A set sync data (k1, v1) local data (k2, v2) (k3, v3) and delete (k4, v4) + * @tc.expected: step1. put data return ok + */ + Key k1 = {'k', '1'}; + Value v1 = {'v', '1'}; + g_deviceB->PutData(k1, v1, 1, 0); + ASSERT_EQ(g_deviceB->Sync(SyncMode::SYNC_MODE_PUSH_ONLY, true), E_OK); + Value actualValue; + EXPECT_EQ(g_kvDelegatePtr->Get(k1, actualValue), OK); + EXPECT_EQ(v1, actualValue); + Key k2 = {'k', '2'}; + Value v2 = {'v', '2'}; + Key k3 = {'k', '3'}; + Value v3 = {'v', '3'}; + Key k4 = {'k', '4'}; + Value v4 = {'v', '4'}; + EXPECT_EQ(g_kvDelegatePtr->Put(k2, v2), OK); + EXPECT_EQ(g_kvDelegatePtr->Put(k3, v3), OK); + EXPECT_EQ(g_kvDelegatePtr->Put(k4, v4), OK); + EXPECT_EQ(g_kvDelegatePtr->Delete(k4), OK); + /** + * @tc.steps: step2. device A update key and set + * @tc.expected: step2. put data return ok + */ + DBStatus status = g_kvDelegatePtr->UpdateKey([](const Key &originKey, Key &newKey) { + newKey = originKey; + newKey.push_back('0'); + }); + EXPECT_EQ(status, OK); + k1.push_back('0'); + k2.push_back('0'); + k3.push_back('0'); + EXPECT_EQ(g_kvDelegatePtr->Get(k1, actualValue), OK); + EXPECT_EQ(v1, actualValue); + EXPECT_EQ(g_kvDelegatePtr->Get(k2, actualValue), OK); + EXPECT_EQ(v2, actualValue); + EXPECT_EQ(g_kvDelegatePtr->Get(k3, actualValue), OK); + EXPECT_EQ(v3, actualValue); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_permission_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_permission_sync_test.cpp index 8c498b1db036a229b55411ba7c29c2afda06af78..d9810710cabca4d728086956f22ce31d267d9a20 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_permission_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_permission_sync_test.cpp @@ -771,4 +771,52 @@ HWTEST_F(DistributedDBSingleVerP2PPermissionSyncTest, PermissionCheck009, TestSi } PermissionCheckCallbackV2 nullCallback; EXPECT_EQ(g_mgr.SetPermissionCheckCallback(nullCallback), OK); +} + +/** + * @tc.name: PermissionCheck010 + * @tc.desc: permission check cost lot of time and return false + * @tc.type: FUNC + * @tc.require: AR000D4876 + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBSingleVerP2PPermissionSyncTest, PermissionCheck010, TestSize.Level3) +{ + /** + * @tc.steps: step1. SetPermissionCheckCallback + * @tc.expected: step1. return OK. + */ + int count = 0; + auto permissionCheckCallback = [&count] (const std::string &userId, const std::string &appId, + const std::string &storeId, const std::string &deviceId, uint8_t flag) -> bool { + std::this_thread::sleep_for(std::chrono::seconds(1)); + count++; + LOGD("check permission %d", count); + return count > 1; + }; + EXPECT_EQ(g_mgr.SetPermissionCheckCallback(permissionCheckCallback), OK); + /** + * @tc.steps: step2. put (k1, v1) + * @tc.expected: step2. return OK. + */ + Key k1 = {'k', '1'}; + Value v1 = {'v', '1'}; + EXPECT_EQ(g_kvDelegatePtr->Put(k1, v1), OK); + /** + * @tc.steps: step3. sync to DEVICE_B twice + * @tc.expected: step3. return OK. + */ + std::vector devices; + devices.push_back(DEVICE_B); + EXPECT_TRUE(g_kvDelegatePtr->Sync(devices, SYNC_MODE_PUSH_ONLY, nullptr, false) == OK); + EXPECT_TRUE(g_kvDelegatePtr->Sync(devices, SYNC_MODE_PUSH_ONLY, nullptr, true) == OK); + /** + * @tc.steps: step4. (k1, v1) exist in DeviceB + * @tc.expected: step4. get return OK. + */ + VirtualDataItem actualValue; + EXPECT_EQ(g_deviceB->GetData(k1, actualValue), OK); + EXPECT_EQ(v1, actualValue.value); + PermissionCheckCallbackV2 nullCallback = nullptr; + EXPECT_EQ(g_mgr.SetPermissionCheckCallback(nullCallback), OK); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp index 36e4121669ee1aa8e44160643bdaddbdc2aa9cf8..4a928773d3532eb01293bc4996faf87b20a04252 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_query_sync_test.cpp @@ -895,6 +895,78 @@ HWTEST_F(DistributedDBSingleVerP2PQuerySyncTest, GetQueryWaterMark002, TestSize. EXPECT_EQ(w1, w); } +/** + * @tc.name: GetQueryWaterMark 003 + * @tc.desc: check time offset after remove water mark + * @tc.type: FUNC + * @tc.require: + * @tc.author: lianhuix + */ +HWTEST_F(DistributedDBSingleVerP2PQuerySyncTest, GetQueryWaterMark003, TestSize.Level1) +{ + VirtualSingleVerSyncDBInterface storage; + Metadata meta; + + int errCode = meta.Initialize(&storage); + ASSERT_EQ(errCode, E_OK); + + const std::string DEVICE_B = "DEVICE_B"; + TimeOffset offset = 100; // 100: offset + meta.SaveTimeOffset(DEVICE_B, offset); + + WaterMark w1 = 2; // 2: watermark + meta.SavePeerWaterMark(DBCommon::TransferHashString(DEVICE_B), w1, false); + + TimeOffset offsetGot; + meta.GetTimeOffset(DEVICE_B, offsetGot); + EXPECT_EQ(offsetGot, offset); +} + +/** + * @tc.name: GetDeleteWaterMark001 + * @tc.desc: Test metaData save and get deleteWaterMark. + * @tc.type: FUNC + * @tc.require: AR000FN6G9 + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBSingleVerP2PQuerySyncTest, GetDeleteWaterMark001, TestSize.Level1) +{ + VirtualSingleVerSyncDBInterface storage; + Metadata meta; + + /** + * @tc.steps: step1. initialize meta with storage + * @tc.expected: step1. E_OK + */ + int errCode = meta.Initialize(&storage); + ASSERT_EQ(errCode, E_OK); + + /** + * @tc.steps: step2. set and get recv/send delete watermark + * @tc.expected: step2. set E_OK and get water mark is equal with last set + */ + const std::string device = "DEVICE"; + const WaterMark maxWaterMark = 1000u; + std::thread recvThread([&meta, &device, &maxWaterMark]() { + for (WaterMark expectRecv = 0u; expectRecv < maxWaterMark; ++expectRecv) { + EXPECT_EQ(meta.SetRecvDeleteSyncWaterMark(device, expectRecv), E_OK); + WaterMark actualRecv = 0u; + EXPECT_EQ(meta.GetRecvDeleteSyncWaterMark(device, actualRecv), E_OK); + EXPECT_EQ(actualRecv, expectRecv); + } + }); + std::thread sendThread([&meta, &device, &maxWaterMark]() { + for (WaterMark expectSend = 0u; expectSend < maxWaterMark; ++expectSend) { + EXPECT_EQ(meta.SetSendDeleteSyncWaterMark(device, expectSend), E_OK); + WaterMark actualSend = 0u; + EXPECT_EQ(meta.GetSendDeleteSyncWaterMark(device, actualSend), E_OK); + EXPECT_EQ(actualSend, expectSend); + } + }); + recvThread.join(); + sendThread.join(); +} + /** * @tc.name: ClearQueryWaterMark 001 * @tc.desc: Test metaData clear watermark function. @@ -1830,31 +1902,4 @@ HWTEST_F(DistributedDBSingleVerP2PQuerySyncTest, AllPredicateQuerySync004, TestS EXPECT_TRUE(item == value); key.pop_back(); } -} - -/** - * @tc.name: GetQueryWaterMark 003 - * @tc.desc: check time offset after remove water mark - * @tc.type: FUNC - * @tc.require: - * @tc.author: lianhuix - */ -HWTEST_F(DistributedDBSingleVerP2PQuerySyncTest, GetQueryWaterMark003, TestSize.Level1) -{ - VirtualSingleVerSyncDBInterface storage; - Metadata meta; - - int errCode = meta.Initialize(&storage); - ASSERT_EQ(errCode, E_OK); - - const std::string DEVICE_B = "DEVICE_B"; - TimeOffset offset = 100; // 100: offset - meta.SaveTimeOffset(DEVICE_B, offset); - - WaterMark w1 = 2; // 2: watermark - meta.SavePeerWaterMark(DBCommon::TransferHashString(DEVICE_B), w1, false); - - TimeOffset offsetGot; - meta.GetTimeOffset(DEVICE_B, offsetGot); - EXPECT_EQ(offsetGot, offset); -} +} \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_subscribe_sync_test.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_subscribe_sync_test.cpp index cd6eb2ec51fb59adf34028993c4edd1db7dcc8a0..207e1469a4f029a537b68580cb03845da6f20429 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_subscribe_sync_test.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/distributeddb_single_ver_p2p_subscribe_sync_test.cpp @@ -349,7 +349,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, ControlAckTest001, TestSize * @tc.require: AR000FN6G9 * @tc.author: zhuwentao */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager001, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeManager001, TestSize.Level1) { SubscribeManager subManager; std::string device = "device_A"; @@ -420,7 +420,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager001, TestSi * @tc.require: AR000FN6G9 * @tc.author: zhuwentao */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager002, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeManager002, TestSize.Level1) { SubscribeManager subManager; std::string device = "device_A"; @@ -476,7 +476,7 @@ ASSERT_TRUE(subscribeQueryId.size() == 4); * @tc.require: AR000FN6G9 * @tc.author: zhuwentao */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager003, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeManager003, TestSize.Level1) { SubscribeManager subManager; std::string device = "device_"; @@ -526,7 +526,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager003, TestSi * @tc.require: AR000FN6G9 * @tc.author: zhuwentao */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager004, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeManager004, TestSize.Level1) { SubscribeManager subManager; std::string device = "device_"; @@ -577,7 +577,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager004, TestSi * @tc.require: AR000FN6G9 * @tc.author: zhuwentao */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager005, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeManager005, TestSize.Level1) { SubscribeManager subManager; std::vector subscribeQueries; @@ -647,7 +647,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager005, TestSi * @tc.require: * @tc.author: zhangshijie */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager006, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeManager006, TestSize.Level1) { /** * @tc.steps: step1. active a query sync object which is not in local subscribe map @@ -711,7 +711,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeManager006, TestSi * @tc.require: AR000FN6G9 * @tc.author: zhuwentao */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeSync001, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeSync001, TestSize.Level1) { /** * @tc.steps: step1. InitSchemaDb @@ -776,7 +776,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeSync001, TestSize. * @tc.require: AR000FN6G9 * @tc.author: zhuwentao */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeSync002, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeSync002, TestSize.Level1) { /** * @tc.steps: step1. InitSchemaDb @@ -820,7 +820,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeSync002, TestSize. * @tc.require: AR000GOHO7 * @tc.author: lidongwei */ -HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeSync003, TestSize.Level1) +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeSync003, TestSize.Level1) { /** * @tc.steps: step1. InitSchemaDb @@ -829,6 +829,7 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, subscribeSync003, TestSize. InitSubSchemaDb(); std::vector devices; devices.push_back(g_deviceB->GetDeviceId()); + g_deviceB->Online(); /** * @tc.steps: step2. deviceB subscribe inkeys(k2k4) query to deviceA @@ -1165,4 +1166,50 @@ HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeSync012, TestSize. EXPECT_EQ(g_deviceB->GetData(key, item), E_OK); EXPECT_EQ(g_deviceC->GetData(key, item), -E_NOT_FOUND); } +} + +/** + * @tc.name: SubscribeSync014 + * @tc.desc: test device subscribe with put a lot of times + * @tc.type: FUNC + * @tc.require: AR000GOHO7 + * @tc.author: zhangqiquan + */ +HWTEST_F(DistributedDBSingleVerP2PSubscribeSyncTest, SubscribeSync014, TestSize.Level3) +{ + /** + * @tc.steps: step1. InitSchemaDb + */ + LOGI("============step 1============"); + InitSubSchemaDb(); + std::vector devices; + devices.push_back(g_deviceB->GetDeviceId()); + /** + * @tc.steps: step2. deviceB unsubscribe inkeys(k1, key6) and prefix key "k" query to deviceA + */ + LOGI("============step 2============"); + Key key6 { 'k', '6' }; + Query query = Query::Select(); + g_deviceB->Online(); + g_deviceB->Subscribe(QuerySyncObject(query), true, 1); + /** + * @tc.steps: step3. deviceA put a lot of time + * @tc.expected: step3 put performance was not effected by subscribe + */ + LOGI("============step 4============"); + std::vector dataKeys; + const uint64_t PUT_LIMIT_30S = 30 * 1000000; // 30s = 30 * 1000000us + LOGD("BEGIN PUT"); + for (uint8_t i = 0u; i < 10u; ++i) { // loop 10 times + Key key = { i }; + dataKeys.push_back(key); + uint64_t curTime = 0; + uint64_t lastTime = 0; + EXPECT_EQ(OS::GetCurrentSysTimeInMicrosecond(curTime), E_OK); + lastTime = curTime; + EXPECT_EQ(g_schemaKvDelegatePtr->Put(key, Value(SCHEMA_VALUE1.begin(), SCHEMA_VALUE1.end())), OK); + EXPECT_EQ(OS::GetCurrentSysTimeInMicrosecond(curTime), E_OK); + EXPECT_LE(curTime - lastTime, PUT_LIMIT_30S); + } + LOGD("END PUT"); } \ No newline at end of file diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_remote_executor.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_remote_executor.h index bfab8c9d88781061611c0805aad7e3fdc5f705ec..d8c230bd39b6e5b915e29ced54c63e8d32598fd8 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_remote_executor.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_remote_executor.h @@ -25,9 +25,9 @@ public: MOCK_METHOD1(IsPacketValid, bool(uint32_t)); - void CallResponseFailed(int errCode, uint32_t sessionId, uint32_t sequenceId, const std::string &device) + int CallResponseFailed(int errCode, uint32_t sessionId, uint32_t sequenceId, const std::string &device) { - RemoteExecutor::ResponseFailed(errCode, sessionId, sequenceId, device); + return RemoteExecutor::ResponseFailed(errCode, sessionId, sequenceId, device); } }; } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_sync_task_context.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_sync_task_context.h index 39dbab055e441b9f84aa0479b73839d6388b8763..9cb58cc816e453832f7a77420e17ed8d88a22359 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_sync_task_context.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/mock_sync_task_context.h @@ -92,6 +92,11 @@ public: } return SingleVerKvSyncTaskContext::GetDeviceId(); } + + void SetSyncOperation(SyncOperation *operation) + { + syncOperation_ = operation; + } private: std::function forkGetDeviceIdFunc_; }; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp index d3836d1a247cf0a5d522d7c293e28620a60603b3..31c89841ca4f9c93f37a09936bc3916112ab9b4f 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.cpp @@ -313,4 +313,14 @@ void VirtualCommunicatorAggregator::DelayTimeHandle(uint32_t messageId, const st skipTimes_--; } } + +std::set VirtualCommunicatorAggregator::GetOnlineDevices() +{ + std::lock_guard lock(communicatorsLock_); + std::set onlineDevices; + for (const auto &item: communicators_) { + onlineDevices.insert(item.first); + } + return onlineDevices; +} } // namespace DistributedDB diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h index 1c97716c8e2d67243a02d13eb264d2b657b11cbd..1f77ed02845a6af7013d5b96108d974b14028b57 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_communicator_aggregator.h @@ -81,6 +81,8 @@ public: std::set &delayDevices); void ResetSendDelayInfo(); + std::set GetOnlineDevices(); + ~VirtualCommunicatorAggregator() {}; VirtualCommunicatorAggregator() {}; diff --git a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_single_ver_sync_db_Interface.cpp b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_single_ver_sync_db_Interface.cpp index 778b08f98f0cc000adcba814eedc981d24e8d48a..9ef22110b6b54a3d3d31a8b1ccd73e05628a04b1 100644 --- a/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_single_ver_sync_db_Interface.cpp +++ b/kv_store/frameworks/libs/distributeddb/test/unittest/common/syncer/virtual_single_ver_sync_db_Interface.cpp @@ -138,6 +138,11 @@ int VirtualSingleVerSyncDBInterface::GetSyncDataNext(std::vector &data void VirtualSingleVerSyncDBInterface::ReleaseContinueToken(ContinueToken& continueStmtToken) const { + VirtualContinueToken *token = static_cast(continueStmtToken); + if (token != nullptr) { + delete token; + continueStmtToken = nullptr; + } return; } @@ -553,12 +558,12 @@ bool VirtualSingleVerSyncDBInterface::GetDataInner(Timestamp begin, Timestamp en { bool isFinished = true; for (const auto &data : dbData_) { - if (dataItems.size() >= dataSizeInfo.packetSize) { - LOGD("virtual device dataItem size reach to packetSize=%u", dataSizeInfo.packetSize); - isFinished = false; - break; - } if (data.isLocal) { + if (dataItems.size() >= dataSizeInfo.packetSize) { + LOGD("virtual device dataItem size reach to packetSize=%u", dataSizeInfo.packetSize); + isFinished = false; + break; + } if (data.writeTimestamp >= begin && data.writeTimestamp < end) { dataItems.push_back(data); currentWaterMark = data.writeTimestamp; diff --git a/kv_store/interfaces/innerkits/distributeddata/BUILD.gn b/kv_store/interfaces/innerkits/distributeddata/BUILD.gn index cfc75bdbdef6c77e93571f133eee87f993234eca..a0ee3aa5794253d4086c3561ee24fe1dd3461d0e 100644 --- a/kv_store/interfaces/innerkits/distributeddata/BUILD.gn +++ b/kv_store/interfaces/innerkits/distributeddata/BUILD.gn @@ -42,12 +42,11 @@ config("distributeddatafwk_config") { } config("distributeddatafwk_public_config") { - visibility = [ "//foundation/distributeddatamgr/kv_store:*" ] + visibility = [ ":*" ] include_dirs = [ "include", "../../../frameworks/innerkitsimpl/distributeddatafwk/include", - "//commonlibrary/c_utils/base/include", ] } @@ -99,7 +98,7 @@ external_deps_config = [ "hitrace_native:libhitracechain", "hiviewdfx_hilog_native:libhilog", "huks:libhukssdk", - "ipc:ipc_core", + "ipc:ipc_single", "samgr:samgr_proxy", ] diff --git a/kv_store/interfaces/innerkits/distributeddata/include/blob.h b/kv_store/interfaces/innerkits/distributeddata/include/blob.h index 88d4fff6f23a7320a2de4c1b7251c2debccf6cb5..b7a59494d2b800ead0585137d94ca4f4965ec424 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/blob.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/blob.h @@ -25,26 +25,44 @@ namespace DistributedKv { class Blob { public: + /** + * @brief Constructor. + */ API_EXPORT Blob(); + /** + * @brief Destructor. + */ API_EXPORT ~Blob() = default; /** * @brief Copy constructor for Blob. */ API_EXPORT Blob(const Blob &blob); + + /** + * @brief Operator =. + */ API_EXPORT Blob &operator=(const Blob &blob); /** * @brief Move constructor for Blob. */ API_EXPORT Blob(Blob &&blob); + + /** + * @brief Operator =. + */ API_EXPORT Blob &operator=(Blob &&blob); /** * @brief Construct a Blob use std::string. */ API_EXPORT Blob(const std::string &str); + + /** + * @brief Operator =. + */ API_EXPORT Blob &operator=(const std::string &str); /** @@ -56,6 +74,10 @@ public: * @brief Construct a Blob use char pointer. */ API_EXPORT Blob(const char *str); + + /** + * @brief Operator =. + */ API_EXPORT Blob &operator=(const char *str); /** @@ -73,8 +95,14 @@ public: */ API_EXPORT const std::vector &Data() const; + /** + * @brief Return std::vector &. + */ API_EXPORT operator const std::vector &() const; + /** + * @brief Return std::vector &&. + */ API_EXPORT operator std::vector &&() noexcept; /** @@ -102,6 +130,9 @@ public: */ API_EXPORT uint8_t operator[](size_t n) const; + /** + * @brief Operator ==. + */ API_EXPORT bool operator==(const Blob &) const; /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/change_notification.h b/kv_store/interfaces/innerkits/distributeddata/include/change_notification.h index d4cc84a911f2f6342e26ed97defa0fd5fb88100b..c6bc3df1d50b52fb744365f8b2f8628ec1001102 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/change_notification.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/change_notification.h @@ -34,6 +34,9 @@ public: API_EXPORT ChangeNotification(std::vector &&insertEntries, std::vector &&updateEntries, std::vector &&deleteEntries, const std::string &deviceId, bool isClear); + /** + * @brief Destructor. + */ API_EXPORT ~ChangeNotification(); /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/data_query.h b/kv_store/interfaces/innerkits/distributeddata/include/data_query.h index dc70626ec2fc2ac466f2b28a6edc0045d067532b..5daafcc939c8b3d5c994014b89cb11e97c9bd24a 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/data_query.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/data_query.h @@ -28,8 +28,14 @@ namespace OHOS { namespace DistributedKv { class API_EXPORT DataQuery { public: + /** + * @brief Constructor. + */ DataQuery(); + /** + * @brief Destructor. + */ ~DataQuery() = default; /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/distributed_kv_data_manager.h b/kv_store/interfaces/innerkits/distributeddata/include/distributed_kv_data_manager.h index 016a079afd8ee7181fb8742fb27def6b900f188a..d87a7a2dfb2dded88fcdbf5d496d40b986a0fbec 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/distributed_kv_data_manager.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/distributed_kv_data_manager.h @@ -27,8 +27,14 @@ namespace OHOS { namespace DistributedKv { class API_EXPORT DistributedKvDataManager final { public: + /** + * @brief Constructor. + */ API_EXPORT DistributedKvDataManager(); + /** + * @brief Destructor. + */ API_EXPORT ~DistributedKvDataManager(); /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/kvstore.h b/kv_store/interfaces/innerkits/distributeddata/include/kvstore.h index 420461949bbd40693a5a420ac61eadfb5e626337..0e2e41b531d498a400206c60a6cf543ae0579fa1 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/kvstore.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/kvstore.h @@ -24,12 +24,24 @@ namespace OHOS { namespace DistributedKv { class API_EXPORT KvStore { public: + /** + * @brief Constructor. + */ API_EXPORT KvStore() = default; - // forbidden copy constructor. + /** + * @brief Forbidden copy constructor. + */ KvStore(const KvStore &) = delete; + + /** + * @brief Forbidden copy constructor. + */ KvStore &operator=(const KvStore &) = delete; + /** + * @brief Destructor. + */ API_EXPORT virtual ~KvStore() {} /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/kvstore_observer.h b/kv_store/interfaces/innerkits/distributeddata/include/kvstore_observer.h index 5cec165cdbc47e2e7b16c6a5d8babc2c30a7a1fb..f50754d775d12e114e86d7b8b55d31c9c5b6a7c4 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/kvstore_observer.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/kvstore_observer.h @@ -24,8 +24,14 @@ namespace DistributedKv { // client implement this class to watch kvstore change. class API_EXPORT KvStoreObserver { public: + /** + * @brief Constructor. + */ API_EXPORT KvStoreObserver() = default; + /** + * @brief Destructor. + */ API_EXPORT virtual ~KvStoreObserver() {} /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/kvstore_result_set.h b/kv_store/interfaces/innerkits/distributeddata/include/kvstore_result_set.h index 8965c7e56ee3a296f3e719db48e600beebabff49..42723c94d19bd2ca909c750ede77b8bdc3ade04d 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/kvstore_result_set.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/kvstore_result_set.h @@ -24,6 +24,10 @@ class KvStoreResultSet { public: inline static constexpr int INVALID_COUNT = -ALREADY_CLOSED; inline static constexpr int INVALID_POSITION = -ALREADY_CLOSED; + + /** + * @brief Destructor. + */ API_EXPORT virtual ~KvStoreResultSet() {} /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/kvstore_sync_callback.h b/kv_store/interfaces/innerkits/distributeddata/include/kvstore_sync_callback.h index 5820482a706cb01659a086b5f3ccdc4db515eb3d..3558026efc47994e3395bfb206184689296e7c27 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/kvstore_sync_callback.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/kvstore_sync_callback.h @@ -24,8 +24,14 @@ namespace DistributedKv { // client implement this class to watch kvstore change. class KvStoreSyncCallback { public: + /** + * @brief Constructor. + */ API_EXPORT KvStoreSyncCallback() = default; + /** + * @brief Destructor. + */ API_EXPORT virtual ~KvStoreSyncCallback() {} /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/single_kvstore.h b/kv_store/interfaces/innerkits/distributeddata/include/single_kvstore.h index 3dfa8c008400781efe4de82bd89e6c513a01c407..41d2e31771ffc00893a584d88a79e52383e52e80 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/single_kvstore.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/single_kvstore.h @@ -30,8 +30,14 @@ namespace DistributedKv { // This class provides put, delete, search, sync and subscribe functions of a key-value store. class API_EXPORT SingleKvStore : public virtual KvStore { public: + /** + * @brief Constructor. + */ API_EXPORT SingleKvStore() = default; + /** + * @brief Destructor. + */ API_EXPORT virtual ~SingleKvStore() {} /** diff --git a/kv_store/interfaces/innerkits/distributeddata/include/types.h b/kv_store/interfaces/innerkits/distributeddata/include/types.h index 467ca2ac0361c44cc8677c9ba06aff0a3368081e..345515a93fdce3872d32e36950bbb7e3da414b95 100644 --- a/kv_store/interfaces/innerkits/distributeddata/include/types.h +++ b/kv_store/interfaces/innerkits/distributeddata/include/types.h @@ -66,6 +66,9 @@ struct API_EXPORT AppId { return appId; } + /** + * @brief Check appId. + */ inline bool IsValid() const { if (appId.empty() || appId.size() > MAX_APP_ID_LEN) { @@ -111,11 +114,17 @@ struct API_EXPORT StoreId { return storeId; } + /** + * @brief Operator <. + */ bool operator<(const StoreId &id) const noexcept { return this->storeId < id.storeId; } + /** + * @brief Check storeId. + */ inline bool IsValid() const { if (storeId.empty() || storeId.size() > MAX_STORE_ID_LEN) { @@ -398,25 +407,6 @@ struct Options { return kvStoreType == KvStoreType::DEVICE_COLLABORATION || kvStoreType == KvStoreType::SINGLE_VERSION; } }; - -template -std::vector TransferTypeToByteArray(const T &t) -{ - return std::vector(reinterpret_cast(const_cast(&t)), - reinterpret_cast(const_cast(&t)) + sizeof(T)); -} - -template -T TransferByteArrayToType(const std::vector &blob) -{ - // replace assert to HILOG_FATAL when HILOG_FATAL is ok. - if (blob.size() != sizeof(T) || blob.size() == 0) { - constexpr int tSize = sizeof(T); - uint8_t tContent[tSize] = { 0 }; - return *reinterpret_cast(tContent); - } - return *reinterpret_cast(const_cast(&blob[0])); -} } // namespace DistributedKv } // namespace OHOS #endif // DISTRIBUTED_KVSTORE_TYPES_H diff --git a/kv_store/interfaces/jskits/distributeddata/BUILD.gn b/kv_store/interfaces/jskits/distributeddata/BUILD.gn index b250c263da27b223d09e73a62ee493c3a84843c5..f6bef6beca4d89612c17841da3d08c0988a7434e 100644 --- a/kv_store/interfaces/jskits/distributeddata/BUILD.gn +++ b/kv_store/interfaces/jskits/distributeddata/BUILD.gn @@ -73,6 +73,7 @@ ohos_shared_library("distributeddata") { "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_single", "kv_store:distributeddata_inner", diff --git a/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn b/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn index c61d8ebd6dce91e68a1e6f4b059407912f4d27e9..2755f5f3a521bac8966b0b0e00aeacb6de634428 100644 --- a/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn +++ b/kv_store/interfaces/jskits/distributedkvstore/BUILD.gn @@ -73,6 +73,7 @@ ohos_shared_library("distributedkvstore") { "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hiviewdfx_hilog_native:libhilog", "ipc:ipc_single", "kv_store:distributeddata_inner", diff --git a/kv_store/kvstoremock/distributeddb/BUILD.gn b/kv_store/kvstoremock/distributeddb/BUILD.gn index 51140db01310aeb5db87d0d59264dc83aeffd24d..a35db118ce1e85b37af9a37640d32e169a131c01 100644 --- a/kv_store/kvstoremock/distributeddb/BUILD.gn +++ b/kv_store/kvstoremock/distributeddb/BUILD.gn @@ -79,6 +79,7 @@ config("distrdb_config") { defines += [ "EVLOOP_TIMER_ONLY", "USING_PRINTF_LOGGER", + "OPENSSL_SUPPRESS_DEPRECATED", ] if (use_platform_win) { defines += [ "OS_TYPE_WINDOWS" ] diff --git a/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn b/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn index 7298912cd9d237f44ae553cd7a95f2202a5a98a6..77818a65f3add11f07fb806f915094957937228e 100644 --- a/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn +++ b/kv_store/test/fuzztest/typesutil_fuzzer/BUILD.gn @@ -49,7 +49,7 @@ ohos_fuzztest("TypesUtilFuzzTest") { external_deps = [ "c_utils:utils", "hiviewdfx_hilog_native:libhilog", - "ipc:ipc_core", + "ipc:ipc_single", "kv_store:distributeddata_inner", ] } diff --git a/kv_store/test/unittest/distributeddata/SingleKvStoreDataCallbackJsTest.js b/kv_store/test/unittest/distributeddata/SingleKvStoreDataCallbackJsTest.js index a1cded91276cb90ffcb29a0e264ccaa602265d36..ed175f0cf0b3e2c8028c438dfc729ad6c589477d 100644 --- a/kv_store/test/unittest/distributeddata/SingleKvStoreDataCallbackJsTest.js +++ b/kv_store/test/unittest/distributeddata/SingleKvStoreDataCallbackJsTest.js @@ -1951,27 +1951,6 @@ describe('singleKvStoreCallbackTest', function () { } }) - /** - * @tc.name SingleKvStoreGetSecurityLevelCallbackTest001 - * @tc.desc Test Js Api SingleKvStore.GetSecurityLevel() testcase 001 - * @tc.type: FUNC - * @tc.require: issueNumber - */ - // it('SingleKvStoreGetSecurityLevelCallbackTest001', 0, async function (done) { - // console.info('SingleKvStoreGetSecurityLevelCallbackTest001'); - // try { - // await kvStore.getSecurityLevel(function (err,data) { - // console.info('SingleKvStoreGetSecurityLevelCallbackTest001 getSecurityLevel success'); - // expect(data == factory.SecurityLevel.S2).assertTrue(); - // done(); - // }); - // }catch(e) { - // console.error('SingleKvStoreGetSecurityLevelCallbackTest001 e ' + `, error code is ${e.code}, message is ${e.message}`); - // expect(null).assertFail(); - // done(); - // } - // }) - /** * @tc.name SingleKvStoreGetSecurityLevelCallbackTest002 * @tc.desc Test Js Api SingleKvStore.GetSecurityLevel() testcase 002 diff --git a/kv_store/test/unittest/distributeddata/SingleKvStoreDataPromiseJsTest.js b/kv_store/test/unittest/distributeddata/SingleKvStoreDataPromiseJsTest.js index ed96a3bab31a86d4d8455ba1b1f3de0ec4946bb8..a064c1b141382c540e5b156836f2338929e5951a 100644 --- a/kv_store/test/unittest/distributeddata/SingleKvStoreDataPromiseJsTest.js +++ b/kv_store/test/unittest/distributeddata/SingleKvStoreDataPromiseJsTest.js @@ -2146,29 +2146,6 @@ describe('singleKvStorePromiseTest', function () { done(); }) - /** - * @tc.name SingleKvStoreGetSecurityLevelPromiseTest001 - * @tc.desc Test Js Api SingleKvStoreGetSecurityLevel testcase 001 - * @tc.type: FUNC - * @tc.require: issueNumber - */ - // it('SingleKvStoreGetSecurityLevelPromiseTest001', 0, async function (done) { - // console.info('SingleKvStoreGetSecurityLevelPromiseTest001'); - // try { - // await kvStore.getSecurityLevel().then((data) => { - // console.info('SingleKvStoreGetSecurityLevelPromiseTest001 getSecurityLevel success'); - // expect(data == factory.SecurityLevel.S2).assertTrue(); - // }).catch((err) => { - // console.error('SingleKvStoreGetSecurityLevelPromiseTest001 getSecurityLevel fail ' + `, error code is ${err.code}, message is ${err.message}`); - // expect(null).assertFail(); - // }); - // }catch(e) { - // console.error('SingleKvStoreGetSecurityLevelPromiseTest001 e ' + `, error code is ${e.code}, message is ${e.message}`); - // expect(null).assertFail(); - // } - // done(); - // }) - /** * @tc.name SingleKvStoreGetSecurityLevelPromiseTest002 * @tc.desc Test Js Api SingleKvStoreGetSecurityLevel testcase 002 diff --git a/mock/include/CMakeLists.txt b/mock/include/CMakeLists.txt index efa79ace793c0602b782b7499820c6d635d6c36d..4041c7a0a6200e9d304ef1b5a477609ed6138115 100644 --- a/mock/include/CMakeLists.txt +++ b/mock/include/CMakeLists.txt @@ -101,7 +101,7 @@ include_directories(${MOCK_DIR}/innerkits/napi/ace_napi/include/napi) include_directories(${MOCK_DIR}/innerkits/device_profile_core/distributed_device_profile_client/include) include_directories(${MOCK_DIR}/innerkits/hiview/libfaultlogger/include) include_directories(${MOCK_DIR}/innerkits/syscap_codec/syscap_interface_shared/include) -include_directories(${MOCK_DIR}/innerkits/ipc/ipc_single/include) +#include_directories(${MOCK_DIR}/innerkits/ipc/ipc_single/include) include_directories(${MOCK_DIR}/innerkits/ipc/ipc_core/include) include_directories(${MOCK_DIR}/innerkits/ipc/libdbinder/include) include_directories(${MOCK_DIR}/innerkits/i18n/zone_util/include) diff --git a/mock/innerkits/ability_runtime/runtime/include/js_runtime.h b/mock/innerkits/ability_runtime/runtime/include/js_runtime.h index 00686247d39f75bc788e5e8050913718d98f06d6..2127c171da053974cf9db17218c68e23eb8d3f15 100644 --- a/mock/innerkits/ability_runtime/runtime/include/js_runtime.h +++ b/mock/innerkits/ability_runtime/runtime/include/js_runtime.h @@ -50,18 +50,32 @@ public: return Language::JS; } - std::unique_ptr LoadModule( - const std::string& moduleName, const std::string& modulePath, bool esmodule = false); + std::unique_ptr LoadModule(const std::string& moduleName, const std::string& modulePath, + const std::string& hapPath, bool esmodule = false, bool useCommonChunk = false); std::unique_ptr LoadSystemModule( const std::string& moduleName, NativeValue* const* argv = nullptr, size_t argc = 0); void PostTask(const std::function& task, const std::string& name, int64_t delayTime); void RemoveTask(const std::string& name); void DumpHeapSnapshot(bool isPrivate) override; - std::string BuildJsStackTrace() override; +// bool BuildJsStackInfoList(uint32_t tid, std::vector& jsFrames) override; void NotifyApplicationState(bool isBackground) override; + bool RunSandboxScript(const std::string& path, const std::string& hapPath); + bool RunScript(const std::string& path, const std::string& hapPath, bool useCommonChunk = false); - bool RunSandboxScript(const std::string& path); - virtual bool RunScript(const std::string& path) = 0; + bool LoadScript(const std::string& path, std::vector* buffer = nullptr, bool isBundle = false); + + NativeEngine* GetNativeEnginePointer() const; + + void UpdateModuleNameAndAssetPath(const std::string& moduleName); + static bool GetFileBuffer(const std::string& filePath, std::string& fileFullName, std::vector& buffer); + void StartDebugMode(bool needBreakPoint) override; + void PreloadSystemModule(const std::string &moduleName) override; + void FinishPreload() override; + bool LoadRepairPatch(const std::string &patchFile, const std::string &baseFile) override; + bool NotifyHotReloadPage() override; + bool UnLoadRepairPatch(const std::string &patchFile) override; + void UpdateExtensionType(int32_t extensionType) override; + void RegisterQuickFixQueryFunc(const std::map& moduleAndPath) override; protected: JsRuntime() = default; diff --git a/mock/innerkits/ability_runtime/runtime/include/runtime.h b/mock/innerkits/ability_runtime/runtime/include/runtime.h index cb03c5b103703dba9748a9160913946068dc5119..8280cbbe7b430b4c9a503a76d5fe70ea4e5d3c69 100644 --- a/mock/innerkits/ability_runtime/runtime/include/runtime.h +++ b/mock/innerkits/ability_runtime/runtime/include/runtime.h @@ -17,6 +17,7 @@ #define FOUNDATION_OHOS_ABILITYRUNTIME_RUNTIME_H #include +#include namespace OHOS { namespace AppExecFwk { @@ -45,10 +46,17 @@ public: virtual Language GetLanguage() const = 0; - virtual void StartDebugMode(bool needBreakPoint, int32_t instanceId = 0) = 0; - virtual std::string BuildJsStackTrace() = 0; + virtual void StartDebugMode(bool needBreakPoint) = 0; +// virtual bool BuildJsStackInfoList(uint32_t tid, std::vector& jsFrames) = 0; virtual void DumpHeapSnapshot(bool isPrivate) = 0; virtual void NotifyApplicationState(bool isBackground) = 0; + virtual void PreloadSystemModule(const std::string& moduleName) = 0; + virtual void FinishPreload() = 0; + virtual bool LoadRepairPatch(const std::string& patchFile, const std::string& baseFile) = 0; + virtual bool NotifyHotReloadPage() = 0; + virtual bool UnLoadRepairPatch(const std::string& patchFile) = 0; + virtual void UpdateExtensionType(int32_t extensionType) = 0; + virtual void RegisterQuickFixQueryFunc(const std::map& moduleAndPath) = 0; Runtime(const Runtime&) = delete; Runtime(Runtime&&) = delete; diff --git a/mock/innerkits/appexecfwk_base/include/ability_info.h b/mock/innerkits/appexecfwk_base/include/ability_info.h index 8a31b57d3f5da46feee90b55b79c4179200f761e..81e34796004754b944f0b9a1d5f77eb47c7a31fe 100644 --- a/mock/innerkits/appexecfwk_base/include/ability_info.h +++ b/mock/innerkits/appexecfwk_base/include/ability_info.h @@ -159,7 +159,6 @@ struct CompatibleAbilityInfo : public Parcelable { virtual bool Marshalling(Parcel& parcel) const override; static CompatibleAbilityInfo* Unmarshalling(Parcel& parcel); - void CopyToDest(CompatibleAbilityInfo& dest) const; void ConvertToAbilityInfo(AbilityInfo& abilityInfo) const; }; @@ -182,7 +181,6 @@ struct AbilityInfo : public Parcelable { std::string srcPath; std::string srcLanguage = "js"; std::vector permissions; - bool hapPath; std::string process; std::vector deviceTypes; @@ -215,6 +213,7 @@ struct AbilityInfo : public Parcelable { std::string codePath; // ability main code path with name std::string resourcePath; // resource path for resource init + std::string hapPath; std::string srcEntrance; std::vector metadata; @@ -230,6 +229,8 @@ struct AbilityInfo : public Parcelable { int32_t startWindowBackgroundId; // whether to display in the missions list bool excludeFromMissions = false; + // whether to support recover UI interface + bool recoverable = false; // support windows mode std::vector windowModes; @@ -239,6 +240,9 @@ struct AbilityInfo : public Parcelable { uint32_t minWindowWidth = 0; uint32_t maxWindowHeight = 0; uint32_t minWindowHeight = 0; + // for NAPI, save self query cache + int32_t uid = -1; + CompileMode compileMode = CompileMode::JS_BUNDLE; // unused std::string originalBundleName; @@ -258,7 +262,6 @@ struct AbilityInfo : public Parcelable { AbilitySubType subType = AbilitySubType::UNSPECIFIED; std::string libPath; std::string deviceId; - CompileMode compileMode = CompileMode::JS_BUNDLE; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; diff --git a/mock/innerkits/appexecfwk_base/include/bundle_common_event.h b/mock/innerkits/appexecfwk_base/include/bundle_common_event.h new file mode 100644 index 0000000000000000000000000000000000000000..ec4d5cb6aa21f9510d1177457256d06e427f10d9 --- /dev/null +++ b/mock/innerkits/appexecfwk_base/include/bundle_common_event.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 FOUNDATION_BUNDLEMANAGER_BUNDLE_FRAMEWORK_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_COMMON_EVENT_H +#define FOUNDATION_BUNDLEMANAGER_BUNDLE_FRAMEWORK_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_COMMON_EVENT_H + +#include + +namespace OHOS { +namespace AppExecFwk { +const std::string COMMON_EVENT_SANDBOX_PACKAGE_ADDED = "usual.event.SANDBOX_PACKAGE_ADDED"; + +const std::string COMMON_EVENT_SANDBOX_PACKAGE_REMOVED = "usual.event.SANDBOX_PACKAGE_REMOVED"; + +const std::string COMMON_EVENT_BUNDLE_SCAN_FINISHED = "usual.event.BUNDLE_SCAN_FINISHED"; + +const std::string OVERLAY_ADD_ACTION = "usual.event.OVERLAY_PACKAGE_ADDED"; + +const std::string OVERLAY_CHANGED_ACTION = "usual.event.OVERLAY_PACKAGE_CHANGED"; + +const std::string OVERLAY_STATE_CHANGED = "usual.event.OVERLAY_STATE_CHANGED"; +} // AppExecFwk +} // OHOS +#endif // FOUNDATION_BUNDLEMANAGER_BUNDLE_FRAMEWORK_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_COMMON_EVENT_H \ No newline at end of file diff --git a/mock/innerkits/bundle_framework/appexecfwk_base/include/ability_info.h b/mock/innerkits/bundle_framework/appexecfwk_base/include/ability_info.h index eb1c98d501fb063c02eb2589d87b04599797a04e..23bbbf613f293a411ca2ee8b070c659419c2f0bc 100644 --- a/mock/innerkits/bundle_framework/appexecfwk_base/include/ability_info.h +++ b/mock/innerkits/bundle_framework/appexecfwk_base/include/ability_info.h @@ -33,6 +33,15 @@ enum AbilityInfoFlag { GET_ABILITY_INFO_WITH_DISABLE = 0x00000100, }; +enum class GetAbilityInfoFlag { + GET_ABILITY_INFO_DEFAULT = 0x00000000, + GET_ABILITY_INFO_WITH_PERMISSION = 0x00000001, + GET_ABILITY_INFO_WITH_APPLICATION = 0x00000002, + GET_ABILITY_INFO_WITH_METADATA = 0x00000004, + GET_ABILITY_INFO_WITH_DISABLE = 0x00000008, + GET_ABILITY_INFO_ONLY_SYSTEM_APP = 0x00000010, +}; + enum class AbilityType { UNKNOWN = 0, PAGE, @@ -79,15 +88,9 @@ enum class DisplayOrientation { enum class LaunchMode { SINGLETON = 0, STANDARD, // support more than one instance - SINGLETOP, SPECIFIED, }; -enum class CompileMode { - JS_BUNDLE = 0, - ES_MODULE, -}; - enum class SupportWindowMode { FULLSCREEN = 0, SPLIT, @@ -159,7 +162,6 @@ struct CompatibleAbilityInfo : public Parcelable { virtual bool Marshalling(Parcel& parcel) const override; static CompatibleAbilityInfo* Unmarshalling(Parcel& parcel); - void CopyToDest(CompatibleAbilityInfo& dest) const; void ConvertToAbilityInfo(AbilityInfo& abilityInfo) const; }; @@ -214,6 +216,7 @@ struct AbilityInfo : public Parcelable { std::string codePath; // ability main code path with name std::string resourcePath; // resource path for resource init + std::string hapPath; std::string srcEntrance; std::vector metadata; @@ -229,6 +232,8 @@ struct AbilityInfo : public Parcelable { int32_t startWindowBackgroundId; // whether to display in the missions list bool excludeFromMissions = false; + // whether to support recover UI interface + bool recoverable = false; // support windows mode std::vector windowModes; @@ -238,6 +243,9 @@ struct AbilityInfo : public Parcelable { uint32_t minWindowWidth = 0; uint32_t maxWindowHeight = 0; uint32_t minWindowHeight = 0; + // for NAPI, save self query cache + int32_t uid = -1; + CompileMode compileMode = CompileMode::JS_BUNDLE; // unused std::string originalBundleName; @@ -257,7 +265,6 @@ struct AbilityInfo : public Parcelable { AbilitySubType subType = AbilitySubType::UNSPECIFIED; std::string libPath; std::string deviceId; - CompileMode compileMode = CompileMode::JS_BUNDLE; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; diff --git a/mock/innerkits/bundle_framework/appexecfwk_base/include/appexecfwk_errors.h b/mock/innerkits/bundle_framework/appexecfwk_base/include/appexecfwk_errors.h index 0b6094e723ab7ef80877a6472fb079d909f1b869..586e5a1e2f969873cc33f13e676f659545a65839 100644 --- a/mock/innerkits/bundle_framework/appexecfwk_base/include/appexecfwk_errors.h +++ b/mock/innerkits/bundle_framework/appexecfwk_base/include/appexecfwk_errors.h @@ -38,6 +38,7 @@ enum { ERR_APPEXECFWK_PARCEL_ERROR, ERR_APPEXECFWK_FAILED_SERVICE_DIED, ERR_APPEXECFWK_OPERATION_TIME_OUT, + ERR_APPEXECFWK_SERVICE_INTERNAL_ERROR, }; // Error code for AppMgr @@ -95,6 +96,19 @@ enum { ERR_APPEXECFWK_INSTALL_TYPE_ERROR, ERR_APPEXECFWK_INSTALL_SDK_INCOMPATIBLE, ERR_APPEXECFWK_INSTALL_SO_INCOMPATIBLE, + ERR_APPEXECFWK_INSTALL_AN_INCOMPATIBLE, + ERR_APPEXECFWK_INSTALL_NOT_UNIQUE_DISTRO_MODULE_NAME, + ERR_APPEXECFWK_INSTALL_INCONSISTENT_MODULE_NAME, + ERR_APPEXECFWK_INSTALL_SINGLETON_INCOMPATIBLE, + ERR_APPEXECFWK_INSTALL_DEVICE_TYPE_NOT_SUPPORTED, + ERR_APPEXECFWK_INSTALL_COPY_HAP_FAILED, + ERR_APPEXECFWK_INSTALL_DEPENDENT_MODULE_NOT_EXIST, + ERR_APPEXECFWK_INSTALL_ASAN_ENABLED_NOT_SAME, + ERR_APPEXECFWK_INSTALL_ASAN_NOT_SUPPORT, + ERR_APPEXECFWK_BUNDLE_TYPE_NOT_SAME, + ERR_APPEXECFWK_INSTALL_SHARE_APP_LIBRARY_NOT_ALLOWED, + ERR_APPEXECFWK_INSTALL_COMPATIBLE_POLICY_NOT_SAME, + ERR_APPEXECFWK_INSTALL_FILE_IS_SHARED_LIBRARY, // signature errcode ERR_APPEXECFWK_INSTALL_FAILED_INVALID_SIGNATURE_FILE_PATH = 8519740, @@ -130,6 +144,8 @@ enum { ERR_APPEXECFWK_SANDBOX_INSTALL_NO_SANDBOX_APP_INFO, ERR_APPEXECFWK_SANDBOX_INSTALL_UNKNOWN_INSTALL_TYPE, ERR_APPEXECFWK_SANDBOX_INSTALL_DELETE_APP_INDEX_FAILED, + ERR_APPEXECFWK_SANDBOX_APP_NOT_SUPPORTED, + ERR_APPEXECFWK_SANDBOX_INSTALL_GET_PERMISSIONS_FAILED, // sandbox app query ERR_APPEXECFWK_SANDBOX_QUERY_PARAM_ERROR, @@ -148,7 +164,10 @@ enum { ERR_APPEXECFWK_PARSE_PROFILE_MISSING_PROP, ERR_APPEXECFWK_PARSE_PERMISSION_ERROR, ERR_APPEXECFWK_PARSE_PROFILE_PROP_CHECK_ERROR, + ERR_APPEXECFWK_PARSE_PROFILE_PROP_SIZE_CHECK_ERROR, ERR_APPEXECFWK_PARSE_RPCID_FAILED, + ERR_APPEXECFWK_PARSE_NATIVE_SO_FAILED, + ERR_APPEXECFWK_PARSE_AN_FAILED, ERR_APPEXECFWK_INSTALLD_PARAM_ERROR, ERR_APPEXECFWK_INSTALLD_GET_PROXY_ERROR, @@ -162,6 +181,7 @@ enum { ERR_APPEXECFWK_INSTALLD_MOVE_FILE_FAILED, ERR_APPEXECFWK_INSTALLD_COPY_FILE_FAILED, ERR_APPEXECFWK_INSTALLD_MKDIR_FAILED, + ERR_APPEXECFWK_INSTALLD_PERMISSION_DENIED, ERR_APPEXECFWK_UNINSTALL_SYSTEM_APP_ERROR, ERR_APPEXECFWK_UNINSTALL_KILLING_APP_ERROR, @@ -171,6 +191,9 @@ enum { ERR_APPEXECFWK_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_BUNDLE, ERR_APPEXECFWK_UNINSTALL_MISSING_INSTALLED_MODULE, + ERR_APPEXECFWK_UNINSTALL_SHARE_APP_LIBRARY_IS_NOT_EXIST, + ERR_APPEXECFWK_UNINSTALL_SHARE_APP_LIBRARY_IS_RELIED, + ERR_APPEXECFWK_UNINSTALL_BUNDLE_IS_SHARED_LIBRARY, ERR_APPEXECFWK_FAILED_GET_INSTALLER_PROXY, ERR_APPEXECFWK_FAILED_GET_BUNDLE_INFO, @@ -178,17 +201,142 @@ enum { ERR_APPEXECFWK_FAILED_GET_RESOURCEMANAGER, ERR_APPEXECFWK_FAILED_GET_REMOTE_PROXY, ERR_APPEXECFWK_PERMISSION_DENIED, + ERR_APPEXECFWK_INPUT_WRONG_TYPE_FILE, + ERR_APPEXECFWK_ENCODE_BASE64_FILE_FAILED, ERR_APPEXECFWK_RECOVER_GET_BUNDLEPATH_ERROR = APPEXECFWK_BUNDLEMGR_ERR_OFFSET + 0x0201, // 8520193 ERR_APPEXECFWK_RECOVER_INVALID_BUNDLE_NAME, + ERR_APPEXECFWK_RECOVER_NOT_ALLOWED, ERR_APPEXECFWK_USER_NOT_EXIST = APPEXECFWK_BUNDLEMGR_ERR_OFFSET + 0x0301, - ERR_APPEXECFWK_USER_CREATE_FALIED, - ERR_APPEXECFWK_USER_REMOVE_FALIED, + ERR_APPEXECFWK_USER_CREATE_FAILED, + ERR_APPEXECFWK_USER_REMOVE_FAILED, ERR_APPEXECFWK_USER_NOT_INSTALL_HAP, // error code in prebundle sacn - ERR_APPEXECFWK_PARSE_FILE_FAILED + ERR_APPEXECFWK_PARSE_FILE_FAILED, + + // debug mode + ERR_BUNDLEMANAGER_SET_DEBUG_MODE_INTERNAL_ERROR, + ERR_BUNDLEMANAGER_SET_DEBUG_MODE_PARCEL_ERROR, + ERR_BUNDLEMANAGER_SET_DEBUG_MODE_SEND_REQUEST_ERROR, + ERR_BUNDLEMANAGER_SET_DEBUG_MODE_UID_CHECK_FAILED, + ERR_BUNDLEMANAGER_SET_DEBUG_MODE_INVALID_PARAM, + + // overlay installation errcode + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_INTERNAL_ERROR = 8520600, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_INVALID_BUNDLE_NAME, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_INVALID_MODULE_NAME, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_ERROR_HAP_TYPE, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_ERROR_BUNDLE_TYPE, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_NAME_MISSED, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_MODULE_NAME_MISSED, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_NAME_NOT_SAME, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_INTERNAL_EXTERNAL_OVERLAY_EXISTED_SIMULTANEOUSLY, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_PRIORITY_NOT_SAME, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_INVALID_PRIORITY, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_INCONSISTENT_VERSION_CODE, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_SERVICE_EXCEPTION, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_BUNDLE_NAME_SAME_WITH_TARGET_BUNDLE_NAME, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_NO_SYSTEM_APPLICATION_FOR_EXTERNAL_OVERLAY, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_DIFFERENT_SIGNATURE_CERTIFICATE, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_IS_OVERLAY_BUNDLE, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_MODULE_IS_OVERLAY_MODULE, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_OVERLAY_TYPE_NOT_SAME, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_INVALID_BUNDLE_DIR, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_IS_NOT_STAGE_MODULE, + ERR_BUNDLEMANAGER_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_IS_SERVICE, + + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_PARAM_ERROR, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_MISSING_OVERLAY_BUNDLE, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_MISSING_OVERLAY_MODULE, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_NON_OVERLAY_BUNDLE, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_NON_OVERLAY_MODULE, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_BUNDLE_NOT_INSTALLED_AT_SPECIFIED_USERID, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_TARGET_BUNDLE_NOT_EXISTED, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_TARGET_MODULE_NOT_EXISTED, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_NO_OVERLAY_BUNDLE_INFO, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_NO_OVERLAY_MODULE_INFO, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_PERMISSION_DENIED, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_TARGET_MODULE_IS_OVERLAY_MODULE, + ERR_BUNDLEMANAGER_OVERLAY_QUERY_FAILED_TARGET_BUNDLE_IS_OVERLAY_BUNDLE, + ERR_BUNDLEMANAGER_OVERLAY_SET_OVERLAY_PARAM_ERROR, + + // quick fix errcode + ERR_BUNDLEMANAGER_QUICK_FIX_INTERNAL_ERROR = APPEXECFWK_BUNDLEMGR_ERR_OFFSET + 0x0401, // 8520705 + ERR_BUNDLEMANAGER_QUICK_FIX_PARAM_ERROR, + ERR_BUNDLEMANAGER_QUICK_FIX_PROFILE_PARSE_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_BUNDLE_NAME_NOT_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_NOT_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_NAME_NOT_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_VERSION_CODE_NOT_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_VERSION_NAME_NOT_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_TYPE_NOT_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_MODULE_NAME_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_UNKNOWN_QUICK_FIX_TYPE, + ERR_BUNDLEMANAGER_QUICK_FIX_SO_INCOMPATIBLE, + ERR_BUNDLEMANAGER_QUICK_FIX_BUNDLE_NAME_NOT_EXIST, + ERR_BUNDLEMANAGER_QUICK_FIX_MODULE_NAME_NOT_EXIST, + ERR_BUNDLEMANAGER_QUICK_FIX_SIGNATURE_INFO_NOT_SAME, + ERR_BUNDLEMANAGER_QUICK_FIX_ADD_HQF_FAILED, // 8520720 + ERR_BUNDLEMANAGER_QUICK_FIX_SAVE_APP_QUICK_FIX_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_VERSION_CODE_ERROR, + ERR_BUNDLEMANAGER_QUICK_FIX_EXTRACT_DIFF_FILES_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_APPLY_DIFF_PATCH_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_NO_PATCH_IN_DATABASE, + ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_PATCH_STATUS, + ERR_BUNDLEMANAGER_QUICK_FIX_NOT_EXISTED_BUNDLE_INFO, + ERR_BUNDLEMANAGER_QUICK_FIX_REMOVE_PATCH_PATH_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_CREATE_PATCH_PATH_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_MOVE_PATCH_FILE_FAILED, // 8520730 + ERR_BUNDLEMANAGER_QUICK_FIX_HOT_RELOAD_NOT_SUPPORT_RELEASE_BUNDLE, + ERR_BUNDLEMANAGER_QUICK_FIX_PATCH_ALREADY_EXISTED, + ERR_BUNDLEMANAGER_QUICK_FIX_HOT_RELOAD_ALREADY_EXISTED, + ERR_BUNDLEMANAGER_QUICK_FIX_NO_PATCH_INFO_IN_BUNDLE_INFO, + ERR_BUNDLEMANAGER_QUICK_FIX_OLD_PATCH_OR_HOT_RELOAD_IN_DB, + ERR_BUNDLEMANAGER_QUICK_FIX_SEND_REQUEST_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_REAL_PATH_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_PATH, + ERR_BUNDLEMANAGER_QUICK_FIX_OPEN_SOURCE_FILE_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_CREATE_FD_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_INVALID_TARGET_DIR, + ERR_BUNDLEMANAGER_QUICK_FIX_CREATE_TARGET_DIR_FAILED, + ERR_BUNDLEMANAGER_QUICK_FIX_PERMISSION_DENIED, + ERR_BUNDLEMANAGER_QUICK_FIX_WRITE_FILE_FAILED, + + ERR_BUNDLE_MANAGER_APP_CONTROL_INTERNAL_ERROR = APPEXECFWK_BUNDLEMGR_ERR_OFFSET + 0x0501, // 8520961 + ERR_BUNDLE_MANAGER_APP_CONTROL_PERMISSION_DENIED, + ERR_BUNDLE_MANAGER_APP_CONTROL_RULE_TYPE_INVALID, + ERR_BUNDLE_MANAGER_BUNDLE_NOT_SET_CONTROL, + ERR_BUNDLE_MANAGER_APP_CONTROL_DISALLOWED_INSTALL, + ERR_BUNDLE_MANAGER_APP_CONTROL_DISALLOWED_UNINSTALL, + // query errcode + ERR_BUNDLE_MANAGER_INTERNAL_ERROR = APPEXECFWK_BUNDLEMGR_ERR_OFFSET + 0x0601, // 8521217 + ERR_BUNDLE_MANAGER_INVALID_PARAMETER, + ERR_BUNDLE_MANAGER_INVALID_USER_ID, + ERR_BUNDLE_MANAGER_BUNDLE_NOT_EXIST, + ERR_BUNDLE_MANAGER_ABILITY_NOT_EXIST, + ERR_BUNDLE_MANAGER_MODULE_NOT_EXIST, + ERR_BUNDLE_MANAGER_ABILITY_DISABLED, + ERR_BUNDLE_MANAGER_APPLICATION_DISABLED, + ERR_BUNDLE_MANAGER_PARAM_ERROR, + ERR_BUNDLE_MANAGER_PERMISSION_DENIED, + ERR_BUNDLE_MANAGER_IPC_TRANSACTION, + ERR_BUNDLE_MANAGER_GLOBAL_RES_MGR_ENABLE_DISABLED, + ERR_BUNDLE_MANAGER_CAN_NOT_CLEAR_USER_DATA, + ERR_BUNDLE_MANAGER_QUERY_PERMISSION_DEFINE_FAILED, + ERR_BUNDLE_MANAGER_DEVICE_ID_NOT_EXIST, + ERR_BUNDLE_MANAGER_PROFILE_NOT_EXIST, + ERR_BUNDLE_MANAGER_INVALID_UID, + ERR_BUNDLE_MANAGER_INVALID_HAP_PATH, + ERR_BUNDLE_MANAGER_DEFAULT_APP_NOT_EXIST, + ERR_BUNDLE_MANAGER_INVALID_TYPE, + ERR_BUNDLE_MANAGER_ABILITY_AND_TYPE_MISMATCH, + ERR_BUNDLE_MANAGER_SYSTEM_API_DENIED, + // zlib errcode + ERR_ZLIB_SRC_FILE_DISABLED, + ERR_ZLIB_DEST_FILE_DISABLED, + ERR_ZLIB_SERVICE_DISABLED, }; // Error code for Hidump diff --git a/mock/innerkits/bundle_framework/appexecfwk_base/include/application_info.h b/mock/innerkits/bundle_framework/appexecfwk_base/include/application_info.h index 12460bcb2c1ca4d6bdd578a2194fcb1e461c197f..56b6e0d6065012931b60cfd1226461b4e5b2a1c2 100644 --- a/mock/innerkits/bundle_framework/appexecfwk_base/include/application_info.h +++ b/mock/innerkits/bundle_framework/appexecfwk_base/include/application_info.h @@ -27,7 +27,8 @@ namespace OHOS { namespace AppExecFwk { namespace { - const std::string AVAILABLELEVEL_NORMAL = "normal"; + static const std::string AVAILABLELEVEL_NORMAL = "normal"; + static const std::string DEFAULT_ENTITY_TYPE = "unspecified"; } enum ApplicationFlag { GET_BASIC_APPLICATION_INFO = 0x00000000, @@ -38,6 +39,24 @@ enum ApplicationFlag { GET_ALL_APPLICATION_INFO = 0xFFFF0000, }; +enum class GetApplicationFlag { + GET_APPLICATION_INFO_DEFAULT = 0x00000000, + GET_APPLICATION_INFO_WITH_PERMISSION = 0x00000001, + GET_APPLICATION_INFO_WITH_METADATA = 0x00000002, + GET_APPLICATION_INFO_WITH_DISABLE = 0x00000004, +}; + +enum class BundleType { + APP = 0, + ATOMIC_SERVICE = 1, +}; + +enum class CompatiblePolicy { + NORMAL = 0, + BACK_COMPATIBLE = 1, + PRECISE_MATCH = 2, +}; + struct Metadata : public Parcelable { std::string name; std::string value; @@ -140,10 +159,17 @@ struct ApplicationInfo : public Parcelable { bool singleton = false; bool userDataClearable = true; bool accessible = false; + bool runningResourcesApply = false; + bool associatedWakeUp = false; + bool hideDesktopIcon = false; + bool formVisibleNotify = false; + std::vector allowCommonEvent; bool isSystemApp = false; bool isLauncherApp = false; bool isFreeInstallApp = false; + bool asanEnabled = false; + std::string asanLogPath; std::string codePath; std::string dataDir; @@ -155,7 +181,7 @@ struct ApplicationInfo : public Parcelable { bool debug = false; std::string deviceId; bool distributedNotificationEnabled = true; - std::string entityType; + std::string entityType = DEFAULT_ENTITY_TYPE; std::string process; int32_t supportedModes = 0; // returns 0 if the application does not support the driving mode std::string vendor; @@ -168,12 +194,15 @@ struct ApplicationInfo : public Parcelable { // user related fields, assign when calling the get interface uint32_t accessTokenId = 0; + uint64_t accessTokenIdEx = 0; bool enabled = false; int32_t uid = -1; // native so std::string nativeLibraryPath; std::string cpuAbi; + std::string arkNativeFilePath; + std::string arkNativeFileAbi; // assign when calling the get interface std::vector permissions; @@ -196,12 +225,27 @@ struct ApplicationInfo : public Parcelable { // switch bool multiProjects = false; + // app detail ability + bool needAppDetail = false; + std::string appDetailAbilityLibraryPath; + + // overlay installation + std::string targetBundleName; + int32_t targetPriority; + int32_t overlayState; + + bool split = true; + BundleType bundleType = BundleType::APP; + + CompatiblePolicy compatiblePolicy = CompatiblePolicy::NORMAL; + bool ReadFromParcel(Parcel &parcel); bool ReadMetaDataFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; static ApplicationInfo *Unmarshalling(Parcel &parcel); void Dump(std::string prefix, int fd); void ConvertToCompatibleApplicationInfo(CompatibleApplicationInfo& compatibleApplicationInfo) const; + bool CheckNeedPreload(const std::string &moduleName) const; }; } // namespace AppExecFwk } // namespace OHOS diff --git a/mock/innerkits/bundle_framework/appexecfwk_base/include/bundle_common_event.h b/mock/innerkits/bundle_framework/appexecfwk_base/include/bundle_common_event.h new file mode 100644 index 0000000000000000000000000000000000000000..ec4d5cb6aa21f9510d1177457256d06e427f10d9 --- /dev/null +++ b/mock/innerkits/bundle_framework/appexecfwk_base/include/bundle_common_event.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 FOUNDATION_BUNDLEMANAGER_BUNDLE_FRAMEWORK_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_COMMON_EVENT_H +#define FOUNDATION_BUNDLEMANAGER_BUNDLE_FRAMEWORK_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_COMMON_EVENT_H + +#include + +namespace OHOS { +namespace AppExecFwk { +const std::string COMMON_EVENT_SANDBOX_PACKAGE_ADDED = "usual.event.SANDBOX_PACKAGE_ADDED"; + +const std::string COMMON_EVENT_SANDBOX_PACKAGE_REMOVED = "usual.event.SANDBOX_PACKAGE_REMOVED"; + +const std::string COMMON_EVENT_BUNDLE_SCAN_FINISHED = "usual.event.BUNDLE_SCAN_FINISHED"; + +const std::string OVERLAY_ADD_ACTION = "usual.event.OVERLAY_PACKAGE_ADDED"; + +const std::string OVERLAY_CHANGED_ACTION = "usual.event.OVERLAY_PACKAGE_CHANGED"; + +const std::string OVERLAY_STATE_CHANGED = "usual.event.OVERLAY_STATE_CHANGED"; +} // AppExecFwk +} // OHOS +#endif // FOUNDATION_BUNDLEMANAGER_BUNDLE_FRAMEWORK_INNERKITS_APPEXECFWK_BASE_INCLUDE_BUNDLE_COMMON_EVENT_H \ No newline at end of file diff --git a/mock/innerkits/bundle_framework/appexecfwk_base/include/bundle_info.h b/mock/innerkits/bundle_framework/appexecfwk_base/include/bundle_info.h index 80e9a745ce343761161f4231a1f9dca37202e7a9..2d271b3b816936ee07f37e53ee0ff58eb64d2fca 100644 --- a/mock/innerkits/bundle_framework/appexecfwk_base/include/bundle_info.h +++ b/mock/innerkits/bundle_framework/appexecfwk_base/include/bundle_info.h @@ -42,6 +42,18 @@ enum BundleFlag { GET_BUNDLE_WITH_HASH_VALUE = 0x00000030, }; +enum class GetBundleInfoFlag { + GET_BUNDLE_INFO_DEFAULT = 0x00000000, + GET_BUNDLE_INFO_WITH_APPLICATION = 0x00000001, + GET_BUNDLE_INFO_WITH_HAP_MODULE = 0x00000002, + GET_BUNDLE_INFO_WITH_ABILITY = 0x00000004, + GET_BUNDLE_INFO_WITH_EXTENSION_ABILITY = 0x00000008, + GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION = 0x00000010, + GET_BUNDLE_INFO_WITH_METADATA = 0x00000020, + GET_BUNDLE_INFO_WITH_DISABLE = 0x00000040, + GET_BUNDLE_INFO_WITH_SIGNATURE_INFO = 0x00000080, +}; + struct RequestPermissionUsedScene : public Parcelable { std::vector abilities; std::string when; @@ -61,6 +73,16 @@ struct RequestPermission : public Parcelable { virtual bool Marshalling(Parcel &parcel) const override; static RequestPermission *Unmarshalling(Parcel &parcel); }; + +struct SignatureInfo : public Parcelable { + std::string appId; + std::string fingerprint; + + bool ReadFromParcel(Parcel &parcel); + virtual bool Marshalling(Parcel &parcel) const override; + static SignatureInfo *Unmarshalling(Parcel &parcel); +}; + // configuration information about a bundle struct BundleInfo : public Parcelable { std::string name; @@ -83,7 +105,6 @@ struct BundleInfo : public Parcelable { std::string mainEntry; // modulePackage std::string entryModuleName; // moduleName bool entryInstallationFree = false; // application : false; atomic service : true - std::string appId; // user related fields, assign when calling the get interface @@ -91,6 +112,7 @@ struct BundleInfo : public Parcelable { int gid = -1; int64_t installTime = 0; int64_t updateTime = 0; + int32_t appIndex = 0; // index for sandbox app ApplicationInfo applicationInfo; std::vector abilityInfos; @@ -106,6 +128,7 @@ struct BundleInfo : public Parcelable { std::vector defPermissions; std::vector reqPermissionStates; std::vector reqPermissionDetails; + std::vector overlayBundleInfos; // unused std::string cpuAbi; @@ -116,6 +139,9 @@ struct BundleInfo : public Parcelable { int32_t minSdkVersion = -1; int32_t maxSdkVersion = -1; bool isDifferentName = false; + int32_t overlayType = NON_OVERLAY_TYPE; + + SignatureInfo signatureInfo; bool ReadFromParcel(Parcel &parcel); virtual bool Marshalling(Parcel &parcel) const override; diff --git a/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_installer_interface.h b/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_installer_interface.h index 9cb7729d847602958caec78c6dabb038d73f7ff6..4b5e16bed71e479a84b7fdca91956ddd39fa5b7d 100644 --- a/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_installer_interface.h +++ b/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_installer_interface.h @@ -123,6 +123,7 @@ public: INSTALL_MULTIPLE_HAPS, UNINSTALL, UNINSTALL_MODULE, + UNINSTALL_BY_UNINSTALL_PARAM, RECOVER, INSTALL_SANDBOX_APP, UNINSTALL_SANDBOX_APP, diff --git a/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h b/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h index ad77c945963914c91534055552a1d0244e9d4780..ae07463cd0f574ac6adbcc6c90df5b477e85d8ab 100644 --- a/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h +++ b/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/bundle_mgr_interface.h @@ -981,11 +981,7 @@ public: GET_BUNDLE_ARCHIVE_INFO, GET_HAP_MODULE_INFO, GET_LAUNCH_WANT_FOR_BUNDLE, - CHECK_PUBLICKEYS, GET_PERMISSION_DEF, - HAS_SYSTEM_CAPABILITY, - GET_SYSTEM_AVAILABLE_CAPABILITIES, - IS_SAFE_MODE, CLEAN_BUNDLE_CACHE_FILES, CLEAN_BUNDLE_DATA_FILES, REGISTER_BUNDLE_STATUS_CALLBACK, @@ -998,8 +994,6 @@ public: SET_ABILITY_ENABLED, GET_ABILITY_INFO, GET_ABILITY_INFO_WITH_MODULE_NAME, - GET_ABILITY_PIXELMAP_ICON, - GET_ABILITY_PIXELMAP_ICON_WITH_MODULE_NAME, GET_ALL_FORMS_INFO, GET_FORMS_INFO_BY_APP, GET_FORMS_INFO_BY_MODULE, @@ -1023,7 +1017,6 @@ public: QUERY_EXTENSION_INFO, QUERY_EXTENSION_INFO_BY_TYPE, VERIFY_CALLING_PERMISSION, - GET_ACCESSIBLE_APP_CODE_PATH, QUERY_EXTENSION_ABILITY_INFO_BY_URI, IS_MODULE_REMOVABLE, SET_MODULE_REMOVABLE, @@ -1036,15 +1029,45 @@ public: IMPLICIT_QUERY_INFOS, GET_ALL_DEPENDENT_MODULE_NAMES, GET_SANDBOX_APP_BUNDLE_INFO, - SET_DISPOSED_STATUS, - GET_DISPOSED_STATUS, QUERY_CALLING_BUNDLE_NAME, GET_DEFAULT_APP_PROXY, GET_BUNDLE_STATS, CHECK_ABILITY_ENABLE_INSTALL, GET_SANDBOX_APP_ABILITY_INFO, GET_SANDBOX_APP_EXTENSION_INFOS, - GET_SANDBOX_MODULE_INFO + GET_SANDBOX_MODULE_INFO, + GET_MEDIA_DATA, + GET_QUICK_FIX_MANAGER_PROXY, + GET_STRING_BY_ID, + GET_ICON_BY_ID, + GET_UDID_BY_NETWORK_ID, + GET_APP_CONTROL_PROXY, + SET_DEBUG_MODE, + QUERY_ABILITY_INFOS_V9, + QUERY_EXTENSION_INFO_WITHOUT_TYPE_V9, + QUERY_EXTENSION_INFO_V9, + GET_APPLICATION_INFOS_WITH_INT_FLAGS_V9, + GET_APPLICATION_INFO_WITH_INT_FLAGS_V9, + GET_BUNDLE_ARCHIVE_INFO_WITH_INT_FLAGS_V9, + GET_BUNDLE_INFO_WITH_INT_FLAGS_V9, + GET_BUNDLE_INFOS_WITH_INT_FLAGS_V9, + GET_SHORTCUT_INFO_V9, + REGISTER_BUNDLE_EVENT_CALLBACK, + UNREGISTER_BUNDLE_EVENT_CALLBACK, + GET_BUNDLE_INFO_FOR_SELF, + VERIFY_SYSTEM_API, + GET_OVERLAY_MANAGER_PROXY, + SILENT_INSTALL, + PROCESS_PRELOAD, + GET_APP_PROVISION_INFO, + GET_PROVISION_METADATA, + GET_BASE_SHARED_BUNDLE_INFOS, + GET_ALL_SHARED_BUNDLE_INFO, + GET_SHARED_BUNDLE_INFO, + GET_SHARED_BUNDLE_INFO_BY_SELF, + GET_SHARED_DEPENDENCIES, + GET_DEPENDENT_BUNDLE_INFO, + GET_UID_BY_DEBUG_BUNDLE_NAME, }; }; } // namespace AppExecFwk diff --git a/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/status_receiver_interface.h b/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/status_receiver_interface.h index d01af2307c49f621234b291bf6478cbc3f913ace..fad959e0b4fe27dd9bbf72dc0f8c224d99f66cf6 100644 --- a/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/status_receiver_interface.h +++ b/mock/innerkits/bundle_framework/appexecfwk_core/include/bundlemgr/status_receiver_interface.h @@ -86,6 +86,22 @@ public: ERR_INSTALL_TYPE_ERROR, ERR_INSTALL_SDK_INCOMPATIBLE, ERR_INSTALL_SO_INCOMPATIBLE, + ERR_INSTALL_AN_INCOMPATIBLE, + ERR_INSTALL_NOT_UNIQUE_DISTRO_MODULE_NAME, + ERR_INSTALL_INCONSISTENT_MODULE_NAME, + ERR_INSTALL_SINGLETON_INCOMPATIBLE, + ERR_INSTALL_DISALLOWED, + ERR_INSTALL_DEVICE_TYPE_NOT_SUPPORTED, + ERR_INSTALL_DEPENDENT_MODULE_NOT_EXIST, + ERR_INSTALL_ASAN_ENABLED_NOT_SAME, + ERR_INSTALL_ASAN_ENABLED_NOT_SUPPORT, + ERR_INSTALL_BUNDLE_TYPE_NOT_SAME, + ERR_INSTALL_SHARE_APP_LIBRARY_NOT_ALLOWED, + ERR_INSTALL_COMPATIBLE_POLICY_NOT_SAME, + ERR_APPEXECFWK_UNINSTALL_SHARE_APP_LIBRARY_IS_NOT_EXIST, + ERR_APPEXECFWK_UNINSTALL_SHARE_APP_LIBRARY_IS_RELIED, + ERR_APPEXECFWK_UNINSTALL_BUNDLE_IS_SHARED_LIBRARY, + ERR_INSTALL_FILE_IS_SHARED_LIBRARY, // signature errcode ERR_INSTALL_FAILED_INVALID_SIGNATURE_FILE_PATH, @@ -117,7 +133,10 @@ public: ERR_INSTALL_PARSE_PROFILE_MISSING_PROP, ERR_INSTALL_PARSE_PERMISSION_ERROR, ERR_INSTALL_PARSE_PROFILE_PROP_CHECK_ERROR, + ERR_INSTALL_PARSE_PROFILE_PROP_SIZE_CHECK_ERROR, ERR_INSTALL_PARSE_RPCID_FAILED, + ERR_INSTALL_PARSE_NATIVE_SO_FAILED, + ERR_INSTALL_PARSE_AN_FAILED, ERR_INSTALLD_PARAM_ERROR, ERR_INSTALLD_GET_PROXY_ERROR, @@ -128,6 +147,29 @@ public: ERR_INSTALLD_EXTRACT_FILES_FAILED, ERR_INSTALLD_RNAME_DIR_FAILED, ERR_INSTALLD_CLEAN_DIR_FAILED, + ERR_INSTALLD_PERMISSION_DENIED, + + // overlay installation + ERR_OVERLAY_INSTALLATION_FAILED_INTERNAL_ERROR, + ERR_OVERLAY_INSTALLATION_FAILED_INVALID_BUNDLE_NAME, + ERR_OVERLAY_INSTALLATION_FAILED_INVALID_MODULE_NAME, + ERR_OVERLAY_INSTALLATION_FAILED_ERROR_HAP_TYPE, + ERR_OVERLAY_INSTALLATION_FAILED_ERROR_BUNDLE_TYPE, + ERR_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_NAME_MISSED, + ERR_OVERLAY_INSTALLATION_FAILED_TARGET_MODULE_NAME_MISSED, + ERR_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_NAME_NOT_SAME, + ERR_OVERLAY_INSTALLATION_FAILED_INTERNAL_EXTERNAL_OVERLAY_EXISTED_SIMULTANEOUSLY, + ERR_OVERLAY_INSTALLATION_FAILED_TARGET_PRIORITY_NOT_SAME, + ERR_OVERLAY_INSTALLATION_FAILED_INVALID_PRIORITY, + ERR_OVERLAY_INSTALLATION_FAILED_INCONSISTENT_VERSION_CODE, + ERR_OVERLAY_INSTALLATION_FAILED_SERVICE_EXCEPTION, + ERR_OVERLAY_INSTALLATION_FAILED_BUNDLE_NAME_SAME_WITH_TARGET_BUNDLE_NAME, + ERR_OVERLAY_INSTALLATION_FAILED_NO_SYSTEM_APPLICATION_FOR_EXTERNAL_OVERLAY, + ERR_OVERLAY_INSTALLATION_FAILED_DIFFERENT_SIGNATURE_CERTIFICATE, + ERR_OVERLAY_INSTALLATION_FAILED_TARGET_BUNDLE_IS_OVERLAY_BUNDLE, + ERR_OVERLAY_INSTALLATION_FAILED_TARGET_MODULE_IS_OVERLAY_MODULE, + ERR_OVERLAY_INSTALLATION_FAILED_OVERLAY_TYPE_NOT_SAME, + ERR_OVERLAY_INSTALLATION_FAILED_INVALID_BUNDLE_DIR, ERR_UNINSTALL_SYSTEM_APP_ERROR, ERR_UNINSTALL_KILLING_APP_ERROR, @@ -137,6 +179,7 @@ public: ERR_UNINSTALL_BUNDLE_MGR_SERVICE_ERROR, ERR_UNINSTALL_MISSING_INSTALLED_BUNDLE, ERR_UNINSTALL_MISSING_INSTALLED_MODULE, + ERR_UNINSTALL_DISALLOWED, ERR_UNKNOWN, ERR_FAILED_GET_INSTALLER_PROXY, @@ -145,10 +188,11 @@ public: ERR_RECOVER_GET_BUNDLEPATH_ERROR = 201, ERR_RECOVER_INVALID_BUNDLE_NAME, + ERR_RECOVER_NOT_ALLOWED, ERR_USER_NOT_EXIST = 301, - ERR_USER_CREATE_FALIED, - ERR_USER_REMOVE_FALIED, + ERR_USER_CREATE_FAILED, + ERR_USER_REMOVE_FAILED, ERR_USER_NOT_INSTALL_HAP, }; }; diff --git a/mock/innerkits/device_manager/devicemanagersdk/include/device_manager.h b/mock/innerkits/device_manager/devicemanagersdk/include/device_manager.h index d926cb798652650f6ef08e46a2c9acf4b7c95f34..ddd92e92d56051399d2e87df296bcc4de9f6aad9 100644 --- a/mock/innerkits/device_manager/devicemanagersdk/include/device_manager.h +++ b/mock/innerkits/device_manager/devicemanagersdk/include/device_manager.h @@ -1,17 +1,17 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * 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. - */ +* Copyright (c) 2022-2023 Huawei Device Co., Ltd. +* 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 OHOS_DEVICE_MANAGER_H #define OHOS_DEVICE_MANAGER_H @@ -29,184 +29,229 @@ namespace OHOS { namespace DistributedHardware { class DeviceManager { public: - static DeviceManager &GetInstance(); + static DeviceManager &GetInstance(); public: - /** - * @tc.name: DeviceManagerImpl::InitDeviceManager - * @tc.desc: Initialize DeviceManager - * @tc.type: FUNC - */ - virtual int32_t InitDeviceManager(const std::string &pkgName, std::shared_ptr dmInitCallback) = 0; - /** - * @tc.name: DeviceManagerImpl::UnInitDeviceManager - * @tc.desc: UnInitialize DeviceManager - * @tc.type: FUNC - */ - virtual int32_t UnInitDeviceManager(const std::string &pkgName) = 0; - /** - * @tc.name: DeviceManagerImpl::GetTrustedDeviceList - * @tc.desc: Get device list of trusted devices - * @tc.type: FUNC - */ - virtual int32_t GetTrustedDeviceList(const std::string &pkgName, const std::string &extra, - std::vector &deviceList) = 0; - /** - * @tc.name: DeviceManagerImpl::GetLocalDeviceInfo - * @tc.desc: Get local device information - * @tc.type: FUNC - */ - virtual int32_t GetLocalDeviceInfo(const std::string &pkgName, DmDeviceInfo &deviceInfo) = 0; - /** - * @brief Register device status callback - * @param pkgName package name - * @param extra extra info.This parameter can be null. - * @param callback device state callback - * @return return 0 if success - */ - virtual int32_t RegisterDevStateCallback(const std::string &pkgName, const std::string &extra, - std::shared_ptr callback) = 0; - /** - * @brief Unregister device status callback - * @param pkgName package name - * @return return 0 if success - */ - virtual int32_t UnRegisterDevStateCallback(const std::string &pkgName) = 0; - /** - * @tc.name: DeviceManagerImpl::StartDeviceDiscovery - * @tc.desc: Initiate device discovery - * @tc.type: FUNC - */ - virtual int32_t StartDeviceDiscovery(const std::string &pkgName, const DmSubscribeInfo &subscribeInfo, - const std::string &extra, std::shared_ptr callback) = 0; - /** - * @tc.name: DeviceManagerImpl::StopDeviceDiscovery - * @tc.desc: Stop device discovery - * @tc.type: FUNC - */ - virtual int32_t StopDeviceDiscovery(const std::string &pkgName, uint16_t subscribeId) = 0; - /** - * @tc.name: DeviceManagerImpl::PublishDeviceDiscovery - * @tc.desc: Publish device discovery - * @tc.type: FUNC - */ - virtual int32_t PublishDeviceDiscovery(const std::string &pkgName, const DmPublishInfo &publishInfo, - std::shared_ptr callback) = 0; - /** - * @tc.name: DeviceManagerImpl::UnPublishDeviceDiscovery - * @tc.desc: UnPublish device discovery - * @tc.type: FUNC - */ - virtual int32_t UnPublishDeviceDiscovery(const std::string &pkgName, int32_t publishId) = 0; - /** - * @tc.name: DeviceManagerImpl::AuthenticateDevice - * @tc.desc: Complete verifying the device - * @tc.type: FUNC - */ - virtual int32_t AuthenticateDevice(const std::string &pkgName, int32_t authType, const DmDeviceInfo &deviceInfo, - const std::string &extra, std::shared_ptr callback) = 0; - /** - * @tc.name: DeviceManagerImpl::UnAuthenticateDevice - * @tc.desc: Cancel complete verification of device - * @tc.type: FUNC - */ - virtual int32_t UnAuthenticateDevice(const std::string &pkgName, const DmDeviceInfo &deviceInfo) = 0; - /** - * @tc.name: DeviceManagerImpl::VerifyAuthentication - * @tc.desc: Verify device authentication - * @tc.type: FUNC - */ - virtual int32_t VerifyAuthentication(const std::string &pkgName, const std::string &authPara, - std::shared_ptr callback) = 0; - /** - * @tc.name: DeviceManagerImpl::RegisterDeviceManagerFaCallback - * @tc.desc: Register Fa callback for device manager - * @tc.type: FUNC - */ - virtual int32_t RegisterDeviceManagerFaCallback(const std::string &pkgName, - std::shared_ptr callback) = 0; - /** - * @tc.name: DeviceManagerImpl::UnRegisterDeviceManagerFaCallback - * @tc.desc: Unregister Fa callback for device manager - * @tc.type: FUNC - */ - virtual int32_t UnRegisterDeviceManagerFaCallback(const std::string &pkgName) = 0; - /** - * @tc.name: DeviceManagerImpl::GetFaParam - * @tc.desc: Get Fa Param - * @tc.type: FUNC - */ - virtual int32_t GetFaParam(const std::string &pkgName, DmAuthParam &faParam) = 0; - /** - * @tc.name: DeviceManagerImpl::SetUserOperation - * @tc.desc: Set User Actions - * @tc.type: FUNC - */ - virtual int32_t SetUserOperation(const std::string &pkgName, int32_t action) = 0; - /** - * @tc.name: DeviceManagerImpl::GetUdidByNetworkId - * @tc.desc: Get Udid by NetworkId - * @tc.type: FUNC - */ - virtual int32_t GetUdidByNetworkId(const std::string &pkgName, const std::string &netWorkId, std::string &udid) = 0; - /** - * @tc.name: DeviceManagerImpl::GetUuidByNetworkId - * @tc.desc: Get Uuid by NetworkId - * @tc.type: FUNC - */ - virtual int32_t GetUuidByNetworkId(const std::string &pkgName, const std::string &netWorkId, std::string &uuid) = 0; - /** - * @brief Unregister device status callback - * @param pkgName package name - * @param extra extra info.This parameter can be null. - * @return return 0 if success - */ - virtual int32_t RegisterDevStateCallback(const std::string &pkgName, const std::string &extra) = 0; - /** - * @brief Unregister device status callback - * @param pkgName package name - * @param extra extra info.This parameter can be null. - * @return return 0 if success - */ - virtual int32_t UnRegisterDevStateCallback(const std::string &pkgName, const std::string &extra) = 0; - /** - * @tc.name: DeviceManagerImpl::RequestCredential - * @tc.desc: RequestCredential - * @tc.type: FUNC - */ - virtual int32_t RequestCredential(const std::string &pkgName, const std::string &reqJsonStr, - std::string &returnJsonStr) = 0; - /** - * @tc.name: DeviceManagerImpl::ImportCredential - * @tc.desc: ImportCredential - * @tc.type: FUNC - */ - virtual int32_t ImportCredential(const std::string &pkgName, const std::string &credentialInfo) = 0; - /** - * @tc.name: DeviceManagerImpl::DeleteCredential - * @tc.desc: DeleteCredential - * @tc.type: FUNC - */ - virtual int32_t DeleteCredential(const std::string &pkgName, const std::string &deleteInfo) = 0; - /** - * @tc.name: DeviceManagerImpl::RegisterCredentialCallback - * @tc.desc: RegisterCredentialCallback - * @tc.type: FUNC - */ - virtual int32_t RegisterCredentialCallback(const std::string &pkgName, - std::shared_ptr callback) = 0; - /** - * @tc.name: DeviceManagerImpl::UnRegisterCredentialCallback - * @tc.desc: UnRegisterCredentialCallback - * @tc.type: FUNC - */ - virtual int32_t UnRegisterCredentialCallback(const std::string &pkgName) = 0; - /** - * @brief Notify Event to DM - * @param pkgName package name - * @param event event info - */ - virtual int32_t NotifyEvent(const std::string &pkgName, const int32_t eventId, const std::string &event) = 0; + /** + * @brief Initialize DeviceManager. + * @param pkgName package name. + * @param dmInitCallback the callback to be invoked upon InitDeviceManager. + * @return Returns 0 if success. + */ + virtual int32_t InitDeviceManager(const std::string &pkgName, std::shared_ptr dmInitCallback) = 0; + /** + * @brief UnInitialize DeviceManager. + * @param pkgName package name. + * @return Returns 0 if success. + */ + virtual int32_t UnInitDeviceManager(const std::string &pkgName) = 0; + /** + * @brief Get device info list of trusted devices. + * @param pkgName package name. + * @param extra extra info.This parameter can be null. + * @param deviceList device info list. + * @return Returns a list of trusted devices. + */ + virtual int32_t GetTrustedDeviceList(const std::string &pkgName, const std::string &extra, + std::vector &deviceList) = 0; + /** + * @brief Get local device information. + * @param pkgName package name. + * @param deviceInfo device info. + * @return Returns local device info. + */ + virtual int32_t GetLocalDeviceInfo(const std::string &pkgName, DmDeviceInfo &deviceInfo) = 0; + /** + * @tc.name: DeviceManagerImpl::GetDeviceInfo + * @tc.desc: Get local device information by networkId + * @tc.type: FUNC + */ + virtual int32_t GetDeviceInfo(const std::string &pkgName, const std::string networkId, + DmDeviceInfo &deviceInfo) = 0; + /** + * @brief Register device status callback. + * @param pkgName package name. + * @param extra extra info.This parameter can be null. + * @param callback device state callback. + * @return Returns 0 if success. + */ + virtual int32_t RegisterDevStateCallback(const std::string &pkgName, const std::string &extra, + std::shared_ptr callback) = 0; + /** + * @brief Unregister device status callback. + * @param pkgName package name. + * @return Returns 0 if success. + */ + virtual int32_t UnRegisterDevStateCallback(const std::string &pkgName) = 0; + /** + * @brief Initiate device discovery. + * @param pkgName package name. + * @param subscribeInfo subscribe info to discovery device. + * @param extra extra info.This parameter can be null. + * @param callback discovery callback. + * @return Returns 0 if success. + */ + virtual int32_t StartDeviceDiscovery(const std::string &pkgName, const DmSubscribeInfo &subscribeInfo, + const std::string &extra, std::shared_ptr callback) = 0; + /** + * @brief Stop device discovery. + * @param pkgName package name. + * @param subscribeInfo subscribe info to discovery device. + * @return Returns 0 if success. + */ + virtual int32_t StopDeviceDiscovery(const std::string &pkgName, uint16_t subscribeId) = 0; + /** + * @brief Publish device discovery. + * @param pkgName package name. + * @param publishInfo publish info to Publish discovery device. + * @param callback the callback to be invoked upon PublishDeviceDiscovery. + * @return Returns 0 if success. + */ + virtual int32_t PublishDeviceDiscovery(const std::string &pkgName, const DmPublishInfo &publishInfo, + std::shared_ptr callback) = 0; + /** + * @brief UnPublish device discovery. + * @param pkgName package name. + * @param publishId service publish ID, identify a publish operation, should be a unique id in package range. + * @return Returns 0 if success. + */ + virtual int32_t UnPublishDeviceDiscovery(const std::string &pkgName, int32_t publishId) = 0; + /** + * @brief Authenticate the specified device. + * @param pkgName package name. + * @param authType authType of device to authenticate. + * @param deviceInfo deviceInfo of device to authenticate. + * @param extra extra info.This parameter can be null. + * @param callback the callback to be invoked upon AuthenticateDevice. + * @return Returns 0 if success. + */ + virtual int32_t AuthenticateDevice(const std::string &pkgName, int32_t authType, const DmDeviceInfo &deviceInfo, + const std::string &extra, std::shared_ptr callback) = 0; + /** + * @brief Cancel complete verification of device. + * @param pkgName package name. + * @param deviceInfo deviceInfo of device to authenticate. + * @return Returns 0 if success. + */ + virtual int32_t UnAuthenticateDevice(const std::string &pkgName, const DmDeviceInfo &deviceInfo) = 0; + /** + * @brief Verify device authentication. + * @param pkgName package name. + * @param authPara authPara of device to authenticate. + * @param callback the callback to be invoked upon VerifyAuthentication. + * @return Returns 0 if success. + */ + virtual int32_t VerifyAuthentication(const std::string &pkgName, const std::string &authPara, + std::shared_ptr callback) = 0; + /** + * @brief Get Fa Param. + * @param pkgName package name. + * @param faParam fa param. + * @return Returns 0 if success. + */ + virtual int32_t GetFaParam(const std::string &pkgName, DmAuthParam &faParam) = 0; + /** + * @brief Set User Actions. + * @param pkgName package name. + * @param action user operation action. + * @param params indicates the input param of the user. + * @return Returns 0 if success. + */ + virtual int32_t SetUserOperation(const std::string &pkgName, int32_t action, const std::string ¶ms) = 0; + /** + * @brief Get Udid by NetworkId. + * @param pkgName package name. + * @param netWorkId netWork Id. + * @param udid unique device id. + * @return Returns 0 if success. + */ + virtual int32_t GetUdidByNetworkId(const std::string &pkgName, const std::string &netWorkId, std::string &udid) = 0; + /** + * @brief Get Uuid by NetworkId. + * @param pkgName package name. + * @param netWorkId netWork Id. + * @param uuid universally unique id. + * @return Returns 0 if success. + */ + virtual int32_t GetUuidByNetworkId(const std::string &pkgName, const std::string &netWorkId, std::string &uuid) = 0; + /** + * @brief Unregister device status callback. + * @param pkgName package name. + * @param extra extra info.This parameter can be null. + * @return Returns 0 if success. + */ + virtual int32_t RegisterDevStateCallback(const std::string &pkgName, const std::string &extra) = 0; + /** + * @brief Unregister device status callback. + * @param pkgName package name. + * @param extra extra info.This parameter can be null. + * @return Returns 0 if success. + */ + virtual int32_t UnRegisterDevStateCallback(const std::string &pkgName, const std::string &extra) = 0; + /** + * @brief Request credential information. + * @param pkgName package name. + * @param reqJsonStr request credential params, the params is json string, it includes version and userId. + * @param returnJsonStr return json string, it includes deviceId, devicePk, useId and version. + * @return Returns 0 if success. + */ + virtual int32_t RequestCredential(const std::string &pkgName, const std::string &reqJsonStr, + std::string &returnJsonStr) = 0; + /** + * @brief Import credential information. + * @param pkgName package name. + * @param credentialInfo import credential params, the params is json string, it includes processType, authType, + * userId, deviceId, version, devicePk and credentialData, the credentialData is array, each array element + * includes credentialType, credentialId, serverPk, pkInfoSignature, pkInfo, authCode, peerDeviceId. + * @return Returns 0 if success. + */ + virtual int32_t ImportCredential(const std::string &pkgName, const std::string &credentialInfo) = 0; + /** + * @brief Delete credential information. + * @param pkgName package name. + * @param deleteInfo delete credential params. the params is json string, it includes processType, authType, userId. + * @return Returns 0 if success. + */ + virtual int32_t DeleteCredential(const std::string &pkgName, const std::string &deleteInfo) = 0; + /** + * @brief Register credential callback. + * @param pkgName package name. + * @param callback credential callback. + * @return Returns 0 if success. + */ + virtual int32_t RegisterCredentialCallback(const std::string &pkgName, + std::shared_ptr callback) = 0; + /** + * @brief UnRegister credential callback. + * @param pkgName package name. + * @return Returns 0 if success. + */ + virtual int32_t UnRegisterCredentialCallback(const std::string &pkgName) = 0; + /** + * @brief Notify event to device manager. + * @param pkgName package name. + * @param event event info. + * @param event event string. + * @return Returns 0 if success. + */ + virtual int32_t NotifyEvent(const std::string &pkgName, const int32_t eventId, const std::string &event) = 0; + + /** + * @brief Get encrypted uuid. + * @param networkId device networkId. + * @return Returns encrypted uuid. + */ + virtual int32_t GetEncryptedUuidByNetworkId(const std::string &pkgName, const std::string &networkId, + std::string &uuid) = 0; + + /** + * @brief Get encrypted uuid. + * @param uuid device uuid. + * @param tokenId tokenId. + * @return Returns encrypted uuid. + */ + virtual int32_t GenerateEncryptedUuid(const std::string &pkgName, const std::string &uuid, const std::string &appId, + std::string &encryptedUuid) = 0; }; } // namespace DistributedHardware } // namespace OHOS diff --git a/mock/innerkits/device_manager/devicemanagersdk/include/device_manager_impl.h b/mock/innerkits/device_manager/devicemanagersdk/include/device_manager_impl.h index fd78f385579f93492a6643c775f5ea41a032418f..4215fde3fce87e7aacda633ecef5f2c9e0fcb2a1 100644 --- a/mock/innerkits/device_manager/devicemanagersdk/include/device_manager_impl.h +++ b/mock/innerkits/device_manager/devicemanagersdk/include/device_manager_impl.h @@ -112,31 +112,13 @@ public: */ virtual int32_t VerifyAuthentication(const std::string &pkgName, const std::string &authPara, std::shared_ptr callback) override; - /** - * @tc.name: DeviceManagerImpl::RegisterDeviceManagerFaCallback - * @tc.desc: Register Fa callback for device manager - * @tc.type: FUNC - */ - virtual int32_t RegisterDeviceManagerFaCallback(const std::string &packageName, - std::shared_ptr callback) override; - /** - * @tc.name: DeviceManagerImpl::UnRegisterDeviceManagerFaCallback - * @tc.desc: Unregister Fa callback for device manager - * @tc.type: FUNC - */ - virtual int32_t UnRegisterDeviceManagerFaCallback(const std::string &pkgName) override; /** * @tc.name: DeviceManagerImpl::GetFaParam * @tc.desc: Get Fa Param * @tc.type: FUNC */ virtual int32_t GetFaParam(const std::string &pkgName, DmAuthParam &faParam) override; - /** - * @tc.name: DeviceManagerImpl::SetUserOperation - * @tc.desc: Set User Actions - * @tc.type: FUNC - */ - virtual int32_t SetUserOperation(const std::string &pkgName, int32_t action) override; + /** * @tc.name: DeviceManagerImpl::GetUdidByNetworkId * @tc.desc: Get Udid by NetworkId @@ -202,6 +184,16 @@ public: * @tc.type: FUNC */ virtual int32_t NotifyEvent(const std::string &pkgName, const int32_t eventId, const std::string &event) override; + + virtual int32_t GetEncryptedUuidByNetworkId(const std::string &pkgName, const std::string &networkId, + std::string &uuid) override; + + virtual int32_t GenerateEncryptedUuid(const std::string &pkgName, const std::string &uuid, + const std::string &appId, std::string &encryptedUuid) override; + + int32_t GetDeviceInfo(const std::string &pkgName, const std::string networkId, DmDeviceInfo &deviceInfo) override; + int32_t SetUserOperation(const std::string &pkgName, int32_t action, const std::string ¶ms) override; + private: DeviceManagerImpl() = default; ~DeviceManagerImpl() = default; diff --git a/mock/innerkits/huks/libhukssdk/include/hks_log.h b/mock/innerkits/huks/libhukssdk/include/hks_log.h index 3a5a31a46ae453e33df177bd45aba624fc4b1c44..ed971a70f6b4788dd27af1979d587eb9714eac12 100644 --- a/mock/innerkits/huks/libhukssdk/include/hks_log.h +++ b/mock/innerkits/huks/libhukssdk/include/hks_log.h @@ -1,17 +1,17 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. - * 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. - */ +* Copyright (c) 2021 Huawei Device Co., Ltd. +* 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 HKS_LOG_H #define HKS_LOG_H @@ -47,13 +47,13 @@ #endif #define HKS_LOG_I(fmt, arg...) HILOG_INFO(LOG_ENGINE, "%" LOG_PUBLIC "s[%" LOG_PUBLIC "u]: " fmt "\n", \ - __func__, __LINE__, ##arg) + __func__, __LINE__, ##arg) #define HKS_LOG_W(fmt, arg...) HILOG_WARN(LOG_ENGINE, "%" LOG_PUBLIC "s[%" LOG_PUBLIC "u]: " fmt "\n", \ - __func__, __LINE__, ##arg) + __func__, __LINE__, ##arg) #define HKS_LOG_E(fmt, arg...) HILOG_ERROR(LOG_ENGINE, "%" LOG_PUBLIC "s[%" LOG_PUBLIC "u]: " fmt "\n", \ - __func__, __LINE__, ##arg) + __func__, __LINE__, ##arg) #define HKS_LOG_D(fmt, arg...) HILOG_DEBUG(LOG_ENGINE, "%" LOG_PUBLIC "s[%" LOG_PUBLIC "u]: " fmt "\n", \ - __func__, __LINE__, ##arg) + __func__, __LINE__, ##arg) #else #define HKS_LOG_I(...) #define HKS_LOG_W(...) diff --git a/mock/innerkits/huks/libhukssdk/include/hks_template.h b/mock/innerkits/huks/libhukssdk/include/hks_template.h index 20eca013cdeedf5c7ecc3b8622ff60878c9f8cf9..a6a7f2a870c367729c59019f7d6efec1b4506516 100644 --- a/mock/innerkits/huks/libhukssdk/include/hks_template.h +++ b/mock/innerkits/huks/libhukssdk/include/hks_template.h @@ -1,8 +1,75 @@ -// -// Created by HuTao on 2023/2/20. -// +/* +* Copyright (c) 2022 Huawei Device Co., Ltd. +* 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 LDBPROJ_HKS_TEMPLATE_H -#define LDBPROJ_HKS_TEMPLATE_H +#ifndef HKS_TEMPLATE_H +#define HKS_TEMPLATE_H -#endif //LDBPROJ_HKS_TEMPLATE_H +#undef HKS_NULL_POINTER + +#ifdef __cplusplus +#define HKS_NULL_POINTER nullptr +#else +#define HKS_NULL_POINTER NULL +#endif + +#define HKS_IF_NOT_SUCC_LOGE_RETURN(RESULT, ERROR_CODE, LOG_MESSAGE, ...) \ +if ((RESULT) != HKS_SUCCESS) { \ + HKS_LOG_E(LOG_MESSAGE, ##__VA_ARGS__); \ + return (ERROR_CODE); \ +} + +#define HKS_IF_NOT_SUCC_LOGE_BREAK(RESULT, LOG_MESSAGE, ...) \ +if ((RESULT) != HKS_SUCCESS) { \ + HKS_LOG_E(LOG_MESSAGE, ##__VA_ARGS__); \ + break; \ +} + +#define HKS_IF_NOT_SUCC_BREAK(RESULT, ...) \ +if ((RESULT) != HKS_SUCCESS) { \ + break; \ +} + +#define HKS_IF_NOT_SUCC_LOGE(RESULT, LOG_MESSAGE, ...) \ +if ((RESULT) != HKS_SUCCESS) { \ + HKS_LOG_E(LOG_MESSAGE, ##__VA_ARGS__); \ +} + +#define HKS_IF_NOT_SUCC_RETURN(RESULT, ERROR_CODE) \ +if ((RESULT) != HKS_SUCCESS) { \ + return (ERROR_CODE); \ +} + +#define HKS_IF_NULL_LOGE_RETURN(OBJECT, ERROR_CODE, LOG_MESSAGE, ...) \ +if ((OBJECT) == HKS_NULL_POINTER) { \ + HKS_LOG_E(LOG_MESSAGE, ##__VA_ARGS__); \ + return (ERROR_CODE); \ +} + +#define HKS_IF_NULL_LOGE_BREAK(OBJECT, LOG_MESSAGE, ...) \ +if ((OBJECT) == HKS_NULL_POINTER) { \ + HKS_LOG_E(LOG_MESSAGE, ##__VA_ARGS__); \ + break; \ +} + +#define HKS_IF_NULL_RETURN(OBJECT, ERROR_CODE) \ +if ((OBJECT) == HKS_NULL_POINTER) { \ + return (ERROR_CODE); \ +} + +#define HKS_IF_NULL_BREAK(OBJECT) \ +if ((OBJECT) == HKS_NULL_POINTER) { \ + break; \ +} +#endif /* HKS_TEMPLATE_H */ diff --git a/mock/innerkits/huks/libhukssdk/include/hks_type.h b/mock/innerkits/huks/libhukssdk/include/hks_type.h index 6b674e24ebea2af14ac371bbe391095523f74523..4dfaa437be76de2c9f4cda2257c30cf244a272d4 100644 --- a/mock/innerkits/huks/libhukssdk/include/hks_type.h +++ b/mock/innerkits/huks/libhukssdk/include/hks_type.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2022 Huawei Device Co., Ltd. +* Copyright (c) 2021-2023 Huawei Device Co., Ltd. * 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 @@ -13,6 +13,14 @@ * limitations under the License. */ +/** +* @file hks_param.h +* +* @brief Declares huks struct and enum. +* +* @since 8 +*/ + #ifndef HKS_TYPE_H #define HKS_TYPE_H @@ -70,6 +78,12 @@ extern "C" { #define HKS_CERT_DEVICE_SIZE 2048 #define HKS_CERT_APP_SIZE 4096 +#define HKS_KEY_BLOB_AT_KEY_SIZE 256 +#define HKS_KEY_BLOB_AT_KEY_BYTES 32 + +/** +* @brief hks key type +*/ enum HksKeyType { HKS_KEY_TYPE_RSA_PUBLIC_KEY = 0x01001000, HKS_KEY_TYPE_RSA_KEYPAIR = 0x01002000, @@ -95,6 +109,9 @@ enum HksKeyType { HKS_KEY_TYPE_PBKDF2 = 0x07000000, }; +/** +* @brief hks key purpose +*/ enum HksKeyPurpose { HKS_KEY_PURPOSE_ENCRYPT = 1, /* Usable with RSA, EC, AES, and SM4 keys. */ HKS_KEY_PURPOSE_DECRYPT = 2, /* Usable with RSA, EC, AES, and SM4 keys. */ @@ -107,6 +124,9 @@ enum HksKeyPurpose { HKS_KEY_PURPOSE_AGREE = 256, /* Usable with agree. */ }; +/** +* @brief hks key digest +*/ enum HksKeyDigest { HKS_DIGEST_NONE = 0, HKS_DIGEST_MD5 = 1, @@ -118,6 +138,9 @@ enum HksKeyDigest { HKS_DIGEST_SHA512 = 14, }; +/** +* @brief hks key padding +*/ enum HksKeyPadding { HKS_PADDING_NONE = 0, HKS_PADDING_OAEP = 1, @@ -127,6 +150,9 @@ enum HksKeyPadding { HKS_PADDING_PKCS7 = 5, }; +/** +* @brief hks cipher mode +*/ enum HksCipherMode { HKS_MODE_ECB = 1, HKS_MODE_CBC = 2, @@ -136,6 +162,9 @@ enum HksCipherMode { HKS_MODE_GCM = 32, }; +/** +* @brief hks key size +*/ enum HksKeySize { HKS_RSA_KEY_SIZE_512 = 512, HKS_RSA_KEY_SIZE_768 = 768, @@ -164,6 +193,9 @@ enum HksKeySize { HKS_SM4_KEY_SIZE_128 = 128, }; +/** +* @brief hks key algorithm +*/ enum HksKeyAlg { HKS_ALG_RSA = 1, HKS_ALG_ECC = 2, @@ -173,6 +205,7 @@ enum HksKeyAlg { HKS_ALG_HMAC = 50, HKS_ALG_HKDF = 51, HKS_ALG_PBKDF2 = 52, + HKS_ALG_GMKDF = 53, HKS_ALG_ECDH = 100, HKS_ALG_X25519 = 101, @@ -184,6 +217,9 @@ enum HksKeyAlg { HKS_ALG_SM4 = 152, }; +/** +* @brief hks algorithm suite +*/ enum HuksAlgSuite { /* Algorithm suites of unwrapping wrapped-key by huks */ /* Unwrap suite of key agreement type */ @@ -204,14 +240,37 @@ enum HuksAlgSuite { * | key_material_size_len (4 Byte) | key_material_size | key_mat_enc_length (4 Byte) | key_mat_enc_data */ HKS_UNWRAP_SUITE_ECDH_AES_256_GCM_NOPADDING = 2, + + /* WrappedData format(Bytes Array): + * | SM2_plain_pubkey_length (4 Byte) | SM2_plain_pubkey | signData_size_length (4 Byte) | signData_size + * | kek_enc_data_length (4 Byte) | kek_enc_data | kek_material_size_len(4 Byte) | kek_material_size + * | factor1_data_len (4 Byte) | factor1_data | factor2_data_len (4 Byte) | factor2_data + * | mac_data_length (4 Byte) | mac_data | key_mat_enc_length (4 Byte) | key_mat_enc_data + * | iv_data_length (4 Byte) | iv_data |key_material_size_len (4 Byte) | key_material_size + */ + HKS_UNWRAP_SUITE_SM2_SM4_128_CBC_PKCS7_WITH_VERIFY_DIG_SM3 = 3, + + /* WrappedData format(Bytes Array): + * | kek_enc_data_length (4 Byte) | kek_enc_data | kek_material_size_len(4 Byte) | kek_material_size + * | factor1_data_len (4 Byte) | factor1_data | factor2_data_len (4 Byte) | factor2_data + * | mac_data_length (4 Byte) | mac_data | key_mat_enc_length (4 Byte) | key_mat_enc_data + * | iv_data_length (4 Byte) | iv_data |key_material_size_len (4 Byte) | key_material_size + */ + HKS_UNWRAP_SUITE_SM2_SM4_128_CBC_PKCS7 = 4, }; +/** +* @brief hks key generate type +*/ enum HksKeyGenerateType { HKS_KEY_GENERATE_TYPE_DEFAULT = 0, HKS_KEY_GENERATE_TYPE_DERIVE = 1, HKS_KEY_GENERATE_TYPE_AGREE = 2, }; +/** +* @brief hks key flag +*/ enum HksKeyFlag { HKS_KEY_FLAG_IMPORT_KEY = 1, HKS_KEY_FLAG_GENERATE_KEY = 2, @@ -219,17 +278,36 @@ enum HksKeyFlag { HKS_KEY_FLAG_DERIVE_KEY = 4, }; +/** +* @brief hks key storage type +*/ enum HksKeyStorageType { HKS_STORAGE_TEMP = 0, HKS_STORAGE_PERSISTENT = 1, + HKS_STORAGE_ONLY_USED_IN_HUKS = 2, + HKS_STORAGE_ALLOW_KEY_EXPORTED = 3, }; +/** +* @brief hks import key type +*/ enum HksImportKeyType { HKS_KEY_TYPE_PUBLIC_KEY = 0, HKS_KEY_TYPE_PRIVATE_KEY = 1, HKS_KEY_TYPE_KEY_PAIR = 2, }; +/** +* @brief hks rsa pss salt len type +*/ +enum HksRsaPssSaltLenType { + HKS_RSA_PSS_SALTLEN_DIGEST = 0, /* Salt length matches digest */ + HKS_RSA_PSS_SALTLEN_MAX = 1, /* Set salt length to maximum possible, default type */ +}; + +/** +* @brief hks error code +*/ enum HksErrorCode { HKS_SUCCESS = 0, HKS_FAILURE = -1, @@ -327,6 +405,9 @@ enum HksErrorCode { HKS_ERROR_UNKNOWN_ERROR = -1000, }; +/** +* @brief hks err code +*/ enum HksErrCode { HUKS_ERR_CODE_PERMISSION_FAIL = 201, HUKS_ERR_CODE_ILLEGAL_ARGUMENT = 401, @@ -349,6 +430,9 @@ enum HksErrCode { HUKS_ERR_CODE_CALL_SERVICE_FAILED = 12000015, }; +/** +* @brief hks tag type +*/ enum HksTagType { HKS_TAG_TYPE_INVALID = 0 << 28, HKS_TAG_TYPE_INT = 1 << 28, @@ -358,28 +442,43 @@ enum HksTagType { HKS_TAG_TYPE_BYTES = 5 << 28, }; +/** +* @brief hks send type +*/ enum HksSendType { HKS_SEND_TYPE_ASYNC = 0, HKS_SEND_TYPE_SYNC, }; +/** +* @brief hks user auth type +*/ enum HksUserAuthType { HKS_USER_AUTH_TYPE_FINGERPRINT = 1 << 0, HKS_USER_AUTH_TYPE_FACE = 1 << 1, HKS_USER_AUTH_TYPE_PIN = 1 << 2, }; +/** +* @brief hks auth access type +*/ enum HksAuthAccessType { HKS_AUTH_ACCESS_INVALID_CLEAR_PASSWORD = 1 << 0, HKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL = 1 << 1, }; +/** +* @brief hks challenge type +*/ enum HksChallengeType { HKS_CHALLENGE_TYPE_NORMAL = 0, HKS_CHALLENGE_TYPE_CUSTOM = 1, HKS_CHALLENGE_TYPE_NONE = 2, }; +/** +* @brief hks challenge position +*/ enum HksChallengePosition { HKS_CHALLENGE_POS_0 = 0, HKS_CHALLENGE_POS_1, @@ -387,154 +486,157 @@ enum HksChallengePosition { HKS_CHALLENGE_POS_3, }; +/** +* @brief hks secure sign type +*/ enum HksSecureSignType { HKS_SECURE_SIGN_WITH_AUTHINFO = 1, }; +#define HKS_ASSIGN_ENUM_VALUE(x, y) x = y, + +#define HKS_ASSIGN_PARAM_ALG_ENUM \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_INVALID, HKS_TAG_TYPE_INVALID | 0) \ + /* Base algrithom TAG: 1 - 200 */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ALGORITHM, HKS_TAG_TYPE_UINT | 1) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_PURPOSE, HKS_TAG_TYPE_UINT | 2) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_SIZE, HKS_TAG_TYPE_UINT | 3) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_DIGEST, HKS_TAG_TYPE_UINT | 4) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_PADDING, HKS_TAG_TYPE_UINT | 5) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_BLOCK_MODE, HKS_TAG_TYPE_UINT | 6) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_TYPE, HKS_TAG_TYPE_UINT | 7) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ASSOCIATED_DATA, HKS_TAG_TYPE_BYTES | 8) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_NONCE, HKS_TAG_TYPE_BYTES | 9) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IV, HKS_TAG_TYPE_BYTES | 10) \ + /* Key derivation TAG */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_INFO, HKS_TAG_TYPE_BYTES | 11) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_SALT, HKS_TAG_TYPE_BYTES | 12) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_PWD, HKS_TAG_TYPE_BYTES | 13) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ITERATION, HKS_TAG_TYPE_UINT | 14) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_GENERATE_TYPE, HKS_TAG_TYPE_UINT | 15) /* choose from enum HksKeyGenerateType */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_DERIVE_MAIN_KEY, HKS_TAG_TYPE_BYTES | 16) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_DERIVE_FACTOR, HKS_TAG_TYPE_BYTES | 17) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_DERIVE_ALG, HKS_TAG_TYPE_UINT | 18) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_AGREE_ALG, HKS_TAG_TYPE_UINT | 19) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_AGREE_PUBLIC_KEY_IS_KEY_ALIAS, HKS_TAG_TYPE_BOOL | 20) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_AGREE_PRIVATE_KEY_ALIAS, HKS_TAG_TYPE_BYTES | 21) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_AGREE_PUBLIC_KEY, HKS_TAG_TYPE_BYTES | 22) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_ALIAS, HKS_TAG_TYPE_BYTES | 23) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_DERIVE_KEY_SIZE, HKS_TAG_TYPE_UINT | 24) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IMPORT_KEY_TYPE, HKS_TAG_TYPE_UINT | 25) /* choose from enum HksImportKeyType */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_UNWRAP_ALGORITHM_SUITE, HKS_TAG_TYPE_UINT | 26) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_CIPHER_TEXT, HKS_TAG_TYPE_BYTES | 27) \ + /* parameters required by HuksCoreChipsetPlatformDecrypt */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_PEER_PUBLIC_KEY, HKS_TAG_TYPE_BYTES | 28) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_DERIVE_AGREE_KEY_STORAGE_FLAG, HKS_TAG_TYPE_UINT | 29) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_RSA_PSS_SALT_LEN_TYPE, HKS_TAG_TYPE_UINT | 30) /* only supported for PSS padding */\ + /* Key authentication related TAG: 201 - 300 */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ACTIVE_DATETIME, HKS_TAG_TYPE_ULONG | 201) \ + /* Date when new "messages" should not be created. */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ORIGINATION_EXPIRE_DATETIME, HKS_TAG_TYPE_ULONG | 202) \ + /* Date when existing "messages" should not be used. */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_USAGE_EXPIRE_DATETIME, HKS_TAG_TYPE_ULONG | 203) \ + /* Key creation time */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_CREATION_DATETIME, HKS_TAG_TYPE_ULONG | 204) \ + /* Other authentication related TAG: 301 - 500 */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ALL_USERS, HKS_TAG_TYPE_BOOL | 301) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_USER_ID, HKS_TAG_TYPE_UINT | 302) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_NO_AUTH_REQUIRED, HKS_TAG_TYPE_BOOL | 303) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_USER_AUTH_TYPE, HKS_TAG_TYPE_UINT | 304) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_AUTH_TIMEOUT, HKS_TAG_TYPE_UINT | 305) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_AUTH_TOKEN, HKS_TAG_TYPE_BYTES | 306) \ + /* Key secure access control and user auth TAG */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_AUTH_ACCESS_TYPE, HKS_TAG_TYPE_UINT | 307) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_SECURE_SIGN_TYPE, HKS_TAG_TYPE_UINT | 308) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_CHALLENGE_TYPE, HKS_TAG_TYPE_UINT | 309) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_CHALLENGE_POS, HKS_TAG_TYPE_UINT | 310) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_AUTH_PURPOSE, HKS_TAG_TYPE_UINT | 311) \ + /* Attestation related TAG: 501 - 600 */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_CHALLENGE, HKS_TAG_TYPE_BYTES | 501) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_APPLICATION_ID, HKS_TAG_TYPE_BYTES | 502) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_BRAND, HKS_TAG_TYPE_BYTES | 503) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_DEVICE, HKS_TAG_TYPE_BYTES | 504) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_PRODUCT, HKS_TAG_TYPE_BYTES | 505) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_SERIAL, HKS_TAG_TYPE_BYTES | 506) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_IMEI, HKS_TAG_TYPE_BYTES | 507) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_MEID, HKS_TAG_TYPE_BYTES | 508) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_MANUFACTURER, HKS_TAG_TYPE_BYTES | 509) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_MODEL, HKS_TAG_TYPE_BYTES | 510) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_ALIAS, HKS_TAG_TYPE_BYTES | 511) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_SOCID, HKS_TAG_TYPE_BYTES | 512) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_UDID, HKS_TAG_TYPE_BYTES | 513) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO, HKS_TAG_TYPE_BYTES | 514) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_ID_VERSION_INFO, HKS_TAG_TYPE_BYTES | 515) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ATTESTATION_BASE64, HKS_TAG_TYPE_BOOL | 516) \ + /* Extention TAG: 1001 - 9999 */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IS_KEY_ALIAS, HKS_TAG_TYPE_BOOL | 1001) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_STORAGE_FLAG, HKS_TAG_TYPE_UINT | 1002) /* choose from enum HksKeyStorageType */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IS_ALLOWED_WRAP, HKS_TAG_TYPE_BOOL | 1003) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_WRAP_TYPE, HKS_TAG_TYPE_UINT | 1004) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_AUTH_ID, HKS_TAG_TYPE_BYTES | 1005) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_ROLE, HKS_TAG_TYPE_UINT | 1006) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_FLAG, HKS_TAG_TYPE_UINT | 1007) /* choose from enum HksKeyFlag */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IS_ASYNCHRONIZED, HKS_TAG_TYPE_UINT | 1008) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_SECURE_KEY_ALIAS, HKS_TAG_TYPE_BOOL | 1009) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_SECURE_KEY_UUID, HKS_TAG_TYPE_BYTES | 1010) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_DOMAIN, HKS_TAG_TYPE_UINT | 1011) \ + /* Inner-use TAG: 10001 - 10999 */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_PACKAGE_NAME, HKS_TAG_TYPE_BYTES | 10002) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ACCESS_TIME, HKS_TAG_TYPE_UINT | 10003) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_USES_TIME, HKS_TAG_TYPE_UINT | 10004) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_CRYPTO_CTX, HKS_TAG_TYPE_ULONG | 10005) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_PAYLOAD_LEN, HKS_TAG_TYPE_UINT | 10008) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_AE_TAG, HKS_TAG_TYPE_BYTES | 10009) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IS_KEY_HANDLE, HKS_TAG_TYPE_ULONG | 10010) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_INIT_CHALLENGE, HKS_TAG_TYPE_BYTES | 10011) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IS_USER_AUTH_ACCESS, HKS_TAG_TYPE_BOOL | 10012) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_USER_AUTH_CHALLENGE, HKS_TAG_TYPE_BYTES | 10013) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_USER_AUTH_ENROLL_ID_INFO, HKS_TAG_TYPE_BYTES | 10014) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_USER_AUTH_SECURE_UID, HKS_TAG_TYPE_BYTES | 10015) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_AUTH_RESULT, HKS_TAG_TYPE_INT | 10016) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IF_NEED_APPEND_AUTH_INFO, HKS_TAG_TYPE_BOOL | 10017) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_VERIFIED_AUTH_TOKEN, HKS_TAG_TYPE_BYTES | 10018) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_IS_APPEND_UPDATE_DATA, HKS_TAG_TYPE_BOOL | 10019) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_ACCESS_TIME, HKS_TAG_TYPE_ULONG | 10020) \ + /* TAGs used for paramSetOut */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_SYMMETRIC_KEY_DATA, HKS_TAG_TYPE_BYTES | 20001) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ASYMMETRIC_PUBLIC_KEY_DATA, HKS_TAG_TYPE_BYTES | 20002) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_ASYMMETRIC_PRIVATE_KEY_DATA, HKS_TAG_TYPE_BYTES | 20003) \ + +#define HKS_ASSIGN_PARAM_FILE_ENUM \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_PROCESS_NAME, HKS_TAG_TYPE_BYTES | 10001) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY, HKS_TAG_TYPE_BYTES | 10006) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_KEY_VERSION, HKS_TAG_TYPE_UINT | 10007) \ + /* Os version related TAG */\ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_OS_VERSION, HKS_TAG_TYPE_UINT | 10101) \ + HKS_ASSIGN_ENUM_VALUE(HKS_TAG_OS_PATCHLEVEL, HKS_TAG_TYPE_UINT | 10102) \ + +/** +* @brief hks Tag +*/ enum HksTag { - /* Invalid TAG */ - HKS_TAG_INVALID = HKS_TAG_TYPE_INVALID | 0, - - /* Base algrithom TAG: 1 - 200 */ - HKS_TAG_ALGORITHM = HKS_TAG_TYPE_UINT | 1, - HKS_TAG_PURPOSE = HKS_TAG_TYPE_UINT | 2, - HKS_TAG_KEY_SIZE = HKS_TAG_TYPE_UINT | 3, - HKS_TAG_DIGEST = HKS_TAG_TYPE_UINT | 4, - HKS_TAG_PADDING = HKS_TAG_TYPE_UINT | 5, - HKS_TAG_BLOCK_MODE = HKS_TAG_TYPE_UINT | 6, - HKS_TAG_KEY_TYPE = HKS_TAG_TYPE_UINT | 7, - HKS_TAG_ASSOCIATED_DATA = HKS_TAG_TYPE_BYTES | 8, - HKS_TAG_NONCE = HKS_TAG_TYPE_BYTES | 9, - HKS_TAG_IV = HKS_TAG_TYPE_BYTES | 10, - - /* Key derivation TAG */ - HKS_TAG_INFO = HKS_TAG_TYPE_BYTES | 11, - HKS_TAG_SALT = HKS_TAG_TYPE_BYTES | 12, - HKS_TAG_PWD = HKS_TAG_TYPE_BYTES | 13, - HKS_TAG_ITERATION = HKS_TAG_TYPE_UINT | 14, - - HKS_TAG_KEY_GENERATE_TYPE = HKS_TAG_TYPE_UINT | 15, /* choose from enum HksKeyGenerateType */ - HKS_TAG_DERIVE_MAIN_KEY = HKS_TAG_TYPE_BYTES | 16, - HKS_TAG_DERIVE_FACTOR = HKS_TAG_TYPE_BYTES | 17, - HKS_TAG_DERIVE_ALG = HKS_TAG_TYPE_UINT | 18, - HKS_TAG_AGREE_ALG = HKS_TAG_TYPE_UINT | 19, - HKS_TAG_AGREE_PUBLIC_KEY_IS_KEY_ALIAS = HKS_TAG_TYPE_BOOL | 20, - HKS_TAG_AGREE_PRIVATE_KEY_ALIAS = HKS_TAG_TYPE_BYTES | 21, - HKS_TAG_AGREE_PUBLIC_KEY = HKS_TAG_TYPE_BYTES | 22, - HKS_TAG_KEY_ALIAS = HKS_TAG_TYPE_BYTES | 23, - HKS_TAG_DERIVE_KEY_SIZE = HKS_TAG_TYPE_UINT | 24, - HKS_TAG_IMPORT_KEY_TYPE = HKS_TAG_TYPE_UINT | 25, /* choose from enum HksImportKeyType */ - HKS_TAG_UNWRAP_ALGORITHM_SUITE = HKS_TAG_TYPE_UINT | 26, - - /* - * Key authentication related TAG: 201 - 300 - * - * Start of validity + /** + * HUKS tags for alg enum */ - HKS_TAG_ACTIVE_DATETIME = HKS_TAG_TYPE_ULONG | 201, - - /* Date when new "messages" should not be created. */ - HKS_TAG_ORIGINATION_EXPIRE_DATETIME = HKS_TAG_TYPE_ULONG | 202, - - /* Date when existing "messages" should not be used. */ - HKS_TAG_USAGE_EXPIRE_DATETIME = HKS_TAG_TYPE_ULONG | 203, - - /* Key creation time */ - HKS_TAG_CREATION_DATETIME = HKS_TAG_TYPE_ULONG | 204, + HKS_ASSIGN_PARAM_ALG_ENUM - /* Other authentication related TAG: 301 - 500 */ - HKS_TAG_ALL_USERS = HKS_TAG_TYPE_BOOL | 301, - HKS_TAG_USER_ID = HKS_TAG_TYPE_UINT | 302, - HKS_TAG_NO_AUTH_REQUIRED = HKS_TAG_TYPE_BOOL | 303, - HKS_TAG_USER_AUTH_TYPE = HKS_TAG_TYPE_UINT | 304, - HKS_TAG_AUTH_TIMEOUT = HKS_TAG_TYPE_UINT | 305, - HKS_TAG_AUTH_TOKEN = HKS_TAG_TYPE_BYTES | 306, - - /* - * Key secure access control and user auth TAG - */ - HKS_TAG_KEY_AUTH_ACCESS_TYPE = HKS_TAG_TYPE_UINT | 307, - HKS_TAG_KEY_SECURE_SIGN_TYPE = HKS_TAG_TYPE_UINT | 308, - HKS_TAG_CHALLENGE_TYPE = HKS_TAG_TYPE_UINT | 309, - HKS_TAG_CHALLENGE_POS = HKS_TAG_TYPE_UINT | 310, - - /* Attestation related TAG: 501 - 600 */ - HKS_TAG_ATTESTATION_CHALLENGE = HKS_TAG_TYPE_BYTES | 501, - HKS_TAG_ATTESTATION_APPLICATION_ID = HKS_TAG_TYPE_BYTES | 502, - HKS_TAG_ATTESTATION_ID_BRAND = HKS_TAG_TYPE_BYTES | 503, - HKS_TAG_ATTESTATION_ID_DEVICE = HKS_TAG_TYPE_BYTES | 504, - HKS_TAG_ATTESTATION_ID_PRODUCT = HKS_TAG_TYPE_BYTES | 505, - HKS_TAG_ATTESTATION_ID_SERIAL = HKS_TAG_TYPE_BYTES | 506, - HKS_TAG_ATTESTATION_ID_IMEI = HKS_TAG_TYPE_BYTES | 507, - HKS_TAG_ATTESTATION_ID_MEID = HKS_TAG_TYPE_BYTES | 508, - HKS_TAG_ATTESTATION_ID_MANUFACTURER = HKS_TAG_TYPE_BYTES | 509, - HKS_TAG_ATTESTATION_ID_MODEL = HKS_TAG_TYPE_BYTES | 510, - HKS_TAG_ATTESTATION_ID_ALIAS = HKS_TAG_TYPE_BYTES | 511, - HKS_TAG_ATTESTATION_ID_SOCID = HKS_TAG_TYPE_BYTES | 512, - HKS_TAG_ATTESTATION_ID_UDID = HKS_TAG_TYPE_BYTES | 513, - HKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO = HKS_TAG_TYPE_BYTES | 514, - HKS_TAG_ATTESTATION_ID_VERSION_INFO = HKS_TAG_TYPE_BYTES | 515, - HKS_TAG_ATTESTATION_BASE64 = HKS_TAG_TYPE_BOOL | 516, - - /* - * Other reserved TAG: 601 - 1000 - * - * Extention TAG: 1001 - 9999 - */ - HKS_TAG_IS_KEY_ALIAS = HKS_TAG_TYPE_BOOL | 1001, - HKS_TAG_KEY_STORAGE_FLAG = HKS_TAG_TYPE_UINT | 1002, /* choose from enum HksKeyStorageType */ - HKS_TAG_IS_ALLOWED_WRAP = HKS_TAG_TYPE_BOOL | 1003, - HKS_TAG_KEY_WRAP_TYPE = HKS_TAG_TYPE_UINT | 1004, - HKS_TAG_KEY_AUTH_ID = HKS_TAG_TYPE_BYTES | 1005, - HKS_TAG_KEY_ROLE = HKS_TAG_TYPE_UINT | 1006, - HKS_TAG_KEY_FLAG = HKS_TAG_TYPE_UINT | 1007, /* choose from enum HksKeyFlag */ - HKS_TAG_IS_ASYNCHRONIZED = HKS_TAG_TYPE_UINT | 1008, - HKS_TAG_SECURE_KEY_ALIAS = HKS_TAG_TYPE_BOOL | 1009, - HKS_TAG_SECURE_KEY_UUID = HKS_TAG_TYPE_BYTES | 1010, - HKS_TAG_KEY_DOMAIN = HKS_TAG_TYPE_UINT | 1011, - - /* Inner-use TAG: 10001 - 10999 */ - HKS_TAG_PROCESS_NAME = HKS_TAG_TYPE_BYTES | 10001, - HKS_TAG_PACKAGE_NAME = HKS_TAG_TYPE_BYTES | 10002, - HKS_TAG_ACCESS_TIME = HKS_TAG_TYPE_UINT | 10003, - HKS_TAG_USES_TIME = HKS_TAG_TYPE_UINT | 10004, - HKS_TAG_CRYPTO_CTX = HKS_TAG_TYPE_ULONG | 10005, - HKS_TAG_KEY = HKS_TAG_TYPE_BYTES | 10006, - HKS_TAG_KEY_VERSION = HKS_TAG_TYPE_UINT | 10007, - HKS_TAG_PAYLOAD_LEN = HKS_TAG_TYPE_UINT | 10008, - HKS_TAG_AE_TAG = HKS_TAG_TYPE_BYTES | 10009, - HKS_TAG_IS_KEY_HANDLE = HKS_TAG_TYPE_ULONG | 10010, - HKS_TAG_KEY_INIT_CHALLENGE = HKS_TAG_TYPE_BYTES | 10011, - HKS_TAG_IS_USER_AUTH_ACCESS = HKS_TAG_TYPE_BOOL | 10012, - HKS_TAG_USER_AUTH_CHALLENGE = HKS_TAG_TYPE_BYTES | 10013, - HKS_TAG_USER_AUTH_ENROLL_ID_INFO = HKS_TAG_TYPE_BYTES | 10014, - HKS_TAG_USER_AUTH_SECURE_UID = HKS_TAG_TYPE_BYTES | 10015, - HKS_TAG_KEY_AUTH_RESULT = HKS_TAG_TYPE_INT | 10016, - HKS_TAG_IF_NEED_APPEND_AUTH_INFO = HKS_TAG_TYPE_BOOL | 10017, - HKS_TAG_VERIFIED_AUTH_TOKEN = HKS_TAG_TYPE_BYTES | 10018, - HKS_TAG_IS_APPEND_UPDATE_DATA = HKS_TAG_TYPE_BOOL | 10019, - HKS_TAG_KEY_ACCESS_TIME = HKS_TAG_TYPE_ULONG | 10020, - - /* Os version related TAG */ - HKS_TAG_OS_VERSION = HKS_TAG_TYPE_UINT | 10101, - HKS_TAG_OS_PATCHLEVEL = HKS_TAG_TYPE_UINT | 10102, - - /* - * Reversed TAGs for SOTER: 11000 - 12000 - * - * Other TAGs: 20001 - N - * TAGs used for paramSetOut + /** + * HUKS tags for key file enum */ - HKS_TAG_SYMMETRIC_KEY_DATA = HKS_TAG_TYPE_BYTES | 20001, - HKS_TAG_ASYMMETRIC_PUBLIC_KEY_DATA = HKS_TAG_TYPE_BYTES | 20002, - HKS_TAG_ASYMMETRIC_PRIVATE_KEY_DATA = HKS_TAG_TYPE_BYTES | 20003, + HKS_ASSIGN_PARAM_FILE_ENUM }; +/** +* @brief hks blob +*/ struct HksBlob { uint32_t size; uint8_t *data; }; +/** +* @brief hks param +*/ struct HksParam { uint32_t tag; union { @@ -546,22 +648,34 @@ struct HksParam { }; }; +/** +* @brief hks param set +*/ struct HksParamSet { uint32_t paramSetSize; uint32_t paramsCnt; struct HksParam params[]; }; +/** +* @brief hks certificate chain +*/ struct HksCertChain { struct HksBlob *certs; uint32_t certsCount; }; +/** +* @brief hks key info +*/ struct HksKeyInfo { struct HksBlob alias; struct HksParamSet *paramSet; }; +/** +* @brief hks public key info +*/ struct HksPubKeyInfo { enum HksKeyAlg keyAlg; uint32_t keySize; @@ -570,6 +684,9 @@ struct HksPubKeyInfo { uint32_t placeHolder; }; +/** +* @brief hks rsa key material +*/ struct HksKeyMaterialRsa { enum HksKeyAlg keyAlg; uint32_t keySize; @@ -578,6 +695,9 @@ struct HksKeyMaterialRsa { uint32_t dSize; }; +/** +* @brief hks ecc key material +*/ struct HksKeyMaterialEcc { enum HksKeyAlg keyAlg; uint32_t keySize; @@ -586,6 +706,9 @@ struct HksKeyMaterialEcc { uint32_t zSize; }; +/** +* @brief hks dsa key material +*/ struct HksKeyMaterialDsa { enum HksKeyAlg keyAlg; uint32_t keySize; @@ -596,6 +719,9 @@ struct HksKeyMaterialDsa { uint32_t gSize; }; +/** +* @brief hks dh key material +*/ struct HksKeyMaterialDh { enum HksKeyAlg keyAlg; uint32_t keySize; @@ -604,6 +730,9 @@ struct HksKeyMaterialDh { uint32_t reserved; }; +/** +* @brief hks 25519 key material +*/ struct HksKeyMaterial25519 { enum HksKeyAlg keyAlg; uint32_t keySize; @@ -612,20 +741,51 @@ struct HksKeyMaterial25519 { uint32_t reserved; }; -typedef struct __attribute__((__packed__)) HksUserAuthToken { - uint32_t version; +/** +* @brief hks user auth token plaintext data +*/ +typedef struct HksPlaintextData { uint8_t challenge[TOKEN_SIZE]; - uint64_t secureUid; - uint64_t enrolledId; - uint64_t credentialId; uint64_t time; uint32_t authTrustLevel; uint32_t authType; uint32_t authMode; uint32_t securityLevel; +} __attribute__((__packed__)) HksPlaintextData; + +/** +* @brief hks user auth token ciphertext data +*/ +typedef struct HksCiphertextData { + int32_t userId; + uint64_t secureUid; + uint64_t enrolledId; + uint64_t credentialId; +} __attribute__((__packed__)) HksCiphertextData; + +/** +* @brief hks user auth token +*/ +typedef struct __attribute__((__packed__)) HksUserAuthToken { + uint32_t version; + HksPlaintextData plaintextData; + HksCiphertextData ciphertextData; + uint8_t tag[HKS_AE_TAG_LEN]; + uint8_t iv[HKS_AE_NONCE_LEN]; uint8_t sign[SHA256_SIGN_LEN]; } __attribute__((__packed__)) HksUserAuthToken; +/** +* @brief hks user auth token key +*/ +struct HksAuthTokenKey { + uint8_t macKey[HKS_KEY_BLOB_AT_KEY_BYTES]; + uint8_t cipherKey[HKS_KEY_BLOB_AT_KEY_BYTES]; +}; + +/** +* @brief hks secure sign auth info +*/ typedef struct __attribute__((__packed__)) HksSecureSignAuthInfo { uint32_t userAuthType; uint64_t authenticatorId; @@ -640,6 +800,9 @@ typedef struct __attribute__((__packed__)) HksSecureSignAuthInfo { #define HKS_MAX_KEY_LEN (HKS_KEY_BYTES(HKS_RSA_KEY_SIZE_4096) * HKS_KEY_MATERIAL_NUM) #define HKS_MAX_KEY_MATERIAL_LEN (sizeof(struct HksPubKeyInfo) + HKS_MAX_KEY_LEN + HKS_AE_TAG_LEN) +/** +* @brief hks store header info +*/ struct HksStoreHeaderInfo { uint16_t version; uint16_t keyCount; @@ -649,6 +812,9 @@ struct HksStoreHeaderInfo { uint8_t hmac[HKS_HMAC_DIGEST_SHA512_LEN]; }; +/** +* @brief hks store key info +*/ struct HksStoreKeyInfo { uint16_t keyInfoLen; /* current keyinfo len */ uint16_t keySize; /* keySize of key from crypto hal after encrypted */ @@ -667,6 +833,9 @@ struct HksStoreKeyInfo { uint8_t authIdSize; }; +/** +* @brief hks 25519 key pair +*/ struct Hks25519KeyPair { uint32_t publicBufferSize; uint32_t privateBufferSize; @@ -690,6 +859,13 @@ static inline int32_t CheckBlob(const struct HksBlob *blob) return HKS_SUCCESS; } +/** +* @brief hks chipset platform decrypt scene +*/ +enum HksChipsetPlatformDecryptScene { + HKS_CHIPSET_PLATFORM_DECRYPT_SCENE_TA_TO_TA = 1, +}; + #ifdef __cplusplus } #endif diff --git a/mock/innerkits/ipc/ipc_core/include/ipc_object_proxy.h b/mock/innerkits/ipc/ipc_core/include/ipc_object_proxy.h index cf2ca6520469ced32ac8c875e06591d565a0cc62..3754d9b064f405e8a785432107f6d6196ae3d378 100644 --- a/mock/innerkits/ipc/ipc_core/include/ipc_object_proxy.h +++ b/mock/innerkits/ipc/ipc_core/include/ipc_object_proxy.h @@ -35,8 +35,6 @@ public: return true; }; - bool IsObjectDead() const; - int32_t GetObjectRefCount() override; int Dump(int fd, const std::vector &args) override; @@ -66,18 +64,18 @@ public: int InvokeListenThread(MessageParcel &data, MessageParcel &reply); int32_t NoticeServiceDie(); - std::string GetPidAndUidInfo(); - - std::string GetDataBusName(); - std::string TransDataBusName(uint32_t uid, uint32_t pid); + int GetPidUid(MessageParcel &reply); + std::string GetSessionName(); + std::string GetSessionNameForPidUid(uint32_t uid, uint32_t pid); + std::string GetGrantedSessionName(); int GetProto() const; void WaitForInit(); - std::u16string GetInterfaceDescriptor(); private: void MarkObjectDied(); int SendLocalRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &optionoption); int SendRequestInner(bool isLocal, uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + void ClearDeathRecipients(); #ifndef CONFIG_IPC_SINGLE void SetProto(int proto); @@ -88,7 +86,7 @@ private: int32_t IncRefToRemote(); - int GetSessionFromDBinderService(); + int GetProtoInfo(); bool AddDbinderDeathRecipient(); diff --git a/mock/innerkits/ipc/ipc_core/include/ipc_object_stub.h b/mock/innerkits/ipc/ipc_core/include/ipc_object_stub.h index 61ecd9aa401c9a4daa57a5f76fd1406a817e8ecd..a3f677ce0472662c13d3ab6fb3ffec6344237f69 100644 --- a/mock/innerkits/ipc/ipc_core/include/ipc_object_stub.h +++ b/mock/innerkits/ipc/ipc_core/include/ipc_object_stub.h @@ -64,8 +64,12 @@ public: uint32_t GetCallingTokenID(); + uint64_t GetCallingFullTokenID(); + uint32_t GetFirstTokenID(); + uint64_t GetFirstFullTokenID(); + virtual int OnRemoteDump(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); virtual int32_t ProcessProto(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); @@ -76,16 +80,15 @@ public: int32_t InvokerThread(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); int32_t NoticeServiceDie(MessageParcel &data, MessageParcel &reply, MessageOption &option); int32_t InvokerDataBusThread(MessageParcel &data, MessageParcel &reply); - int32_t IncStubRefs(MessageParcel &data, MessageParcel &reply); - int32_t DecStubRefs(MessageParcel &data, MessageParcel &reply); int32_t AddAuthInfo(MessageParcel &data, MessageParcel &reply, uint32_t code); private: - int32_t GrantDataBusName(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); - int32_t TransDataBusName(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); - std::string CreateDatabusName(int uid, int pid); - std::string GetDataBusName(); - bool IsSamgrCall(uint32_t accessToken); + int GetPidUid(MessageParcel &data, MessageParcel &reply); + std::string GetSessionName(); + int32_t GetSessionNameForPidUid(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + int32_t GetGrantedSessionName(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option); + std::string CreateSessionName(int uid, int pid); + bool IsSamgrCall(); #endif private: bool IsDeviceIdIllegal(const std::string &deviceID); diff --git a/mock/innerkits/ipc/ipc_core/include/ipc_skeleton.h b/mock/innerkits/ipc/ipc_core/include/ipc_skeleton.h index 4ea3c1a3bf9e224ffc41a3aca95f2e86989612ec..822b457d3f9535a7a8a119b80bf2af87367cce15 100644 --- a/mock/innerkits/ipc/ipc_core/include/ipc_skeleton.h +++ b/mock/innerkits/ipc/ipc_core/include/ipc_skeleton.h @@ -39,8 +39,14 @@ public: static uint32_t GetCallingTokenID(); + static uint64_t GetCallingFullTokenID(); + static uint32_t GetFirstTokenID(); + static uint64_t GetFirstFullTokenID(); + + static uint64_t GetSelfTokenID(); + static std::string GetLocalDeviceID(); static std::string GetCallingDeviceID(); diff --git a/mock/innerkits/ipc/ipc_core/include/ipc_types.h b/mock/innerkits/ipc/ipc_core/include/ipc_types.h index 66b46ad1b8ac72b24d874fd4f4b0fe615fc31716..97c4030075be09b60419257b9769ad62eb43f0f1 100644 --- a/mock/innerkits/ipc/ipc_core/include/ipc_types.h +++ b/mock/innerkits/ipc/ipc_core/include/ipc_types.h @@ -35,15 +35,15 @@ enum { SYSPROPS_TRANSACTION = ZIPC_PACK_CHARS('_', 'S', 'P', 'R'), SYNCHRONIZE_REFERENCE = ZIPC_PACK_CHARS('_', 'S', 'Y', 'C'), INVOKE_LISTEN_THREAD = ZIPC_PACK_CHARS('_', 'I', 'L', 'T'), + GET_PID_UID = ZIPC_PACK_CHARS('_', 'G', 'P', 'U'), GET_PROTO_INFO = ZIPC_PACK_CHARS('_', 'G', 'R', 'I'), - GET_UIDPID_INFO = ZIPC_PACK_CHARS('_', 'G', 'U', 'I'), - GRANT_DATABUS_NAME = ZIPC_PACK_CHARS('_', 'G', 'D', 'N'), - TRANS_DATABUS_NAME = ZIPC_PACK_CHARS('_', 'T', 'D', 'N'), + GET_SESSION_NAME = ZIPC_PACK_CHARS('_', 'G', 'S', 'N'), + GET_SESSION_NAME_PID_UID = ZIPC_PACK_CHARS('_', 'G', 'S', 'P'), + GET_GRANTED_SESSION_NAME = ZIPC_PACK_CHARS('_', 'G', 'G', 'S'), DBINDER_OBITUARY_TRANSACTION = ZIPC_PACK_CHARS('_', 'D', 'O', 'T'), DBINDER_INCREFS_TRANSACTION = ZIPC_PACK_CHARS('_', 'D', 'I', 'T'), DBINDER_DECREFS_TRANSACTION = ZIPC_PACK_CHARS('_', 'D', 'D', 'T'), DBINDER_ADD_COMMAUTH = ZIPC_PACK_CHARS('_', 'D', 'A', 'C'), - DBINDER_TRANS_COMMAUTH = ZIPC_PACK_CHARS('_', 'D', 'T', 'C'), TRANS_SYNC = 0, TRANS_ASYNC = 1, }; diff --git a/mock/innerkits/ipc/ipc_core/include/iremote_broker.h b/mock/innerkits/ipc/ipc_core/include/iremote_broker.h index 7105ff7740465454e389109d59597a3791db237f..c09c4d47c21dec46c2e6a5dbf166ec493e991d06 100644 --- a/mock/innerkits/ipc/ipc_core/include/iremote_broker.h +++ b/mock/innerkits/ipc/ipc_core/include/iremote_broker.h @@ -40,18 +40,23 @@ public: class IRemoteBroker : public virtual RefBase { public: IRemoteBroker() = default; - virtual ~IRemoteBroker() = default; + virtual ~IRemoteBroker() override = default; virtual sptr AsObject() = 0; - static inline sptr AsImplement(const sptr &object) - { - (void)object; - return nullptr; - } +}; + +class BrokerDelegatorBase { +public: + BrokerDelegatorBase() = default; + virtual ~BrokerDelegatorBase() = default; + +public: + bool isSoUnloaded = false; + std::u16string descriptor_; }; #define DECLARE_INTERFACE_DESCRIPTOR(DESCRIPTOR) \ - static inline const std::u16string metaDescriptor_ = { DESCRIPTOR }; \ - static inline const std::u16string &GetDescriptor() \ + static constexpr const char16_t *metaDescriptor_ = DESCRIPTOR; \ + static inline const std::u16string GetDescriptor() \ { \ return metaDescriptor_; \ } @@ -61,7 +66,7 @@ class BrokerRegistration { public: static BrokerRegistration &Get(); - bool Register(const std::u16string &descriptor, const Constructor &creator); + bool Register(const std::u16string &descriptor, const Constructor &creator, const BrokerDelegatorBase *object); void Unregister(const std::u16string &descriptor); sptr NewInstance(const std::u16string &descriptor, const sptr &object); @@ -76,12 +81,14 @@ private: BrokerRegistration &operator = (BrokerRegistration &&) = delete; std::mutex creatorMutex_; std::unordered_map creators_; + std::vector objects_; + std::atomic isUnloading = false; }; -template class BrokerDelegator { +template class BrokerDelegator : public BrokerDelegatorBase { public: BrokerDelegator(); - ~BrokerDelegator(); + ~BrokerDelegator() override; private: BrokerDelegator(const BrokerDelegator &) = delete; @@ -94,14 +101,17 @@ template BrokerDelegator::BrokerDelegator() { const std::u16string descriptor = T::GetDescriptor(); BrokerRegistration ®istration = BrokerRegistration::Get(); - registration.Register(descriptor, BrokerCreator()); + if (registration.Register(descriptor, BrokerCreator(), this)) { + descriptor_ = T::GetDescriptor(); + } } template BrokerDelegator::~BrokerDelegator() { - const std::u16string descriptor = T::GetDescriptor(); - BrokerRegistration ®istration = BrokerRegistration::Get(); - registration.Unregister(descriptor); + if (!isSoUnloaded && !descriptor_.empty()) { + BrokerRegistration ®istration = BrokerRegistration::Get(); + registration.Unregister(descriptor_); + } } template inline sptr iface_cast(const sptr &object) diff --git a/mock/innerkits/ipc/ipc_core/include/iremote_object.h b/mock/innerkits/ipc/ipc_core/include/iremote_object.h index 67ef09e1ae44c5b11e85d7276a2194d886b690e1..6e4161b5de81b7daabf9a0d3920e2b9e5461cfdf 100644 --- a/mock/innerkits/ipc/ipc_core/include/iremote_object.h +++ b/mock/innerkits/ipc/ipc_core/include/iremote_object.h @@ -66,7 +66,7 @@ public: virtual bool RemoveDeathRecipient(const sptr &recipient) = 0; - bool Marshalling(Parcel &parcel) const override; + virtual bool Marshalling(Parcel &parcel) const override; static sptr Unmarshalling(Parcel &parcel); diff --git a/mock/innerkits/ipc/libdbinder/include/dbinder_service.h b/mock/innerkits/ipc/libdbinder/include/dbinder_service.h index 4bea9ad31227076498ab1ad1b1653a71ed2fd939..54758c523cca2be4d939e48011ce7f4db64bfc91 100644 --- a/mock/innerkits/ipc/libdbinder/include/dbinder_service.h +++ b/mock/innerkits/ipc/libdbinder/include/dbinder_service.h @@ -54,7 +54,8 @@ struct DHandleEntryTxRx { struct DHandleEntryHead head; uint32_t transType; uint32_t dBinderCode; - uint32_t rpcFeatureSet; + uint16_t fromPort; + uint16_t toPort; uint64_t stubIndex; uint32_t seqNumber; binder_uintptr_t binderObject; @@ -69,7 +70,8 @@ struct DHandleEntryTxRx { struct SessionInfo { uint32_t seqNumber; uint32_t type; - uint32_t rpcFeatureSet; + uint16_t toPort; + uint16_t fromPort; uint64_t stubIndex; uint32_t socketFd; std::string serviceName; @@ -80,16 +82,29 @@ enum DBinderCode { MESSAGE_AS_INVOKER = 1, MESSAGE_AS_REPLY = 2, MESSAGE_AS_OBITUARY = 3, + MESSAGE_AS_REMOTE_ERROR = 4, + MESSAGE_AS_REPLY_TOKENID = 5, }; -enum AfType { - IPV4_TYPE = 1, - IPV6_TYPE = 2, - DATABBUS_TYPE = 3, +enum DBinderErrorCode { + DBINDER_OK = 100, + STUB_INVALID = 101, + SEND_MESSAGE_FAILED = 102, + MAKE_THREADLOCK_FAILED = 103, + WAIT_REPLY_TIMEOUT = 104, + QUERY_REPLY_SESSION_FAILED = 105, + SA_NOT_FOUND = 106, + SA_INVOKE_FAILED = 107, + DEVICEID_INVALID = 108, + SESSION_NAME_NOT_FOUND = 109, + WRITE_PARCEL_FAILED = 110, + INVOKE_STUB_THREAD_FAILED = 111, + SESSION_NAME_INVALID = 112, }; struct ThreadLockInfo { std::mutex mutex; + std::string networkId; std::condition_variable condition; bool ready = false; }; @@ -100,12 +115,14 @@ public: virtual ~DBinderService(); public: static sptr GetInstance(); + static std::string ConvertToSecureDeviceID(const std::string &deviceID); bool StartDBinderService(std::shared_ptr &callbackImpl); sptr MakeRemoteBinder(const std::u16string &serviceName, - const std::string &deviceID, binder_uintptr_t binderObject, uint64_t pid = 0); + const std::string &deviceID, int32_t binderObject, uint32_t pid = 0, uint32_t uid = 0); bool RegisterRemoteProxy(std::u16string serviceName, sptr binderObject); bool RegisterRemoteProxy(std::u16string serviceName, int32_t systemAbilityId); - bool OnRemoteMessageTask(const struct DHandleEntryTxRx *message); + bool OnRemoteMessageTask(std::shared_ptr message); + void AddAsynMessageTask(std::shared_ptr message); std::shared_ptr QuerySessionObject(binder_uintptr_t stub); bool DetachDeathRecipient(sptr object); bool AttachDeathRecipient(sptr object, sptr deathRecipient); @@ -114,32 +131,33 @@ public: bool AttachCallbackProxy(sptr object, DBinderServiceStub *dbStub); int32_t NoticeServiceDie(const std::u16string &serviceName, const std::string &deviceID); int32_t NoticeDeviceDie(const std::string &deviceID); - bool AttachBusNameObject(IPCObjectProxy *proxy, const std::string &name); - bool DetachBusNameObject(IPCObjectProxy *proxy); std::string CreateDatabusName(int uid, int pid); bool DetachProxyObject(binder_uintptr_t binderObject); - std::string QueryBusNameObject(IPCObjectProxy *proxy); + void LoadSystemAbilityComplete(const std::string& srcNetworkId, int32_t systemAbilityId, + const sptr& remoteObject); + bool ProcessOnSessionClosed(std::shared_ptr session); private: static std::shared_ptr GetRemoteListener(); static bool StartRemoteListener(); static void StopRemoteListener(); - static std::string ConvertToSecureDeviceID(const std::string &deviceID); std::u16string GetRegisterService(binder_uintptr_t binderObject); - bool InvokerRemoteDBinder(const sptr stub, uint32_t seqNumber); + int32_t InvokerRemoteDBinder(const sptr stub, uint32_t seqNumber, uint32_t pid, uint32_t uid); bool OnRemoteReplyMessage(const struct DHandleEntryTxRx *replyMessage); + bool OnRemoteErrorMessage(const struct DHandleEntryTxRx *replyMessage); void MakeSessionByReplyMessage(const struct DHandleEntryTxRx *replyMessage); bool OnRemoteInvokerMessage(const struct DHandleEntryTxRx *message); void WakeupThreadByStub(uint32_t seqNumber); void DetachThreadLockInfo(uint32_t seqNumber); - bool AttachThreadLockInfo(uint32_t seqNumber, std::shared_ptr object); + bool AttachThreadLockInfo(uint32_t seqNumber, const std::string &networkId, + std::shared_ptr object); std::shared_ptr QueryThreadLockInfo(uint32_t seqNumber); bool AttachProxyObject(sptr object, binder_uintptr_t binderObject); sptr QueryProxyObject(binder_uintptr_t binderObject); bool DetachSessionObject(binder_uintptr_t stub); bool AttachSessionObject(std::shared_ptr object, binder_uintptr_t stub); sptr FindOrNewProxy(binder_uintptr_t binderObject, int32_t systemAbilityId); - bool SendEntryToRemote(const sptr stub, uint32_t seqNumber); + bool SendEntryToRemote(const sptr stub, uint32_t seqNumber, uint32_t pid, uint32_t uid); uint16_t AllocFreeSocketPort(); std::string GetLocalDeviceID(); bool CheckBinderObject(const sptr &stub, binder_uintptr_t binderObject); @@ -155,38 +173,46 @@ private: std::list FindServicesByDeviceID(const std::string &deviceID); int32_t NoticeServiceDieInner(const std::u16string &serviceName, const std::string &deviceID); uint32_t GetRemoteTransType(); - bool OnRemoteInvokerDataBusMessage(IPCObjectProxy *proxy, struct DHandleEntryTxRx *replyMessage, - std::string &remoteDeviceId, int pid, int uid); + uint32_t OnRemoteInvokerDataBusMessage(IPCObjectProxy *proxy, struct DHandleEntryTxRx *replyMessage, + std::string &remoteDeviceId, int pid, int uid, uint32_t tokenId); bool IsDeviceIdIllegal(const std::string &deviceID); std::string GetDatabusNameByProxy(IPCObjectProxy *proxy); uint32_t GetSeqNumber(); + bool StartThreadPool(); + bool StopThreadPool(); + bool AddAsynTask(const ThreadPool::Task &f); + bool IsSameSession(std::shared_ptr oldSession, std::shared_ptr newSession); bool RegisterRemoteProxyInner(std::u16string serviceName, binder_uintptr_t binder); bool CheckSystemAbilityId(int32_t systemAbilityId); - bool IsSameSession(std::shared_ptr oldSession, std::shared_ptr nowSession); bool HandleInvokeListenThread(IPCObjectProxy *proxy, uint64_t stubIndex, std::string serverSessionName, struct DHandleEntryTxRx *replyMessage); bool ReStartRemoteListener(); - bool ReGrantPermission(const std::string &sessionName); + bool IsSameLoadSaItem(const std::string& srcNetworkId, int32_t systemAbilityId, + std::shared_ptr loadSaItem); + std::shared_ptr PopLoadSaItem(const std::string& srcNetworkId, int32_t systemAbilityId); + void SendMessageToRemote(uint32_t dBinderCode, uint32_t reason, + std::shared_ptr replyMessage); private: DISALLOW_COPY_AND_MOVE(DBinderService); static std::mutex instanceMutex_; - static constexpr int WAIT_FOR_REPLY_MAX_SEC = 4; + static constexpr int WAIT_FOR_REPLY_MAX_SEC = 8; static constexpr int RETRY_TIMES = 2; static std::shared_ptr remoteListener_; static bool mainThreadCreated_; static sptr instance_; std::shared_mutex remoteBinderMutex_; - std::shared_mutex busNameMutex_; std::shared_mutex proxyMutex_; std::shared_mutex deathRecipientMutex_; std::shared_mutex sessionMutex_; + std::shared_mutex loadSaMutex_; std::mutex handleEntryMutex_; std::mutex threadLockMutex_; std::mutex callbackProxyMutex_; std::mutex deathNotificationMutex_; + std::mutex threadPoolMutex_; uint32_t seqNumber_ = 0; /* indicate make remote binder message sequence number, and can be overflow */ std::list> DBinderStubRegisted_; @@ -196,7 +222,9 @@ private: std::map> sessionObject_; std::map, DBinderServiceStub *> noticeProxy_; std::map, sptr> deathRecipients_; - std::map busNameObject_; + bool threadPoolStarted_ = false; + int32_t threadPoolNumber_ = 4; + std::unique_ptr threadPool_ = nullptr; static constexpr int32_t FIRST_SYS_ABILITY_ID = 0x00000001; static constexpr int32_t LAST_SYS_ABILITY_ID = 0x00ffffff; diff --git a/mock/innerkits/ipc/libdbinder/include/dbinder_service_stub.h b/mock/innerkits/ipc/libdbinder/include/dbinder_service_stub.h index 93c8f1267d298aa30a9c974c708b6c93ce41ef24..e502acd4fa2fc5f1a161fdff59338ff2e2c630c4 100644 --- a/mock/innerkits/ipc/libdbinder/include/dbinder_service_stub.h +++ b/mock/innerkits/ipc/libdbinder/include/dbinder_service_stub.h @@ -21,18 +21,22 @@ #include "ipc_object_stub.h" namespace OHOS { +#ifdef BINDER_IPC_32BIT +typedef unsigned int binder_uintptr_t; +#else typedef unsigned long long binder_uintptr_t; +#endif class DBinderServiceStub : public IPCObjectStub { public: - explicit DBinderServiceStub(const std::string& serviceName, const std::string& deviceID, + explicit DBinderServiceStub(const std::string &serviceName, const std::string &deviceID, binder_uintptr_t binderObject); ~DBinderServiceStub(); int32_t ProcessProto(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; - const std::string& GetServiceName(); - const std::string& GetDeviceID(); + const std::string &GetServiceName(); + const std::string &GetDeviceID(); binder_uintptr_t GetBinderObject() const; private: diff --git a/mock/innerkits/native_appdatamgr/native_rdb/include/abs_shared_result_set.h b/mock/innerkits/native_appdatamgr/native_rdb/include/abs_shared_result_set.h index b5c67cc4774152d9e31f871e71092c462db5d259..79dce00b6ad2e0538120b6fc97bab4c442194b6e 100644 --- a/mock/innerkits/native_appdatamgr/native_rdb/include/abs_shared_result_set.h +++ b/mock/innerkits/native_appdatamgr/native_rdb/include/abs_shared_result_set.h @@ -39,6 +39,8 @@ public: int GetInt(int columnIndex, int &value) override; int GetLong(int columnIndex, int64_t &value) override; int GetDouble(int columnIndex, double &value) override; + int GetAsset(int32_t col, ValueObject::Asset &value) override; + int GetAssets(int32_t col, ValueObject::Assets &value) override; int IsColumnNull(int columnIndex, bool &isNull) override; int GetColumnType(int columnIndex, ColumnType &columnType) override; int GoToRow(int position) override; diff --git a/mock/sqlite/include/sqlite3.h b/mock/sqlite/include/sqlite3.h index 9f89fdcc483231f2348f970203a64cd7bcbf39c2..020b3ad8be94f01e465fd5fa8022dfef9aa75b8c 100644 --- a/mock/sqlite/include/sqlite3.h +++ b/mock/sqlite/include/sqlite3.h @@ -288,18 +288,18 @@ typedef struct sqlite3 sqlite3; ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE -typedef SQLITE_INT64_TYPE sqlite_int64; + typedef SQLITE_INT64_TYPE sqlite_int64; # ifdef SQLITE_UINT64_TYPE -typedef SQLITE_UINT64_TYPE sqlite_uint64; + typedef SQLITE_UINT64_TYPE sqlite_uint64; # else -typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; + typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; # endif #elif defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 sqlite_int64; -typedef unsigned __int64 sqlite_uint64; + typedef __int64 sqlite_int64; + typedef unsigned __int64 sqlite_uint64; #else -typedef long long int sqlite_int64; -typedef unsigned long long int sqlite_uint64; + typedef long long int sqlite_int64; + typedef unsigned long long int sqlite_uint64; #endif typedef sqlite_int64 sqlite3_int64; typedef sqlite_uint64 sqlite3_uint64; @@ -423,11 +423,11 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**); ** */ SQLITE_API int sqlite3_exec( - sqlite3*, /* An open database */ - const char *sql, /* SQL to be evaluated */ - int (*callback)(void*,int,char**,char**), /* Callback function */ - void *, /* 1st argument to callback */ - char **errmsg /* Error msg written here */ + sqlite3*, /* An open database */ + const char *sql, /* SQL to be evaluated */ + int (*callback)(void*,int,char**,char**), /* Callback function */ + void *, /* 1st argument to callback */ + char **errmsg /* Error msg written here */ ); /* @@ -721,7 +721,7 @@ SQLITE_API int sqlite3_exec( */ typedef struct sqlite3_file sqlite3_file; struct sqlite3_file { - const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ + const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ }; /* @@ -820,29 +820,29 @@ struct sqlite3_file { */ typedef struct sqlite3_io_methods sqlite3_io_methods; struct sqlite3_io_methods { - int iVersion; - int (*xClose)(sqlite3_file*); - int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); - int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); - int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); - int (*xSync)(sqlite3_file*, int flags); - int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); - int (*xLock)(sqlite3_file*, int); - int (*xUnlock)(sqlite3_file*, int); - int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); - int (*xFileControl)(sqlite3_file*, int op, void *pArg); - int (*xSectorSize)(sqlite3_file*); - int (*xDeviceCharacteristics)(sqlite3_file*); - /* Methods above are valid for version 1 */ - int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); - int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); - void (*xShmBarrier)(sqlite3_file*); - int (*xShmUnmap)(sqlite3_file*, int deleteFlag); - /* Methods above are valid for version 2 */ - int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); - int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); - /* Methods above are valid for version 3 */ - /* Additional methods may be added in future releases */ + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + /* Methods above are valid for version 1 */ + int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); + int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); + void (*xShmBarrier)(sqlite3_file*); + int (*xShmUnmap)(sqlite3_file*, int deleteFlag); + /* Methods above are valid for version 2 */ + int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); + int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p); + /* Methods above are valid for version 3 */ + /* Additional methods may be added in future releases */ }; /* @@ -1425,38 +1425,38 @@ typedef struct sqlite3_api_routines sqlite3_api_routines; typedef struct sqlite3_vfs sqlite3_vfs; typedef void (*sqlite3_syscall_ptr)(void); struct sqlite3_vfs { - int iVersion; /* Structure version number (currently 3) */ - int szOsFile; /* Size of subclassed sqlite3_file */ - int mxPathname; /* Maximum file pathname length */ - sqlite3_vfs *pNext; /* Next registered VFS */ - const char *zName; /* Name of this virtual file system */ - void *pAppData; /* Pointer to application-specific data */ - int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, - int flags, int *pOutFlags); - int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); - int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); - int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); - void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); - void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); - void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); - void (*xDlClose)(sqlite3_vfs*, void*); - int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); - int (*xSleep)(sqlite3_vfs*, int microseconds); - int (*xCurrentTime)(sqlite3_vfs*, double*); - int (*xGetLastError)(sqlite3_vfs*, int, char *); - /* + int iVersion; /* Structure version number (currently 3) */ + int szOsFile; /* Size of subclassed sqlite3_file */ + int mxPathname; /* Maximum file pathname length */ + sqlite3_vfs *pNext; /* Next registered VFS */ + const char *zName; /* Name of this virtual file system */ + void *pAppData; /* Pointer to application-specific data */ + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + int (*xGetLastError)(sqlite3_vfs*, int, char *); + /* ** The methods above are in version 1 of the sqlite_vfs object ** definition. Those that follow are added in version 2 or later */ - int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); - /* + int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); + /* ** The methods above are in versions 1 and 2 of the sqlite_vfs object. ** Those below are for version 3 and greater. */ - int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); - sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); - const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); - /* + int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); + const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); + /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in future versions. The iVersion ** value will increment whenever this happens. @@ -1722,14 +1722,14 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); */ typedef struct sqlite3_mem_methods sqlite3_mem_methods; struct sqlite3_mem_methods { - void *(*xMalloc)(int); /* Memory allocation function */ - void (*xFree)(void*); /* Free a prior allocation */ - void *(*xRealloc)(void*,int); /* Resize an allocation */ - int (*xSize)(void*); /* Return the size of an allocation */ - int (*xRoundup)(int); /* Round up request size to allocation size */ - int (*xInit)(void*); /* Initialize the memory allocator */ - void (*xShutdown)(void*); /* Deinitialize the memory allocator */ - void *pAppData; /* Argument to xInit() and xShutdown() */ + void *(*xMalloc)(int); /* Memory allocation function */ + void (*xFree)(void*); /* Free a prior allocation */ + void *(*xRealloc)(void*,int); /* Resize an allocation */ + int (*xSize)(void*); /* Return the size of an allocation */ + int (*xRoundup)(int); /* Round up request size to allocation size */ + int (*xInit)(void*); /* Initialize the memory allocator */ + void (*xShutdown)(void*); /* Deinitialize the memory allocator */ + void *pAppData; /* Argument to xInit() and xShutdown() */ }; /* @@ -2833,12 +2833,12 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); ** [sqlite3_errmsg()]. */ SQLITE_API int sqlite3_get_table( - sqlite3 *db, /* An open database */ - const char *zSql, /* SQL to be evaluated */ - char ***pazResult, /* Results of the query */ - int *pnRow, /* Number of result rows written here */ - int *pnColumn, /* Number of result columns written here */ - char **pzErrmsg /* Error msg written here */ + sqlite3 *db, /* An open database */ + const char *zSql, /* SQL to be evaluated */ + char ***pazResult, /* Results of the query */ + int *pnRow, /* Number of result rows written here */ + int *pnColumn, /* Number of result columns written here */ + char **pzErrmsg /* Error msg written here */ ); SQLITE_API void sqlite3_free_table(char **result); @@ -3108,15 +3108,15 @@ SQLITE_API void sqlite3_randomness(int N, void *P); ** sqlite3_prepare_v2() to reprepare a statement after a schema change. */ SQLITE_API int sqlite3_set_authorizer( - sqlite3*, - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), - void *pUserData + sqlite3*, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pUserData ); #ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK SQLITE_API int sqlite3_set_droptable_handle( - sqlite3 *db, - void (*xFunc)(sqlite3*,const char*,const char*) + sqlite3 *db, + void (*xFunc)(sqlite3*,const char*,const char*) ); #endif @@ -3223,9 +3223,9 @@ SQLITE_API int sqlite3_set_droptable_handle( ** profile callback. */ SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*, - void(*xTrace)(void*,const char*), void*); + void(*xTrace)(void*,const char*), void*); SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, - void(*xProfile)(void*,const char*,sqlite3_uint64), void*); + void(*xProfile)(void*,const char*,sqlite3_uint64), void*); /* ** CAPI3REF: SQL Trace Event Codes @@ -3314,10 +3314,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*, ** are deprecated. */ SQLITE_API int sqlite3_trace_v2( - sqlite3*, - unsigned uMask, - int(*xCallback)(unsigned,void*,void*,void*), - void *pCtx + sqlite3*, + unsigned uMask, + int(*xCallback)(unsigned,void*,void*,void*), + void *pCtx ); /* @@ -3625,18 +3625,18 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); ** See also: [sqlite3_temp_directory] */ SQLITE_API int sqlite3_open( - const char *filename, /* Database filename (UTF-8) */ - sqlite3 **ppDb /* OUT: SQLite db handle */ + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ ); SQLITE_API int sqlite3_open16( - const void *filename, /* Database filename (UTF-16) */ - sqlite3 **ppDb /* OUT: SQLite db handle */ + const void *filename, /* Database filename (UTF-16) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ ); SQLITE_API int sqlite3_open_v2( - const char *filename, /* Database filename (UTF-8) */ - sqlite3 **ppDb, /* OUT: SQLite db handle */ - int flags, /* Flags */ - const char *zVfs /* Name of VFS module to use */ + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ ); /* @@ -3806,11 +3806,11 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*); ** invoked prior to calling sqlite3_free_filename(Y). */ SQLITE_API char *sqlite3_create_filename( - const char *zDatabase, - const char *zJournal, - const char *zWal, - int nParam, - const char **azParam + const char *zDatabase, + const char *zJournal, + const char *zWal, + int nParam, + const char **azParam ); SQLITE_API void sqlite3_free_filename(char*); @@ -4149,48 +4149,48 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** sqlite3_prepare_v3() with a zero prepFlags parameter. */ SQLITE_API int sqlite3_prepare( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare_v2( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare_v3( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16_v2( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16_v3( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nByte, /* Maximum length of zSql in bytes. */ - unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); /* @@ -4516,7 +4516,7 @@ typedef struct sqlite3_context sqlite3_context; */ SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, - void(*)(void*)); + void(*)(void*)); SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); @@ -4524,7 +4524,7 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, - void(*)(void*), unsigned char encoding); + void(*)(void*), unsigned char encoding); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); @@ -5271,47 +5271,47 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); ** statement in which the function is running. */ SQLITE_API int sqlite3_create_function( - sqlite3 *db, - const char *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*) + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) ); SQLITE_API int sqlite3_create_function16( - sqlite3 *db, - const void *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*) + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) ); SQLITE_API int sqlite3_create_function_v2( - sqlite3 *db, - const char *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void(*xDestroy)(void*) + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*) ); SQLITE_API int sqlite3_create_window_function( - sqlite3 *db, - const char *zFunctionName, - int nArg, - int eTextRep, - void *pApp, - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void (*xValue)(sqlite3_context*), - void (*xInverse)(sqlite3_context*,int,sqlite3_value**), - void(*xDestroy)(void*) + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInverse)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*) ); /* @@ -5414,7 +5414,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), - void*,sqlite3_int64); + void*,sqlite3_int64); #endif /* @@ -5889,7 +5889,7 @@ typedef void (*sqlite3_destructor_type)(void*); */ SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*, - sqlite3_uint64,void(*)(void*)); + sqlite3_uint64,void(*)(void*)); SQLITE_API void sqlite3_result_double(sqlite3_context*, double); SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); @@ -5901,7 +5901,7 @@ SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, - void(*)(void*), unsigned char encoding); + void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); @@ -6007,26 +6007,26 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int); ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. */ SQLITE_API int sqlite3_create_collation( - sqlite3*, - const char *zName, - int eTextRep, - void *pArg, - int(*xCompare)(void*,int,const void*,int,const void*) + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) ); SQLITE_API int sqlite3_create_collation_v2( - sqlite3*, - const char *zName, - int eTextRep, - void *pArg, - int(*xCompare)(void*,int,const void*,int,const void*), - void(*xDestroy)(void*) + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDestroy)(void*) ); SQLITE_API int sqlite3_create_collation16( - sqlite3*, - const void *zName, - int eTextRep, - void *pArg, - int(*xCompare)(void*,int,const void*,int,const void*) + sqlite3*, + const void *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) ); /* @@ -6057,14 +6057,14 @@ SQLITE_API int sqlite3_create_collation16( ** [sqlite3_create_collation_v2()]. */ SQLITE_API int sqlite3_collation_needed( - sqlite3*, - void*, - void(*)(void*,sqlite3*,int eTextRep,const char*) + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const char*) ); SQLITE_API int sqlite3_collation_needed16( - sqlite3*, - void*, - void(*)(void*,sqlite3*,int eTextRep,const void*) + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const void*) ); #ifdef SQLITE_HAS_CODEC @@ -6076,13 +6076,13 @@ SQLITE_API int sqlite3_collation_needed16( ** of SQLite. */ SQLITE_API int sqlite3_key( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The key */ + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The key */ ); SQLITE_API int sqlite3_key_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The key */ + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The key */ ); /* @@ -6094,13 +6094,13 @@ SQLITE_API int sqlite3_key_v2( ** of SQLite. */ SQLITE_API int sqlite3_rekey( - sqlite3 *db, /* Database to be rekeyed */ - const void *pKey, int nKey /* The new key */ + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The new key */ ); SQLITE_API int sqlite3_rekey_v2( - sqlite3 *db, /* Database to be rekeyed */ - const char *zDbName, /* Name of the database */ - const void *pKey, int nKey /* The new key */ + sqlite3 *db, /* Database to be rekeyed */ + const char *zDbName, /* Name of the database */ + const void *pKey, int nKey /* The new key */ ); #endif @@ -6111,7 +6111,7 @@ SQLITE_API int sqlite3_rekey_v2( ** activated, none of the CEROD routines will work. */ SQLITE_API void sqlite3_activate_cerod( - const char *zPassPhrase /* Activation phrase */ + const char *zPassPhrase /* Activation phrase */ ); #endif @@ -6249,8 +6249,8 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory; ** UTF-8 or UTF-16, respectively. */ SQLITE_API int sqlite3_win32_set_directory( - unsigned long type, /* Identifier for directory being set or reset */ - void *zValue /* New value for directory being set or reset */ + unsigned long type, /* Identifier for directory being set or reset */ + void *zValue /* New value for directory being set or reset */ ); SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue); SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue); @@ -6519,10 +6519,10 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); ** */ SQLITE_API int sqlite3_autovacuum_pages( - sqlite3 *db, - unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), - void*, - void(*)(void*) + sqlite3 *db, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, + void(*)(void*) ); @@ -6576,9 +6576,9 @@ SQLITE_API int sqlite3_autovacuum_pages( ** and [sqlite3_preupdate_hook()] interfaces. */ SQLITE_API void *sqlite3_update_hook( - sqlite3*, - void(*)(void *,int ,char const *,char const *,sqlite3_int64), - void* + sqlite3*, + void(*)(void *,int ,char const *,char const *,sqlite3_int64), + void* ); /* @@ -6801,15 +6801,15 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); ** any errors are encountered while loading the schema. */ SQLITE_API int sqlite3_table_column_metadata( - sqlite3 *db, /* Connection handle */ - const char *zDbName, /* Database name or NULL */ - const char *zTableName, /* Table name */ - const char *zColumnName, /* Column name */ - char const **pzDataType, /* OUTPUT: Declared data type */ - char const **pzCollSeq, /* OUTPUT: Collation sequence name */ - int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ - int *pPrimaryKey, /* OUTPUT: True if column part of PK */ - int *pAutoinc /* OUTPUT: True if column is auto-increment */ + sqlite3 *db, /* Connection handle */ + const char *zDbName, /* Database name or NULL */ + const char *zTableName, /* Table name */ + const char *zColumnName, /* Column name */ + char const **pzDataType, /* OUTPUT: Declared data type */ + char const **pzCollSeq, /* OUTPUT: Collation sequence name */ + int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int *pPrimaryKey, /* OUTPUT: True if column part of PK */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ ); /* @@ -6857,10 +6857,10 @@ SQLITE_API int sqlite3_table_column_metadata( ** See also the [load_extension() SQL function]. */ SQLITE_API int sqlite3_load_extension( - sqlite3 *db, /* Load the extension into this database connection */ - const char *zFile, /* Name of the shared library containing extension */ - const char *zProc, /* Entry point. Derived from zFile if 0 */ - char **pzErrMsg /* Put error message here if not 0 */ + sqlite3 *db, /* Load the extension into this database connection */ + const char *zFile, /* Name of the shared library containing extension */ + const char *zProc, /* Entry point. Derived from zFile if 0 */ + char **pzErrMsg /* Put error message here if not 0 */ ); /* @@ -6982,41 +6982,41 @@ typedef struct sqlite3_module sqlite3_module; ** any database connection. */ struct sqlite3_module { - int iVersion; - int (*xCreate)(sqlite3*, void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVTab, char**); - int (*xConnect)(sqlite3*, void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVTab, char**); - int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); - int (*xDisconnect)(sqlite3_vtab *pVTab); - int (*xDestroy)(sqlite3_vtab *pVTab); - int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); - int (*xClose)(sqlite3_vtab_cursor*); - int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, - int argc, sqlite3_value **argv); - int (*xNext)(sqlite3_vtab_cursor*); - int (*xEof)(sqlite3_vtab_cursor*); - int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); - int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); - int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); - int (*xBegin)(sqlite3_vtab *pVTab); - int (*xSync)(sqlite3_vtab *pVTab); - int (*xCommit)(sqlite3_vtab *pVTab); - int (*xRollback)(sqlite3_vtab *pVTab); - int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, - void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), - void **ppArg); - int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); - /* The methods above are in version 1 of the sqlite_module object. Those + int iVersion; + int (*xCreate)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xConnect)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); + int (*xDisconnect)(sqlite3_vtab *pVTab); + int (*xDestroy)(sqlite3_vtab *pVTab); + int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); + int (*xClose)(sqlite3_vtab_cursor*); + int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, + int argc, sqlite3_value **argv); + int (*xNext)(sqlite3_vtab_cursor*); + int (*xEof)(sqlite3_vtab_cursor*); + int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); + int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); + int (*xBegin)(sqlite3_vtab *pVTab); + int (*xSync)(sqlite3_vtab *pVTab); + int (*xCommit)(sqlite3_vtab *pVTab); + int (*xRollback)(sqlite3_vtab *pVTab); + int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg); + int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + /* The methods above are in version 1 of the sqlite_module object. Those ** below are for version 2 and greater. */ - int (*xSavepoint)(sqlite3_vtab *pVTab, int); - int (*xRelease)(sqlite3_vtab *pVTab, int); - int (*xRollbackTo)(sqlite3_vtab *pVTab, int); - /* The methods above are in versions 1 and 2 of the sqlite_module object. + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); + /* The methods above are in versions 1 and 2 of the sqlite_module object. ** Those below are for version 3 and greater. */ - int (*xShadowName)(const char*); + int (*xShadowName)(const char*); }; /* @@ -7122,35 +7122,35 @@ struct sqlite3_module { ** 3009000. */ struct sqlite3_index_info { - /* Inputs */ - int nConstraint; /* Number of entries in aConstraint */ - struct sqlite3_index_constraint { - int iColumn; /* Column constrained. -1 for ROWID */ - unsigned char op; /* Constraint operator */ - unsigned char usable; /* True if this constraint is usable */ - int iTermOffset; /* Used internally - xBestIndex should ignore */ - } *aConstraint; /* Table of WHERE clause constraints */ - int nOrderBy; /* Number of terms in the ORDER BY clause */ - struct sqlite3_index_orderby { - int iColumn; /* Column number */ - unsigned char desc; /* True for DESC. False for ASC. */ - } *aOrderBy; /* The ORDER BY clause */ - /* Outputs */ - struct sqlite3_index_constraint_usage { - int argvIndex; /* if >0, constraint is part of argv to xFilter */ - unsigned char omit; /* Do not code a test for this constraint */ - } *aConstraintUsage; - int idxNum; /* Number used to identify the index */ - char *idxStr; /* String, possibly obtained from sqlite3_malloc */ - int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ - int orderByConsumed; /* True if output is already ordered */ - double estimatedCost; /* Estimated cost of using this index */ - /* Fields below are only available in SQLite 3.8.2 and later */ - sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ - /* Fields below are only available in SQLite 3.9.0 and later */ - int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ - /* Fields below are only available in SQLite 3.10.0 and later */ - sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ + /* Inputs */ + int nConstraint; /* Number of entries in aConstraint */ + struct sqlite3_index_constraint { + int iColumn; /* Column constrained. -1 for ROWID */ + unsigned char op; /* Constraint operator */ + unsigned char usable; /* True if this constraint is usable */ + int iTermOffset; /* Used internally - xBestIndex should ignore */ + } *aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct sqlite3_index_orderby { + int iColumn; /* Column number */ + unsigned char desc; /* True for DESC. False for ASC. */ + } *aOrderBy; /* The ORDER BY clause */ + /* Outputs */ + struct sqlite3_index_constraint_usage { + int argvIndex; /* if >0, constraint is part of argv to xFilter */ + unsigned char omit; /* Do not code a test for this constraint */ + } *aConstraintUsage; + int idxNum; /* Number used to identify the index */ + char *idxStr; /* String, possibly obtained from sqlite3_malloc */ + int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ + int orderByConsumed; /* True if output is already ordered */ + double estimatedCost; /* Estimated cost of using this index */ + /* Fields below are only available in SQLite 3.8.2 and later */ + sqlite3_int64 estimatedRows; /* Estimated number of rows returned */ + /* Fields below are only available in SQLite 3.9.0 and later */ + int idxFlags; /* Mask of SQLITE_INDEX_SCAN_* flags */ + /* Fields below are only available in SQLite 3.10.0 and later */ + sqlite3_uint64 colUsed; /* Input: Mask of columns used by statement */ }; /* @@ -7219,17 +7219,17 @@ struct sqlite3_index_info { ** See also: [sqlite3_drop_modules()] */ SQLITE_API int sqlite3_create_module( - sqlite3 *db, /* SQLite connection to register module with */ - const char *zName, /* Name of the module */ - const sqlite3_module *p, /* Methods for the module */ - void *pClientData /* Client data for xCreate/xConnect */ + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData /* Client data for xCreate/xConnect */ ); SQLITE_API int sqlite3_create_module_v2( - sqlite3 *db, /* SQLite connection to register module with */ - const char *zName, /* Name of the module */ - const sqlite3_module *p, /* Methods for the module */ - void *pClientData, /* Client data for xCreate/xConnect */ - void(*xDestroy)(void*) /* Module destructor function */ + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData, /* Client data for xCreate/xConnect */ + void(*xDestroy)(void*) /* Module destructor function */ ); /* @@ -7245,8 +7245,8 @@ SQLITE_API int sqlite3_create_module_v2( ** See also: [sqlite3_create_module()] */ SQLITE_API int sqlite3_drop_modules( - sqlite3 *db, /* Remove modules from this connection */ - const char **azKeep /* Except, do not remove the ones named here */ + sqlite3 *db, /* Remove modules from this connection */ + const char **azKeep /* Except, do not remove the ones named here */ ); /* @@ -7268,10 +7268,10 @@ SQLITE_API int sqlite3_drop_modules( ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { - const sqlite3_module *pModule; /* The module for this virtual table */ - int nRef; /* Number of open cursors */ - char *zErrMsg; /* Error message from sqlite3_mprintf() */ - /* Virtual table implementations will typically add additional fields */ + const sqlite3_module *pModule; /* The module for this virtual table */ + int nRef; /* Number of open cursors */ + char *zErrMsg; /* Error message from sqlite3_mprintf() */ + /* Virtual table implementations will typically add additional fields */ }; /* @@ -7292,8 +7292,8 @@ struct sqlite3_vtab { ** are common to all implementations. */ struct sqlite3_vtab_cursor { - sqlite3_vtab *pVtab; /* Virtual table of this cursor */ - /* Virtual table implementations will typically add additional fields */ + sqlite3_vtab *pVtab; /* Virtual table of this cursor */ + /* Virtual table implementations will typically add additional fields */ }; /* @@ -7433,13 +7433,13 @@ typedef struct sqlite3_blob sqlite3_blob; ** [sqlite3_blob_bytes()], [sqlite3_blob_write()]. */ SQLITE_API int sqlite3_blob_open( - sqlite3*, - const char *zDb, - const char *zTable, - const char *zColumn, - sqlite3_int64 iRow, - int flags, - sqlite3_blob **ppBlob + sqlite3*, + const char *zDb, + const char *zTable, + const char *zColumn, + sqlite3_int64 iRow, + int flags, + sqlite3_blob **ppBlob ); /* @@ -7797,15 +7797,15 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); */ typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; struct sqlite3_mutex_methods { - int (*xMutexInit)(void); - int (*xMutexEnd)(void); - sqlite3_mutex *(*xMutexAlloc)(int); - void (*xMutexFree)(sqlite3_mutex *); - void (*xMutexEnter)(sqlite3_mutex *); - int (*xMutexTry)(sqlite3_mutex *); - void (*xMutexLeave)(sqlite3_mutex *); - int (*xMutexHeld)(sqlite3_mutex *); - int (*xMutexNotheld)(sqlite3_mutex *); + int (*xMutexInit)(void); + int (*xMutexEnd)(void); + sqlite3_mutex *(*xMutexAlloc)(int); + void (*xMutexFree)(sqlite3_mutex *); + void (*xMutexEnter)(sqlite3_mutex *); + int (*xMutexTry)(sqlite3_mutex *); + void (*xMutexLeave)(sqlite3_mutex *); + int (*xMutexHeld)(sqlite3_mutex *); + int (*xMutexNotheld)(sqlite3_mutex *); }; /* @@ -8202,10 +8202,10 @@ SQLITE_API char *sqlite3_str_value(sqlite3_str*); */ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); SQLITE_API int sqlite3_status64( - int op, - sqlite3_int64 *pCurrent, - sqlite3_int64 *pHighwater, - int resetFlag + int op, + sqlite3_int64 *pCurrent, + sqlite3_int64 *pHighwater, + int resetFlag ); @@ -8553,8 +8553,8 @@ typedef struct sqlite3_pcache sqlite3_pcache; */ typedef struct sqlite3_pcache_page sqlite3_pcache_page; struct sqlite3_pcache_page { - void *pBuf; /* The content of the page */ - void *pExtra; /* Extra information associated with the page */ + void *pBuf; /* The content of the page */ + void *pExtra; /* Extra information associated with the page */ }; /* @@ -8718,20 +8718,20 @@ struct sqlite3_pcache_page { */ typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2; struct sqlite3_pcache_methods2 { - int iVersion; - void *pArg; - int (*xInit)(void*); - void (*xShutdown)(void*); - sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); - void (*xCachesize)(sqlite3_pcache*, int nCachesize); - int (*xPagecount)(sqlite3_pcache*); - sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); - void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); - void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, - unsigned oldKey, unsigned newKey); - void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); - void (*xDestroy)(sqlite3_pcache*); - void (*xShrink)(sqlite3_pcache*); + int iVersion; + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int szExtra, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard); + void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*, + unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); + void (*xShrink)(sqlite3_pcache*); }; /* @@ -8741,17 +8741,17 @@ struct sqlite3_pcache_methods2 { */ typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; struct sqlite3_pcache_methods { - void *pArg; - int (*xInit)(void*); - void (*xShutdown)(void*); - sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); - void (*xCachesize)(sqlite3_pcache*, int nCachesize); - int (*xPagecount)(sqlite3_pcache*); - void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); - void (*xUnpin)(sqlite3_pcache*, void*, int discard); - void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); - void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); - void (*xDestroy)(sqlite3_pcache*); + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, void*, int discard); + void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); }; @@ -8954,10 +8954,10 @@ typedef struct sqlite3_backup sqlite3_backup; ** possible that they return invalid values. */ SQLITE_API sqlite3_backup *sqlite3_backup_init( - sqlite3 *pDest, /* Destination database handle */ - const char *zDestName, /* Destination database name */ - sqlite3 *pSource, /* Source database handle */ - const char *zSourceName /* Source database name */ + sqlite3 *pDest, /* Destination database handle */ + const char *zDestName, /* Destination database name */ + sqlite3 *pSource, /* Source database handle */ + const char *zSourceName /* Source database name */ ); SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); @@ -9080,9 +9080,9 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); ** SQLITE_LOCKED.)^ */ SQLITE_API int sqlite3_unlock_notify( - sqlite3 *pBlocked, /* Waiting connection */ - void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ - void *pNotifyArg /* Argument to pass to xNotify */ + sqlite3 *pBlocked, /* Waiting connection */ + void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ + void *pNotifyArg /* Argument to pass to xNotify */ ); @@ -9196,9 +9196,9 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); ** overwrite any prior [sqlite3_wal_hook()] settings. */ SQLITE_API void *sqlite3_wal_hook( - sqlite3*, - int(*)(void *,sqlite3*,const char*,int), - void* + sqlite3*, + int(*)(void *,sqlite3*,const char*,int), + void* ); /* @@ -9347,11 +9347,11 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); ** from SQL. */ SQLITE_API int sqlite3_wal_checkpoint_v2( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Name of attached database (or NULL) */ - int eMode, /* SQLITE_CHECKPOINT_* value */ - int *pnLog, /* OUT: Size of WAL log in frames */ - int *pnCkpt /* OUT: Total number of frames checkpointed */ + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ ); /* @@ -9611,10 +9611,10 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_ ** See also: [sqlite3_stmt_scanstatus_reset()] */ SQLITE_API int sqlite3_stmt_scanstatus( - sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ - int idx, /* Index of loop to report on */ - int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ - void *pOut /* Result written here */ + sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ + int idx, /* Index of loop to report on */ + int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ + void *pOut /* Result written here */ ); /* @@ -9755,17 +9755,17 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*); */ #if defined(SQLITE_ENABLE_PREUPDATE_HOOK) SQLITE_API void *sqlite3_preupdate_hook( - sqlite3 *db, - void(*xPreUpdate)( - void *pCtx, /* Copy of third arg to preupdate_hook() */ - sqlite3 *db, /* Database handle */ - int op, /* SQLITE_UPDATE, DELETE or INSERT */ - char const *zDb, /* Database name */ - char const *zName, /* Table name */ - sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ - sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ - ), - void* + sqlite3 *db, + void(*xPreUpdate)( + void *pCtx, /* Copy of third arg to preupdate_hook() */ + sqlite3 *db, /* Database handle */ + int op, /* SQLITE_UPDATE, DELETE or INSERT */ + char const *zDb, /* Database name */ + char const *zName, /* Table name */ + sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ + sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ + ), + void* ); SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **); SQLITE_API int sqlite3_preupdate_count(sqlite3 *); @@ -9808,7 +9808,7 @@ SQLITE_API int sqlite3_system_errno(sqlite3*); ** the most recent version. */ typedef struct sqlite3_snapshot { - unsigned char hidden[48]; + unsigned char hidden[48]; } sqlite3_snapshot; /* @@ -9855,9 +9855,9 @@ typedef struct sqlite3_snapshot { ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( - sqlite3 *db, - const char *zSchema, - sqlite3_snapshot **ppSnapshot + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot **ppSnapshot ); /* @@ -9904,9 +9904,9 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( ** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open( - sqlite3 *db, - const char *zSchema, - sqlite3_snapshot *pSnapshot + sqlite3 *db, + const char *zSchema, + sqlite3_snapshot *pSnapshot ); /* @@ -9948,8 +9948,8 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*); ** [SQLITE_ENABLE_SNAPSHOT] option. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp( - sqlite3_snapshot *p1, - sqlite3_snapshot *p2 + sqlite3_snapshot *p1, + sqlite3_snapshot *p2 ); /* @@ -10014,10 +10014,10 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c ** [SQLITE_OMIT_DESERIALIZE] option. */ SQLITE_API unsigned char *sqlite3_serialize( - sqlite3 *db, /* The database connection */ - const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ - sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ - unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ + sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ + unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ ); /* @@ -10070,12 +10070,12 @@ SQLITE_API unsigned char *sqlite3_serialize( ** [SQLITE_OMIT_DESERIALIZE] option. */ SQLITE_API int sqlite3_deserialize( - sqlite3 *db, /* The database connection */ - const char *zSchema, /* Which DB to reopen with the deserialization */ - unsigned char *pData, /* The serialized database content */ - sqlite3_int64 szDb, /* Number bytes in the deserialization */ - sqlite3_int64 szBuf, /* Total size of buffer pData[] */ - unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ + sqlite3 *db, /* The database connection */ + const char *zSchema, /* Which DB to reopen with the deserialization */ + unsigned char *pData, /* The serialized database content */ + sqlite3_int64 szDb, /* Number bytes in the deserialization */ + sqlite3_int64 szBuf, /* Total size of buffer pData[] */ + unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */ ); /* @@ -10145,9 +10145,9 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info; ** SQLITE_RTREE_INT_ONLY compile-time option. */ #ifdef SQLITE_RTREE_INT_ONLY -typedef sqlite3_int64 sqlite3_rtree_dbl; + typedef sqlite3_int64 sqlite3_rtree_dbl; #else -typedef double sqlite3_rtree_dbl; + typedef double sqlite3_rtree_dbl; #endif /* @@ -10157,10 +10157,10 @@ typedef double sqlite3_rtree_dbl; ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ SQLITE_API int sqlite3_rtree_geometry_callback( - sqlite3 *db, - const char *zGeom, - int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), - void *pContext + sqlite3 *db, + const char *zGeom, + int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*), + void *pContext ); @@ -10169,11 +10169,11 @@ SQLITE_API int sqlite3_rtree_geometry_callback( ** argument to callbacks registered using rtree_geometry_callback(). */ struct sqlite3_rtree_geometry { - void *pContext; /* Copy of pContext passed to s_r_g_c() */ - int nParam; /* Size of array aParam[] */ - sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ - void *pUser; /* Callback implementation user data */ - void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ + void *pContext; /* Copy of pContext passed to s_r_g_c() */ + int nParam; /* Size of array aParam[] */ + sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */ + void *pUser; /* Callback implementation user data */ + void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; /* @@ -10183,11 +10183,11 @@ struct sqlite3_rtree_geometry { ** SELECT ... FROM WHERE MATCH $zQueryFunc(... params ...) */ SQLITE_API int sqlite3_rtree_query_callback( - sqlite3 *db, - const char *zQueryFunc, - int (*xQueryFunc)(sqlite3_rtree_query_info*), - void *pContext, - void (*xDestructor)(void*) + sqlite3 *db, + const char *zQueryFunc, + int (*xQueryFunc)(sqlite3_rtree_query_info*), + void *pContext, + void (*xDestructor)(void*) ); @@ -10201,23 +10201,23 @@ SQLITE_API int sqlite3_rtree_query_callback( ** sqlite3_rtree_geometry. */ struct sqlite3_rtree_query_info { - void *pContext; /* pContext from when function registered */ - int nParam; /* Number of function parameters */ - sqlite3_rtree_dbl *aParam; /* value of function parameters */ - void *pUser; /* callback can use this, if desired */ - void (*xDelUser)(void*); /* function to free pUser */ - sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ - unsigned int *anQueue; /* Number of pending entries in the queue */ - int nCoord; /* Number of coordinates */ - int iLevel; /* Level of current node or entry */ - int mxLevel; /* The largest iLevel value in the tree */ - sqlite3_int64 iRowid; /* Rowid for current entry */ - sqlite3_rtree_dbl rParentScore; /* Score of parent node */ - int eParentWithin; /* Visibility of parent node */ - int eWithin; /* OUT: Visibility */ - sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ - /* The following fields are only available in 3.8.11 and later */ - sqlite3_value **apSqlParam; /* Original SQL values of parameters */ + void *pContext; /* pContext from when function registered */ + int nParam; /* Number of function parameters */ + sqlite3_rtree_dbl *aParam; /* value of function parameters */ + void *pUser; /* callback can use this, if desired */ + void (*xDelUser)(void*); /* function to free pUser */ + sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */ + unsigned int *anQueue; /* Number of pending entries in the queue */ + int nCoord; /* Number of coordinates */ + int iLevel; /* Level of current node or entry */ + int mxLevel; /* The largest iLevel value in the tree */ + sqlite3_int64 iRowid; /* Rowid for current entry */ + sqlite3_rtree_dbl rParentScore; /* Score of parent node */ + int eParentWithin; /* Visibility of parent node */ + int eWithin; /* OUT: Visibility */ + sqlite3_rtree_dbl rScore; /* OUT: Write the score here */ + /* The following fields are only available in 3.8.11 and later */ + sqlite3_value **apSqlParam; /* Original SQL values of parameters */ }; /* @@ -10296,9 +10296,9 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter; ** to the database when the session object is created. */ SQLITE_API int sqlite3session_create( - sqlite3 *db, /* Database handle */ - const char *zDb, /* Name of db (e.g. "main") */ - sqlite3_session **ppSession /* OUT: New session object */ + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of db (e.g. "main") */ + sqlite3_session **ppSession /* OUT: New session object */ ); /* @@ -10458,8 +10458,8 @@ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect) ** sqlite_stat1 table that are part of a changeset or patchset. */ SQLITE_API int sqlite3session_attach( - sqlite3_session *pSession, /* Session object */ - const char *zTab /* Table name */ + sqlite3_session *pSession, /* Session object */ + const char *zTab /* Table name */ ); /* @@ -10473,12 +10473,12 @@ SQLITE_API int sqlite3session_attach( ** attached, xFilter will not be called again. */ SQLITE_API void sqlite3session_table_filter( - sqlite3_session *pSession, /* Session object */ - int(*xFilter)( - void *pCtx, /* Copy of third arg to _filter_table() */ - const char *zTab /* Table name */ - ), - void *pCtx /* First argument passed to xFilter */ + sqlite3_session *pSession, /* Session object */ + int(*xFilter)( + void *pCtx, /* Copy of third arg to _filter_table() */ + const char *zTab /* Table name */ + ), + void *pCtx /* First argument passed to xFilter */ ); /* @@ -10587,9 +10587,9 @@ SQLITE_API void sqlite3session_table_filter( ** resulting changeset will contain an UPDATE change that updates both fields. */ SQLITE_API int sqlite3session_changeset( - sqlite3_session *pSession, /* Session object */ - int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ - void **ppChangeset /* OUT: Buffer containing changeset */ + sqlite3_session *pSession, /* Session object */ + int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ + void **ppChangeset /* OUT: Buffer containing changeset */ ); /* @@ -10666,10 +10666,10 @@ SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession ** sqlite3_free(). */ SQLITE_API int sqlite3session_diff( - sqlite3_session *pSession, - const char *zFromDb, - const char *zTbl, - char **pzErrMsg + sqlite3_session *pSession, + const char *zFromDb, + const char *zTbl, + char **pzErrMsg ); @@ -10703,9 +10703,9 @@ SQLITE_API int sqlite3session_diff( ** they were attached to the session object). */ SQLITE_API int sqlite3session_patchset( - sqlite3_session *pSession, /* Session object */ - int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ - void **ppPatchset /* OUT: Buffer containing patchset */ + sqlite3_session *pSession, /* Session object */ + int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */ + void **ppPatchset /* OUT: Buffer containing patchset */ ); /* @@ -10775,15 +10775,15 @@ SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession); ** and therefore subject to change. */ SQLITE_API int sqlite3changeset_start( - sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ - int nChangeset, /* Size of changeset blob in bytes */ - void *pChangeset /* Pointer to blob containing changeset */ + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset /* Pointer to blob containing changeset */ ); SQLITE_API int sqlite3changeset_start_v2( - sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ - int nChangeset, /* Size of changeset blob in bytes */ - void *pChangeset, /* Pointer to blob containing changeset */ - int flags /* SESSION_CHANGESETSTART_* flags */ + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ ); /* @@ -10858,11 +10858,11 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter); ** be trusted in this case. */ SQLITE_API int sqlite3changeset_op( - sqlite3_changeset_iter *pIter, /* Iterator object */ - const char **pzTab, /* OUT: Pointer to table name */ - int *pnCol, /* OUT: Number of columns in table */ - int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ - int *pbIndirect /* OUT: True for an 'indirect' change */ + sqlite3_changeset_iter *pIter, /* Iterator object */ + const char **pzTab, /* OUT: Pointer to table name */ + int *pnCol, /* OUT: Number of columns in table */ + int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */ + int *pbIndirect /* OUT: True for an 'indirect' change */ ); /* @@ -10892,9 +10892,9 @@ SQLITE_API int sqlite3changeset_op( ** above. */ SQLITE_API int sqlite3changeset_pk( - sqlite3_changeset_iter *pIter, /* Iterator object */ - unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ - int *pnCol /* OUT: Number of entries in output array */ + sqlite3_changeset_iter *pIter, /* Iterator object */ + unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */ + int *pnCol /* OUT: Number of entries in output array */ ); /* @@ -10923,9 +10923,9 @@ SQLITE_API int sqlite3changeset_pk( ** is returned and *ppValue is set to NULL. */ SQLITE_API int sqlite3changeset_old( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int iVal, /* Column number */ - sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */ ); /* @@ -10957,9 +10957,9 @@ SQLITE_API int sqlite3changeset_old( ** is returned and *ppValue is set to NULL. */ SQLITE_API int sqlite3changeset_new( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int iVal, /* Column number */ - sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */ ); /* @@ -10985,9 +10985,9 @@ SQLITE_API int sqlite3changeset_new( ** is returned and *ppValue is set to NULL. */ SQLITE_API int sqlite3changeset_conflict( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int iVal, /* Column number */ - sqlite3_value **ppValue /* OUT: Value from conflicting row */ + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int iVal, /* Column number */ + sqlite3_value **ppValue /* OUT: Value from conflicting row */ ); /* @@ -11002,8 +11002,8 @@ SQLITE_API int sqlite3changeset_conflict( ** In all other cases this function returns SQLITE_MISUSE. */ SQLITE_API int sqlite3changeset_fk_conflicts( - sqlite3_changeset_iter *pIter, /* Changeset iterator */ - int *pnOut /* OUT: Number of FK violations */ + sqlite3_changeset_iter *pIter, /* Changeset iterator */ + int *pnOut /* OUT: Number of FK violations */ ); @@ -11068,8 +11068,8 @@ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter); ** changeset. If it is not, the results are undefined. */ SQLITE_API int sqlite3changeset_invert( - int nIn, const void *pIn, /* Input changeset */ - int *pnOut, void **ppOut /* OUT: Inverse of input */ + int nIn, const void *pIn, /* Input changeset */ + int *pnOut, void **ppOut /* OUT: Inverse of input */ ); /* @@ -11099,12 +11099,12 @@ SQLITE_API int sqlite3changeset_invert( ** Refer to the sqlite3_changegroup documentation below for details. */ SQLITE_API int sqlite3changeset_concat( - int nA, /* Number of bytes in buffer pA */ - void *pA, /* Pointer to buffer containing changeset A */ - int nB, /* Number of bytes in buffer pB */ - void *pB, /* Pointer to buffer containing changeset B */ - int *pnOut, /* OUT: Number of bytes in output changeset */ - void **ppOut /* OUT: Buffer containing output changeset */ + int nA, /* Number of bytes in buffer pA */ + void *pA, /* Pointer to buffer containing changeset A */ + int nB, /* Number of bytes in buffer pB */ + void *pB, /* Pointer to buffer containing changeset B */ + int *pnOut, /* OUT: Number of bytes in output changeset */ + void **ppOut /* OUT: Buffer containing output changeset */ ); @@ -11258,9 +11258,9 @@ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pDa ** call to sqlite3_free(). */ SQLITE_API int sqlite3changegroup_output( - sqlite3_changegroup*, - int *pnData, /* OUT: Size of output buffer in bytes */ - void **ppData /* OUT: Pointer to output buffer */ + sqlite3_changegroup*, + int *pnData, /* OUT: Size of output buffer in bytes */ + void **ppData /* OUT: Pointer to output buffer */ ); /* @@ -11428,36 +11428,36 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*); ** and therefore subject to change. */ SQLITE_API int sqlite3changeset_apply( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int nChangeset, /* Size of changeset in bytes */ - void *pChangeset, /* Changeset blob */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx /* First argument passed to xConflict */ + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ ); SQLITE_API int sqlite3changeset_apply_v2( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int nChangeset, /* Size of changeset in bytes */ - void *pChangeset, /* Changeset blob */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx, /* First argument passed to xConflict */ - void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* SESSION_CHANGESETAPPLY_* flags */ + sqlite3 *db, /* Apply change to "main" db of this handle */ + int nChangeset, /* Size of changeset in bytes */ + void *pChangeset, /* Changeset blob */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, /* OUT: Rebase data */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* @@ -11701,8 +11701,8 @@ SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew); ** sqlite3changeset_apply_v2(). */ SQLITE_API int sqlite3rebaser_configure( - sqlite3_rebaser*, - int nRebase, const void *pRebase + sqlite3_rebaser*, + int nRebase, const void *pRebase ); /* @@ -11720,9 +11720,9 @@ SQLITE_API int sqlite3rebaser_configure( ** are set to zero and an SQLite error code returned. */ SQLITE_API int sqlite3rebaser_rebase( - sqlite3_rebaser*, - int nIn, const void *pIn, - int *pnOut, void **ppOut + sqlite3_rebaser*, + int nIn, const void *pIn, + int *pnOut, void **ppOut ); /* @@ -11826,71 +11826,71 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p); ** no guarantees are made as to the size of the chunks of data returned. */ SQLITE_API int sqlite3changeset_apply_strm( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ - void *pIn, /* First arg for xInput */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx /* First argument passed to xConflict */ + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx /* First argument passed to xConflict */ ); SQLITE_API int sqlite3changeset_apply_v2_strm( - sqlite3 *db, /* Apply change to "main" db of this handle */ - int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ - void *pIn, /* First arg for xInput */ - int(*xFilter)( - void *pCtx, /* Copy of sixth arg to _apply() */ - const char *zTab /* Table name */ - ), - int(*xConflict)( - void *pCtx, /* Copy of sixth arg to _apply() */ - int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ - sqlite3_changeset_iter *p /* Handle describing change and conflict */ - ), - void *pCtx, /* First argument passed to xConflict */ - void **ppRebase, int *pnRebase, - int flags + sqlite3 *db, /* Apply change to "main" db of this handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */ + void *pIn, /* First arg for xInput */ + int(*xFilter)( + void *pCtx, /* Copy of sixth arg to _apply() */ + const char *zTab /* Table name */ + ), + int(*xConflict)( + void *pCtx, /* Copy of sixth arg to _apply() */ + int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */ + sqlite3_changeset_iter *p /* Handle describing change and conflict */ + ), + void *pCtx, /* First argument passed to xConflict */ + void **ppRebase, int *pnRebase, + int flags ); SQLITE_API int sqlite3changeset_concat_strm( - int (*xInputA)(void *pIn, void *pData, int *pnData), - void *pInA, - int (*xInputB)(void *pIn, void *pData, int *pnData), - void *pInB, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut + int (*xInputA)(void *pIn, void *pData, int *pnData), + void *pInA, + int (*xInputB)(void *pIn, void *pData, int *pnData), + void *pInB, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut ); SQLITE_API int sqlite3changeset_invert_strm( - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut ); SQLITE_API int sqlite3changeset_start_strm( - sqlite3_changeset_iter **pp, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn ); SQLITE_API int sqlite3changeset_start_v2_strm( - sqlite3_changeset_iter **pp, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn, - int flags + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags ); SQLITE_API int sqlite3session_changeset_strm( - sqlite3_session *pSession, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut ); SQLITE_API int sqlite3session_patchset_strm( - sqlite3_session *pSession, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut + sqlite3_session *pSession, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut ); SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*, int (*xInput)(void *pIn, void *pData, int *pnData), @@ -11901,11 +11901,11 @@ SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*, void *pOut ); SQLITE_API int sqlite3rebaser_rebase_strm( - sqlite3_rebaser *pRebaser, - int (*xInput)(void *pIn, void *pData, int *pnData), - void *pIn, - int (*xOutput)(void *pOut, const void *pData, int nData), - void *pOut + sqlite3_rebaser *pRebaser, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int (*xOutput)(void *pOut, const void *pData, int nData), + void *pOut ); /* @@ -11999,16 +11999,16 @@ typedef struct Fts5Context Fts5Context; typedef struct Fts5PhraseIter Fts5PhraseIter; typedef void (*fts5_extension_function)( - const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ - Fts5Context *pFts, /* First arg to pass to pApi functions */ - sqlite3_context *pCtx, /* Context for returning result/error */ - int nVal, /* Number of values in apVal[] array */ - sqlite3_value **apVal /* Array of trailing arguments */ + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ + Fts5Context *pFts, /* First arg to pass to pApi functions */ + sqlite3_context *pCtx, /* Context for returning result/error */ + int nVal, /* Number of values in apVal[] array */ + sqlite3_value **apVal /* Array of trailing arguments */ ); struct Fts5PhraseIter { - const unsigned char *a; - const unsigned char *b; + const unsigned char *a; + const unsigned char *b; }; /* @@ -12223,41 +12223,41 @@ struct Fts5PhraseIter { ** See xPhraseFirstColumn above. */ struct Fts5ExtensionApi { - int iVersion; /* Currently always set to 3 */ + int iVersion; /* Currently always set to 3 */ - void *(*xUserData)(Fts5Context*); + void *(*xUserData)(Fts5Context*); - int (*xColumnCount)(Fts5Context*); - int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); - int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); + int (*xColumnCount)(Fts5Context*); + int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); + int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken); - int (*xTokenize)(Fts5Context*, - const char *pText, int nText, /* Text to tokenize */ - void *pCtx, /* Context passed to xToken() */ - int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ - ); + int (*xTokenize)(Fts5Context*, + const char *pText, int nText, /* Text to tokenize */ + void *pCtx, /* Context passed to xToken() */ + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ + ); - int (*xPhraseCount)(Fts5Context*); - int (*xPhraseSize)(Fts5Context*, int iPhrase); + int (*xPhraseCount)(Fts5Context*); + int (*xPhraseSize)(Fts5Context*, int iPhrase); - int (*xInstCount)(Fts5Context*, int *pnInst); - int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); + int (*xInstCount)(Fts5Context*, int *pnInst); + int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff); - sqlite3_int64 (*xRowid)(Fts5Context*); - int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); - int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); + sqlite3_int64 (*xRowid)(Fts5Context*); + int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn); + int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken); - int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, - int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) - ); - int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); - void *(*xGetAuxdata)(Fts5Context*, int bClear); + int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData, + int(*)(const Fts5ExtensionApi*,Fts5Context*,void*) + ); + int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*)); + void *(*xGetAuxdata)(Fts5Context*, int bClear); - int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); - void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); + int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*); + void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff); - int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); - void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); + int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*); + void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol); }; /* @@ -12459,21 +12459,21 @@ struct Fts5ExtensionApi { typedef struct Fts5Tokenizer Fts5Tokenizer; typedef struct fts5_tokenizer fts5_tokenizer; struct fts5_tokenizer { - int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); - void (*xDelete)(Fts5Tokenizer*); - int (*xTokenize)(Fts5Tokenizer*, - void *pCtx, - int flags, /* Mask of FTS5_TOKENIZE_* flags */ - const char *pText, int nText, - int (*xToken)( - void *pCtx, /* Copy of 2nd argument to xTokenize() */ - int tflags, /* Mask of FTS5_TOKEN_* flags */ - const char *pToken, /* Pointer to buffer containing token */ - int nToken, /* Size of token in bytes */ - int iStart, /* Byte offset of token within input text */ - int iEnd /* Byte offset of end of token within input text */ - ) - ); + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); + void (*xDelete)(Fts5Tokenizer*); + int (*xTokenize)(Fts5Tokenizer*, + void *pCtx, + int flags, /* Mask of FTS5_TOKENIZE_* flags */ + const char *pText, int nText, + int (*xToken)( + void *pCtx, /* Copy of 2nd argument to xTokenize() */ + int tflags, /* Mask of FTS5_TOKEN_* flags */ + const char *pToken, /* Pointer to buffer containing token */ + int nToken, /* Size of token in bytes */ + int iStart, /* Byte offset of token within input text */ + int iEnd /* Byte offset of end of token within input text */ + ) + ); }; /* Flags that may be passed as the third argument to xTokenize() */ @@ -12495,33 +12495,33 @@ struct fts5_tokenizer { */ typedef struct fts5_api fts5_api; struct fts5_api { - int iVersion; /* Currently always set to 2 */ - - /* Create a new tokenizer */ - int (*xCreateTokenizer)( - fts5_api *pApi, - const char *zName, - void *pContext, - fts5_tokenizer *pTokenizer, - void (*xDestroy)(void*) - ); - - /* Find an existing tokenizer */ - int (*xFindTokenizer)( - fts5_api *pApi, - const char *zName, - void **ppContext, - fts5_tokenizer *pTokenizer - ); - - /* Create a new auxiliary function */ - int (*xCreateFunction)( - fts5_api *pApi, - const char *zName, - void *pContext, - fts5_extension_function xFunction, - void (*xDestroy)(void*) - ); + int iVersion; /* Currently always set to 2 */ + + /* Create a new tokenizer */ + int (*xCreateTokenizer)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_tokenizer *pTokenizer, + void (*xDestroy)(void*) + ); + + /* Find an existing tokenizer */ + int (*xFindTokenizer)( + fts5_api *pApi, + const char *zName, + void **ppContext, + fts5_tokenizer *pTokenizer + ); + + /* Create a new auxiliary function */ + int (*xCreateFunction)( + fts5_api *pApi, + const char *zName, + void *pContext, + fts5_extension_function xFunction, + void (*xDestroy)(void*) + ); }; /* diff --git a/mock/sqlite/include/sqlite3ext.h b/mock/sqlite/include/sqlite3ext.h index 2e220798947ec3b1a09bd7a7882b8781fe2b19c3..7c1373fe85f080143a6ddc39f664d88cecf78bc9 100644 --- a/mock/sqlite/include/sqlite3ext.h +++ b/mock/sqlite/include/sqlite3ext.h @@ -30,322 +30,322 @@ ** libraries! */ struct sqlite3_api_routines { - void * (*aggregate_context)(sqlite3_context*,int nBytes); - int (*aggregate_count)(sqlite3_context*); - int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); - int (*bind_double)(sqlite3_stmt*,int,double); - int (*bind_int)(sqlite3_stmt*,int,int); - int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); - int (*bind_null)(sqlite3_stmt*,int); - int (*bind_parameter_count)(sqlite3_stmt*); - int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); - const char * (*bind_parameter_name)(sqlite3_stmt*,int); - int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); - int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); - int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); - int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); - int (*busy_timeout)(sqlite3*,int ms); - int (*changes)(sqlite3*); - int (*close)(sqlite3*); - int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, - int eTextRep,const char*)); - int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, - int eTextRep,const void*)); - const void * (*column_blob)(sqlite3_stmt*,int iCol); - int (*column_bytes)(sqlite3_stmt*,int iCol); - int (*column_bytes16)(sqlite3_stmt*,int iCol); - int (*column_count)(sqlite3_stmt*pStmt); - const char * (*column_database_name)(sqlite3_stmt*,int); - const void * (*column_database_name16)(sqlite3_stmt*,int); - const char * (*column_decltype)(sqlite3_stmt*,int i); - const void * (*column_decltype16)(sqlite3_stmt*,int); - double (*column_double)(sqlite3_stmt*,int iCol); - int (*column_int)(sqlite3_stmt*,int iCol); - sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); - const char * (*column_name)(sqlite3_stmt*,int); - const void * (*column_name16)(sqlite3_stmt*,int); - const char * (*column_origin_name)(sqlite3_stmt*,int); - const void * (*column_origin_name16)(sqlite3_stmt*,int); - const char * (*column_table_name)(sqlite3_stmt*,int); - const void * (*column_table_name16)(sqlite3_stmt*,int); - const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); - const void * (*column_text16)(sqlite3_stmt*,int iCol); - int (*column_type)(sqlite3_stmt*,int iCol); - sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); - void * (*commit_hook)(sqlite3*,int(*)(void*),void*); - int (*complete)(const char*sql); - int (*complete16)(const void*sql); - int (*create_collation)(sqlite3*,const char*,int,void*, - int(*)(void*,int,const void*,int,const void*)); - int (*create_collation16)(sqlite3*,const void*,int,void*, - int(*)(void*,int,const void*,int,const void*)); - int (*create_function)(sqlite3*,const char*,int,int,void*, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*)); - int (*create_function16)(sqlite3*,const void*,int,int,void*, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*)); - int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); - int (*data_count)(sqlite3_stmt*pStmt); - sqlite3 * (*db_handle)(sqlite3_stmt*); - int (*declare_vtab)(sqlite3*,const char*); - int (*enable_shared_cache)(int); - int (*errcode)(sqlite3*db); - const char * (*errmsg)(sqlite3*); - const void * (*errmsg16)(sqlite3*); - int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); - int (*expired)(sqlite3_stmt*); - int (*finalize)(sqlite3_stmt*pStmt); - void (*free)(void*); - void (*free_table)(char**result); - int (*get_autocommit)(sqlite3*); - void * (*get_auxdata)(sqlite3_context*,int); - int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); - int (*global_recover)(void); - void (*interruptx)(sqlite3*); - sqlite_int64 (*last_insert_rowid)(sqlite3*); - const char * (*libversion)(void); - int (*libversion_number)(void); - void *(*malloc)(int); - char * (*mprintf)(const char*,...); - int (*open)(const char*,sqlite3**); - int (*open16)(const void*,sqlite3**); - int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); - int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); - void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); - void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); - void *(*realloc)(void*,int); - int (*reset)(sqlite3_stmt*pStmt); - void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_double)(sqlite3_context*,double); - void (*result_error)(sqlite3_context*,const char*,int); - void (*result_error16)(sqlite3_context*,const void*,int); - void (*result_int)(sqlite3_context*,int); - void (*result_int64)(sqlite3_context*,sqlite_int64); - void (*result_null)(sqlite3_context*); - void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); - void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); - void (*result_value)(sqlite3_context*,sqlite3_value*); - void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); - int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, - const char*,const char*),void*); - void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); - char * (*xsnprintf)(int,char*,const char*,...); - int (*step)(sqlite3_stmt*); - int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, - char const**,char const**,int*,int*,int*); - void (*thread_cleanup)(void); - int (*total_changes)(sqlite3*); - void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); - int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); - void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, - sqlite_int64),void*); - void * (*user_data)(sqlite3_context*); - const void * (*value_blob)(sqlite3_value*); - int (*value_bytes)(sqlite3_value*); - int (*value_bytes16)(sqlite3_value*); - double (*value_double)(sqlite3_value*); - int (*value_int)(sqlite3_value*); - sqlite_int64 (*value_int64)(sqlite3_value*); - int (*value_numeric_type)(sqlite3_value*); - const unsigned char * (*value_text)(sqlite3_value*); - const void * (*value_text16)(sqlite3_value*); - const void * (*value_text16be)(sqlite3_value*); - const void * (*value_text16le)(sqlite3_value*); - int (*value_type)(sqlite3_value*); - char *(*vmprintf)(const char*,va_list); - /* Added ??? */ - int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); - /* Added by 3.3.13 */ - int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); - int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); - int (*clear_bindings)(sqlite3_stmt*); - /* Added by 3.4.1 */ - int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, - void (*xDestroy)(void *)); - /* Added by 3.5.0 */ - int (*bind_zeroblob)(sqlite3_stmt*,int,int); - int (*blob_bytes)(sqlite3_blob*); - int (*blob_close)(sqlite3_blob*); - int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, - int,sqlite3_blob**); - int (*blob_read)(sqlite3_blob*,void*,int,int); - int (*blob_write)(sqlite3_blob*,const void*,int,int); - int (*create_collation_v2)(sqlite3*,const char*,int,void*, - int(*)(void*,int,const void*,int,const void*), - void(*)(void*)); - int (*file_control)(sqlite3*,const char*,int,void*); - sqlite3_int64 (*memory_highwater)(int); - sqlite3_int64 (*memory_used)(void); - sqlite3_mutex *(*mutex_alloc)(int); - void (*mutex_enter)(sqlite3_mutex*); - void (*mutex_free)(sqlite3_mutex*); - void (*mutex_leave)(sqlite3_mutex*); - int (*mutex_try)(sqlite3_mutex*); - int (*open_v2)(const char*,sqlite3**,int,const char*); - int (*release_memory)(int); - void (*result_error_nomem)(sqlite3_context*); - void (*result_error_toobig)(sqlite3_context*); - int (*sleep)(int); - void (*soft_heap_limit)(int); - sqlite3_vfs *(*vfs_find)(const char*); - int (*vfs_register)(sqlite3_vfs*,int); - int (*vfs_unregister)(sqlite3_vfs*); - int (*xthreadsafe)(void); - void (*result_zeroblob)(sqlite3_context*,int); - void (*result_error_code)(sqlite3_context*,int); - int (*test_control)(int, ...); - void (*randomness)(int,void*); - sqlite3 *(*context_db_handle)(sqlite3_context*); - int (*extended_result_codes)(sqlite3*,int); - int (*limit)(sqlite3*,int,int); - sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); - const char *(*sql)(sqlite3_stmt*); - int (*status)(int,int*,int*,int); - int (*backup_finish)(sqlite3_backup*); - sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); - int (*backup_pagecount)(sqlite3_backup*); - int (*backup_remaining)(sqlite3_backup*); - int (*backup_step)(sqlite3_backup*,int); - const char *(*compileoption_get)(int); - int (*compileoption_used)(const char*); - int (*create_function_v2)(sqlite3*,const char*,int,int,void*, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void(*xDestroy)(void*)); - int (*db_config)(sqlite3*,int,...); - sqlite3_mutex *(*db_mutex)(sqlite3*); - int (*db_status)(sqlite3*,int,int*,int*,int); - int (*extended_errcode)(sqlite3*); - void (*log)(int,const char*,...); - sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); - const char *(*sourceid)(void); - int (*stmt_status)(sqlite3_stmt*,int,int); - int (*strnicmp)(const char*,const char*,int); - int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); - int (*wal_autocheckpoint)(sqlite3*,int); - int (*wal_checkpoint)(sqlite3*,const char*); - void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); - int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); - int (*vtab_config)(sqlite3*,int op,...); - int (*vtab_on_conflict)(sqlite3*); - /* Version 3.7.16 and later */ - int (*close_v2)(sqlite3*); - const char *(*db_filename)(sqlite3*,const char*); - int (*db_readonly)(sqlite3*,const char*); - int (*db_release_memory)(sqlite3*); - const char *(*errstr)(int); - int (*stmt_busy)(sqlite3_stmt*); - int (*stmt_readonly)(sqlite3_stmt*); - int (*stricmp)(const char*,const char*); - int (*uri_boolean)(const char*,const char*,int); - sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); - const char *(*uri_parameter)(const char*,const char*); - char *(*xvsnprintf)(int,char*,const char*,va_list); - int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); - /* Version 3.8.7 and later */ - int (*auto_extension)(void(*)(void)); - int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, - void(*)(void*)); - int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, - void(*)(void*),unsigned char); - int (*cancel_auto_extension)(void(*)(void)); - int (*load_extension)(sqlite3*,const char*,const char*,char**); - void *(*malloc64)(sqlite3_uint64); - sqlite3_uint64 (*msize)(void*); - void *(*realloc64)(void*,sqlite3_uint64); - void (*reset_auto_extension)(void); - void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, - void(*)(void*)); - void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, - void(*)(void*), unsigned char); - int (*strglob)(const char*,const char*); - /* Version 3.8.11 and later */ - sqlite3_value *(*value_dup)(const sqlite3_value*); - void (*value_free)(sqlite3_value*); - int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); - int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); - /* Version 3.9.0 and later */ - unsigned int (*value_subtype)(sqlite3_value*); - void (*result_subtype)(sqlite3_context*,unsigned int); - /* Version 3.10.0 and later */ - int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); - int (*strlike)(const char*,const char*,unsigned int); - int (*db_cacheflush)(sqlite3*); - /* Version 3.12.0 and later */ - int (*system_errno)(sqlite3*); - /* Version 3.14.0 and later */ - int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); - char *(*expanded_sql)(sqlite3_stmt*); - /* Version 3.18.0 and later */ - void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); - /* Version 3.20.0 and later */ - int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, - sqlite3_stmt**,const char**); - int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, - sqlite3_stmt**,const void**); - int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); - void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); - void *(*value_pointer)(sqlite3_value*,const char*); - int (*vtab_nochange)(sqlite3_context*); - int (*value_nochange)(sqlite3_value*); - const char *(*vtab_collation)(sqlite3_index_info*,int); - /* Version 3.24.0 and later */ - int (*keyword_count)(void); - int (*keyword_name)(int,const char**,int*); - int (*keyword_check)(const char*,int); - sqlite3_str *(*str_new)(sqlite3*); - char *(*str_finish)(sqlite3_str*); - void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); - void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); - void (*str_append)(sqlite3_str*, const char *zIn, int N); - void (*str_appendall)(sqlite3_str*, const char *zIn); - void (*str_appendchar)(sqlite3_str*, int N, char C); - void (*str_reset)(sqlite3_str*); - int (*str_errcode)(sqlite3_str*); - int (*str_length)(sqlite3_str*); - char *(*str_value)(sqlite3_str*); - /* Version 3.25.0 and later */ - int (*create_window_function)(sqlite3*,const char*,int,int,void*, - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*), - void (*xValue)(sqlite3_context*), - void (*xInv)(sqlite3_context*,int,sqlite3_value**), - void(*xDestroy)(void*)); - /* Version 3.26.0 and later */ - const char *(*normalized_sql)(sqlite3_stmt*); - /* Version 3.28.0 and later */ - int (*stmt_isexplain)(sqlite3_stmt*); - int (*value_frombind)(sqlite3_value*); - /* Version 3.30.0 and later */ - int (*drop_modules)(sqlite3*,const char**); - /* Version 3.31.0 and later */ - sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); - const char *(*uri_key)(const char*,int); - const char *(*filename_database)(const char*); - const char *(*filename_journal)(const char*); - const char *(*filename_wal)(const char*); - /* Version 3.32.0 and later */ - char *(*create_filename)(const char*,const char*,const char*, - int,const char**); - void (*free_filename)(char*); - sqlite3_file *(*database_file_object)(const char*); - /* Version 3.34.0 and later */ - int (*txn_state)(sqlite3*,const char*); - /* Version 3.36.1 and later */ - sqlite3_int64 (*changes64)(sqlite3*); - sqlite3_int64 (*total_changes64)(sqlite3*); - /* Version 3.37.0 and later */ - int (*autovacuum_pages)(sqlite3*, - unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), - void*, void(*)(void*)); + void * (*aggregate_context)(sqlite3_context*,int nBytes); + int (*aggregate_count)(sqlite3_context*); + int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); + int (*bind_double)(sqlite3_stmt*,int,double); + int (*bind_int)(sqlite3_stmt*,int,int); + int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); + int (*bind_null)(sqlite3_stmt*,int); + int (*bind_parameter_count)(sqlite3_stmt*); + int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); + const char * (*bind_parameter_name)(sqlite3_stmt*,int); + int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); + int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); + int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); + int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); + int (*busy_timeout)(sqlite3*,int ms); + int (*changes)(sqlite3*); + int (*close)(sqlite3*); + int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const char*)); + int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, + int eTextRep,const void*)); + const void * (*column_blob)(sqlite3_stmt*,int iCol); + int (*column_bytes)(sqlite3_stmt*,int iCol); + int (*column_bytes16)(sqlite3_stmt*,int iCol); + int (*column_count)(sqlite3_stmt*pStmt); + const char * (*column_database_name)(sqlite3_stmt*,int); + const void * (*column_database_name16)(sqlite3_stmt*,int); + const char * (*column_decltype)(sqlite3_stmt*,int i); + const void * (*column_decltype16)(sqlite3_stmt*,int); + double (*column_double)(sqlite3_stmt*,int iCol); + int (*column_int)(sqlite3_stmt*,int iCol); + sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); + const char * (*column_name)(sqlite3_stmt*,int); + const void * (*column_name16)(sqlite3_stmt*,int); + const char * (*column_origin_name)(sqlite3_stmt*,int); + const void * (*column_origin_name16)(sqlite3_stmt*,int); + const char * (*column_table_name)(sqlite3_stmt*,int); + const void * (*column_table_name16)(sqlite3_stmt*,int); + const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); + const void * (*column_text16)(sqlite3_stmt*,int iCol); + int (*column_type)(sqlite3_stmt*,int iCol); + sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); + void * (*commit_hook)(sqlite3*,int(*)(void*),void*); + int (*complete)(const char*sql); + int (*complete16)(const void*sql); + int (*create_collation)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_collation16)(sqlite3*,const void*,int,void*, + int(*)(void*,int,const void*,int,const void*)); + int (*create_function)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_function16)(sqlite3*,const void*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*)); + int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); + int (*data_count)(sqlite3_stmt*pStmt); + sqlite3 * (*db_handle)(sqlite3_stmt*); + int (*declare_vtab)(sqlite3*,const char*); + int (*enable_shared_cache)(int); + int (*errcode)(sqlite3*db); + const char * (*errmsg)(sqlite3*); + const void * (*errmsg16)(sqlite3*); + int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); + int (*expired)(sqlite3_stmt*); + int (*finalize)(sqlite3_stmt*pStmt); + void (*free)(void*); + void (*free_table)(char**result); + int (*get_autocommit)(sqlite3*); + void * (*get_auxdata)(sqlite3_context*,int); + int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); + int (*global_recover)(void); + void (*interruptx)(sqlite3*); + sqlite_int64 (*last_insert_rowid)(sqlite3*); + const char * (*libversion)(void); + int (*libversion_number)(void); + void *(*malloc)(int); + char * (*mprintf)(const char*,...); + int (*open)(const char*,sqlite3**); + int (*open16)(const void*,sqlite3**); + int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); + void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); + void *(*realloc)(void*,int); + int (*reset)(sqlite3_stmt*pStmt); + void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_double)(sqlite3_context*,double); + void (*result_error)(sqlite3_context*,const char*,int); + void (*result_error16)(sqlite3_context*,const void*,int); + void (*result_int)(sqlite3_context*,int); + void (*result_int64)(sqlite3_context*,sqlite_int64); + void (*result_null)(sqlite3_context*); + void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); + void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); + void (*result_value)(sqlite3_context*,sqlite3_value*); + void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); + int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, + const char*,const char*),void*); + void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); + char * (*xsnprintf)(int,char*,const char*,...); + int (*step)(sqlite3_stmt*); + int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, + char const**,char const**,int*,int*,int*); + void (*thread_cleanup)(void); + int (*total_changes)(sqlite3*); + void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); + int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); + void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, + sqlite_int64),void*); + void * (*user_data)(sqlite3_context*); + const void * (*value_blob)(sqlite3_value*); + int (*value_bytes)(sqlite3_value*); + int (*value_bytes16)(sqlite3_value*); + double (*value_double)(sqlite3_value*); + int (*value_int)(sqlite3_value*); + sqlite_int64 (*value_int64)(sqlite3_value*); + int (*value_numeric_type)(sqlite3_value*); + const unsigned char * (*value_text)(sqlite3_value*); + const void * (*value_text16)(sqlite3_value*); + const void * (*value_text16be)(sqlite3_value*); + const void * (*value_text16le)(sqlite3_value*); + int (*value_type)(sqlite3_value*); + char *(*vmprintf)(const char*,va_list); + /* Added ??? */ + int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); + /* Added by 3.3.13 */ + int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); + int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); + int (*clear_bindings)(sqlite3_stmt*); + /* Added by 3.4.1 */ + int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, + void (*xDestroy)(void *)); + /* Added by 3.5.0 */ + int (*bind_zeroblob)(sqlite3_stmt*,int,int); + int (*blob_bytes)(sqlite3_blob*); + int (*blob_close)(sqlite3_blob*); + int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, + int,sqlite3_blob**); + int (*blob_read)(sqlite3_blob*,void*,int,int); + int (*blob_write)(sqlite3_blob*,const void*,int,int); + int (*create_collation_v2)(sqlite3*,const char*,int,void*, + int(*)(void*,int,const void*,int,const void*), + void(*)(void*)); + int (*file_control)(sqlite3*,const char*,int,void*); + sqlite3_int64 (*memory_highwater)(int); + sqlite3_int64 (*memory_used)(void); + sqlite3_mutex *(*mutex_alloc)(int); + void (*mutex_enter)(sqlite3_mutex*); + void (*mutex_free)(sqlite3_mutex*); + void (*mutex_leave)(sqlite3_mutex*); + int (*mutex_try)(sqlite3_mutex*); + int (*open_v2)(const char*,sqlite3**,int,const char*); + int (*release_memory)(int); + void (*result_error_nomem)(sqlite3_context*); + void (*result_error_toobig)(sqlite3_context*); + int (*sleep)(int); + void (*soft_heap_limit)(int); + sqlite3_vfs *(*vfs_find)(const char*); + int (*vfs_register)(sqlite3_vfs*,int); + int (*vfs_unregister)(sqlite3_vfs*); + int (*xthreadsafe)(void); + void (*result_zeroblob)(sqlite3_context*,int); + void (*result_error_code)(sqlite3_context*,int); + int (*test_control)(int, ...); + void (*randomness)(int,void*); + sqlite3 *(*context_db_handle)(sqlite3_context*); + int (*extended_result_codes)(sqlite3*,int); + int (*limit)(sqlite3*,int,int); + sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); + const char *(*sql)(sqlite3_stmt*); + int (*status)(int,int*,int*,int); + int (*backup_finish)(sqlite3_backup*); + sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); + int (*backup_pagecount)(sqlite3_backup*); + int (*backup_remaining)(sqlite3_backup*); + int (*backup_step)(sqlite3_backup*,int); + const char *(*compileoption_get)(int); + int (*compileoption_used)(const char*); + int (*create_function_v2)(sqlite3*,const char*,int,int,void*, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*)); + int (*db_config)(sqlite3*,int,...); + sqlite3_mutex *(*db_mutex)(sqlite3*); + int (*db_status)(sqlite3*,int,int*,int*,int); + int (*extended_errcode)(sqlite3*); + void (*log)(int,const char*,...); + sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); + const char *(*sourceid)(void); + int (*stmt_status)(sqlite3_stmt*,int,int); + int (*strnicmp)(const char*,const char*,int); + int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); + int (*wal_autocheckpoint)(sqlite3*,int); + int (*wal_checkpoint)(sqlite3*,const char*); + void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); + int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); + int (*vtab_config)(sqlite3*,int op,...); + int (*vtab_on_conflict)(sqlite3*); + /* Version 3.7.16 and later */ + int (*close_v2)(sqlite3*); + const char *(*db_filename)(sqlite3*,const char*); + int (*db_readonly)(sqlite3*,const char*); + int (*db_release_memory)(sqlite3*); + const char *(*errstr)(int); + int (*stmt_busy)(sqlite3_stmt*); + int (*stmt_readonly)(sqlite3_stmt*); + int (*stricmp)(const char*,const char*); + int (*uri_boolean)(const char*,const char*,int); + sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); + const char *(*uri_parameter)(const char*,const char*); + char *(*xvsnprintf)(int,char*,const char*,va_list); + int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); + /* Version 3.8.7 and later */ + int (*auto_extension)(void(*)(void)); + int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, + void(*)(void*)); + int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, + void(*)(void*),unsigned char); + int (*cancel_auto_extension)(void(*)(void)); + int (*load_extension)(sqlite3*,const char*,const char*,char**); + void *(*malloc64)(sqlite3_uint64); + sqlite3_uint64 (*msize)(void*); + void *(*realloc64)(void*,sqlite3_uint64); + void (*reset_auto_extension)(void); + void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, + void(*)(void*)); + void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, + void(*)(void*), unsigned char); + int (*strglob)(const char*,const char*); + /* Version 3.8.11 and later */ + sqlite3_value *(*value_dup)(const sqlite3_value*); + void (*value_free)(sqlite3_value*); + int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); + int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); + /* Version 3.9.0 and later */ + unsigned int (*value_subtype)(sqlite3_value*); + void (*result_subtype)(sqlite3_context*,unsigned int); + /* Version 3.10.0 and later */ + int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int); + int (*strlike)(const char*,const char*,unsigned int); + int (*db_cacheflush)(sqlite3*); + /* Version 3.12.0 and later */ + int (*system_errno)(sqlite3*); + /* Version 3.14.0 and later */ + int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); + char *(*expanded_sql)(sqlite3_stmt*); + /* Version 3.18.0 and later */ + void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); + /* Version 3.20.0 and later */ + int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, + sqlite3_stmt**,const char**); + int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, + sqlite3_stmt**,const void**); + int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); + void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); + void *(*value_pointer)(sqlite3_value*,const char*); + int (*vtab_nochange)(sqlite3_context*); + int (*value_nochange)(sqlite3_value*); + const char *(*vtab_collation)(sqlite3_index_info*,int); + /* Version 3.24.0 and later */ + int (*keyword_count)(void); + int (*keyword_name)(int,const char**,int*); + int (*keyword_check)(const char*,int); + sqlite3_str *(*str_new)(sqlite3*); + char *(*str_finish)(sqlite3_str*); + void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); + void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); + void (*str_append)(sqlite3_str*, const char *zIn, int N); + void (*str_appendall)(sqlite3_str*, const char *zIn); + void (*str_appendchar)(sqlite3_str*, int N, char C); + void (*str_reset)(sqlite3_str*); + int (*str_errcode)(sqlite3_str*); + int (*str_length)(sqlite3_str*); + char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ + int (*create_window_function)(sqlite3*,const char*,int,int,void*, + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void (*xValue)(sqlite3_context*), + void (*xInv)(sqlite3_context*,int,sqlite3_value**), + void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); + /* Version 3.28.0 and later */ + int (*stmt_isexplain)(sqlite3_stmt*); + int (*value_frombind)(sqlite3_value*); + /* Version 3.30.0 and later */ + int (*drop_modules)(sqlite3*,const char**); + /* Version 3.31.0 and later */ + sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64); + const char *(*uri_key)(const char*,int); + const char *(*filename_database)(const char*); + const char *(*filename_journal)(const char*); + const char *(*filename_wal)(const char*); + /* Version 3.32.0 and later */ + char *(*create_filename)(const char*,const char*,const char*, + int,const char**); + void (*free_filename)(char*); + sqlite3_file *(*database_file_object)(const char*); + /* Version 3.34.0 and later */ + int (*txn_state)(sqlite3*,const char*); + /* Version 3.36.1 and later */ + sqlite3_int64 (*changes64)(sqlite3*); + sqlite3_int64 (*total_changes64)(sqlite3*); + /* Version 3.37.0 and later */ + int (*autovacuum_pages)(sqlite3*, + unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int), + void*, void(*)(void*)); #ifdef SQLITE_ENABLE_DROPTABLE_CALLBACK - int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); + int (*set_droptable_handle)(sqlite3*,void(*)(sqlite3*,const char*,const char*)); #endif }; @@ -354,9 +354,9 @@ struct sqlite3_api_routines { ** is also defined in the file "loadext.c". */ typedef int (*sqlite3_loadext_entry)( - sqlite3 *db, /* Handle to the database. */ - char **pzErrMsg, /* Used to set error string on failure. */ - const sqlite3_api_routines *pThunk /* Extension API function pointers. */ + sqlite3 *db, /* Handle to the database. */ + char **pzErrMsg, /* Used to set error string on failure. */ + const sqlite3_api_routines *pThunk /* Extension API function pointers. */ ); /* @@ -669,14 +669,14 @@ extern const sqlite3_api_routines *sqlite3_export_symbols; #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) -/* This case when the file really is being compiled as a loadable + /* This case when the file really is being compiled as a loadable ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; # define SQLITE_EXTENSION_INIT3 \ extern const sqlite3_api_routines *sqlite3_api; #else -/* This case when the file is being statically linked into the + /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ diff --git a/mock/sqlite/include/sqlite3sym.h b/mock/sqlite/include/sqlite3sym.h index 56eeef3ad96f1cc22b5cdb695c060451d5a5c7d6..bd459b3ebc9c6cb1779a4cfe6fb9ea6128a018e4 100644 --- a/mock/sqlite/include/sqlite3sym.h +++ b/mock/sqlite/include/sqlite3sym.h @@ -1,17 +1,17 @@ /* -* Copyright (c) 2021 Huawei Device Co., Ltd. -* 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. -*/ + * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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 SQLITE3SYM_H #define SQLITE3SYM_H @@ -23,12 +23,12 @@ #include "sqlite3ext.h" struct sqlite3_api_routines_hw { - int (*initialize)(); - int (*config)(int,...); - int (*key)(sqlite3*,const void*,int); - int (*key_v2)(sqlite3*,const char*,const void*,int); - int (*rekey)(sqlite3*,const void*,int); - int (*rekey_v2)(sqlite3*,const char*,const void*,int); + int (*initialize)(); + int (*config)(int,...); + int (*key)(sqlite3*,const void*,int); + int (*key_v2)(sqlite3*,const char*,const void*,int); + int (*rekey)(sqlite3*,const void*,int); + int (*rekey_v2)(sqlite3*,const char*,const void*,int); }; extern const struct sqlite3_api_routines_hw *sqlite3_export_hw_symbols; diff --git a/mock/sqlite/src/shell.c b/mock/sqlite/src/shell.c index b772572fd9c87e0b4ac4ac811f900a9d4f1a2753..dc66c4009cc17ea8c79534d547d60c17035f1dcd 100644 --- a/mock/sqlite/src/shell.c +++ b/mock/sqlite/src/shell.c @@ -37,7 +37,7 @@ /* ** Optionally #include a user-defined header, whereby compilation options -** may be set prior to where they take effect, but after platform setup. +** may be set prior to where they take effect, but after platform setup. ** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include ** file. Note that this macro has a like effect on sqlite3.c compilation. */ @@ -188,14 +188,14 @@ typedef unsigned char u8; # define pclose _pclose # endif #else -/* Make sure isatty() has a prototype. */ -extern int isatty(int); + /* Make sure isatty() has a prototype. */ + extern int isatty(int); # if !defined(__RTP__) && !defined(_WRS_KERNEL) -/* popen and pclose are not C89 functions and so are + /* popen and pclose are not C89 functions and so are ** sometimes omitted from the header */ -extern FILE *popen(const char*,const char*); -extern int pclose(FILE*); + extern FILE *popen(const char*,const char*); + extern int pclose(FILE*); # else # define SQLITE_OMIT_POPEN 1 # endif @@ -235,12 +235,12 @@ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText); */ #if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT static void setBinaryMode(FILE *file, int isOutput){ - if( isOutput ) fflush(file); - _setmode(_fileno(file), _O_BINARY); + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_BINARY); } static void setTextMode(FILE *file, int isOutput){ - if( isOutput ) fflush(file); - _setmode(_fileno(file), _O_TEXT); + if( isOutput ) fflush(file); + _setmode(_fileno(file), _O_TEXT); } #else # define setBinaryMode(X,Y) @@ -253,18 +253,18 @@ static int enableTimer = 0; /* Return the current wall-clock time */ static sqlite3_int64 timeOfDay(void){ - static sqlite3_vfs *clockVfs = 0; - sqlite3_int64 t; - if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); - if( clockVfs==0 ) return 0; /* Never actually happens */ - if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ - clockVfs->xCurrentTimeInt64(clockVfs, &t); - }else{ - double r; - clockVfs->xCurrentTime(clockVfs, &r); - t = (sqlite3_int64)(r*86400000.0); - } - return t; + static sqlite3_vfs *clockVfs = 0; + sqlite3_int64 t; + if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); + if( clockVfs==0 ) return 0; /* Never actually happens */ + if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ + clockVfs->xCurrentTimeInt64(clockVfs, &t); + }else{ + double r; + clockVfs->xCurrentTime(clockVfs, &r); + t = (sqlite3_int64)(r*86400000.0); + } + return t; } #if !defined(_WIN32) && !defined(WIN32) && !defined(__minux) @@ -274,8 +274,8 @@ static sqlite3_int64 timeOfDay(void){ /* VxWorks does not support getrusage() as far as we can determine */ #if defined(_WRS_KERNEL) || defined(__RTP__) struct rusage { - struct timeval ru_utime; /* user CPU time used */ - struct timeval ru_stime; /* system CPU time used */ + struct timeval ru_utime; /* user CPU time used */ + struct timeval ru_stime; /* system CPU time used */ }; #define getrusage(A,B) memset(B,0,sizeof(*B)) #endif @@ -288,31 +288,31 @@ static sqlite3_int64 iBegin; /* Wall-clock time at start */ ** Begin timing an operation */ static void beginTimer(void){ - if( enableTimer ){ - getrusage(RUSAGE_SELF, &sBegin); - iBegin = timeOfDay(); - } + if( enableTimer ){ + getrusage(RUSAGE_SELF, &sBegin); + iBegin = timeOfDay(); + } } /* Return the difference of two time_structs in seconds */ static double timeDiff(struct timeval *pStart, struct timeval *pEnd){ - return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + - (double)(pEnd->tv_sec - pStart->tv_sec); + return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + + (double)(pEnd->tv_sec - pStart->tv_sec); } /* ** Print the timing results. */ static void endTimer(void){ - if( enableTimer ){ - sqlite3_int64 iEnd = timeOfDay(); - struct rusage sEnd; - getrusage(RUSAGE_SELF, &sEnd); - printf("Run Time: real %.3f user %f sys %f\n", - (iEnd - iBegin)*0.001, - timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), - timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); - } + if( enableTimer ){ + sqlite3_int64 iEnd = timeOfDay(); + struct rusage sEnd; + getrusage(RUSAGE_SELF, &sEnd); + printf("Run Time: real %.3f user %f sys %f\n", + (iEnd - iBegin)*0.001, + timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), + timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); + } } #define BEGIN_TIMER beginTimer() @@ -327,7 +327,7 @@ static FILETIME ftKernelBegin; static FILETIME ftUserBegin; static sqlite3_int64 ftWallBegin; typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, - LPFILETIME, LPFILETIME); + LPFILETIME, LPFILETIME); static GETPROCTIMES getProcessTimesAddr = NULL; /* @@ -335,63 +335,63 @@ static GETPROCTIMES getProcessTimesAddr = NULL; ** support found (or found previously). */ static int hasTimer(void){ - if( getProcessTimesAddr ){ - return 1; - } else { + if( getProcessTimesAddr ){ + return 1; + } else { #if !SQLITE_OS_WINRT - /* GetProcessTimes() isn't supported in WIN95 and some other Windows + /* GetProcessTimes() isn't supported in WIN95 and some other Windows ** versions. See if the version we are running on has it, and if it ** does, save off a pointer to it and the current process handle. */ - hProcess = GetCurrentProcess(); - if( hProcess ){ - HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); - if( NULL != hinstLib ){ - getProcessTimesAddr = - (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); - if( NULL != getProcessTimesAddr ){ - return 1; - } - FreeLibrary(hinstLib); - } - } -#endif + hProcess = GetCurrentProcess(); + if( hProcess ){ + HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll")); + if( NULL != hinstLib ){ + getProcessTimesAddr = + (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes"); + if( NULL != getProcessTimesAddr ){ + return 1; + } + FreeLibrary(hinstLib); + } } - return 0; +#endif + } + return 0; } /* ** Begin timing an operation */ static void beginTimer(void){ - if( enableTimer && getProcessTimesAddr ){ - FILETIME ftCreation, ftExit; - getProcessTimesAddr(hProcess,&ftCreation,&ftExit, - &ftKernelBegin,&ftUserBegin); - ftWallBegin = timeOfDay(); - } + if( enableTimer && getProcessTimesAddr ){ + FILETIME ftCreation, ftExit; + getProcessTimesAddr(hProcess,&ftCreation,&ftExit, + &ftKernelBegin,&ftUserBegin); + ftWallBegin = timeOfDay(); + } } /* Return the difference of two FILETIME structs in seconds */ static double timeDiff(FILETIME *pStart, FILETIME *pEnd){ - sqlite_int64 i64Start = *((sqlite_int64 *) pStart); - sqlite_int64 i64End = *((sqlite_int64 *) pEnd); - return (double) ((i64End - i64Start) / 10000000.0); + sqlite_int64 i64Start = *((sqlite_int64 *) pStart); + sqlite_int64 i64End = *((sqlite_int64 *) pEnd); + return (double) ((i64End - i64Start) / 10000000.0); } /* ** Print the timing results. */ static void endTimer(void){ - if( enableTimer && getProcessTimesAddr){ - FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; - sqlite3_int64 ftWallEnd = timeOfDay(); - getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); - printf("Run Time: real %.3f user %f sys %f\n", - (ftWallEnd - ftWallBegin)*0.001, - timeDiff(&ftUserBegin, &ftUserEnd), - timeDiff(&ftKernelBegin, &ftKernelEnd)); - } + if( enableTimer && getProcessTimesAddr){ + FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; + sqlite3_int64 ftWallEnd = timeOfDay(); + getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd); + printf("Run Time: real %.3f user %f sys %f\n", + (ftWallEnd - ftWallBegin)*0.001, + timeDiff(&ftUserBegin, &ftUserEnd), + timeDiff(&ftKernelBegin, &ftKernelEnd)); + } } #define BEGIN_TIMER beginTimer() @@ -474,18 +474,18 @@ static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ */ #if defined(_WIN32) || defined(WIN32) void utf8_printf(FILE *out, const char *zFormat, ...){ - va_list ap; - va_start(ap, zFormat); - if( stdout_is_console && (out==stdout || out==stderr) ){ - char *z1 = sqlite3_vmprintf(zFormat, ap); - char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0); - sqlite3_free(z1); - fputs(z2, out); - sqlite3_free(z2); - }else{ - vfprintf(out, zFormat, ap); - } - va_end(ap); + va_list ap; + va_start(ap, zFormat); + if( stdout_is_console && (out==stdout || out==stderr) ){ + char *z1 = sqlite3_vmprintf(zFormat, ap); + char *z2 = sqlite3_win32_utf8_to_mbcs_v2(z1, 0); + sqlite3_free(z1); + fputs(z2, out); + sqlite3_free(z2); + }else{ + vfprintf(out, zFormat, ap); + } + va_end(ap); } #elif !defined(utf8_printf) # define utf8_printf fprintf @@ -501,8 +501,8 @@ void utf8_printf(FILE *out, const char *zFormat, ...){ /* Indicate out-of-memory and exit. */ static void shell_out_of_memory(void){ - raw_printf(stderr,"Error: out of memory\n"); - exit(1); + raw_printf(stderr,"Error: out of memory\n"); + exit(1); } #ifdef SQLITE_DEBUG @@ -511,11 +511,11 @@ static void shell_out_of_memory(void){ ** the OOM */ void shellOomFault(void){ - if( oomRepeat>0 ){ - oomRepeat--; - }else{ - oomCounter--; - } + if( oomRepeat>0 ){ + oomRepeat--; + }else{ + oomCounter--; + } } #endif /* SQLITE_DEBUG */ @@ -524,15 +524,15 @@ void shellOomFault(void){ ** Out-Of-Memory (OOM) errors for testing purposes. */ static void *oomMalloc(int nByte){ - if( oomCounter ){ - if( oomCounter==1 ){ - shellOomFault(); - return 0; - }else{ - oomCounter--; - } + if( oomCounter ){ + if( oomCounter==1 ){ + shellOomFault(); + return 0; + }else{ + oomCounter--; } - return defaultMalloc(nByte); + } + return defaultMalloc(nByte); } #endif /* SQLITE_DEBUG */ @@ -540,11 +540,11 @@ static void *oomMalloc(int nByte){ /* Register the OOM simulator. This must occur before any memory ** allocations */ static void registerOomSimulator(void){ - sqlite3_mem_methods mem; - sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem); - defaultMalloc = mem.xMalloc; - mem.xMalloc = oomMalloc; - sqlite3_config(SQLITE_CONFIG_MALLOC, &mem); + sqlite3_mem_methods mem; + sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem); + defaultMalloc = mem.xMalloc; + mem.xMalloc = oomMalloc; + sqlite3_config(SQLITE_CONFIG_MALLOC, &mem); } #endif @@ -563,14 +563,14 @@ static FILE *iotrace = 0; */ #ifdef SQLITE_ENABLE_IOTRACE static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ - va_list ap; - char *z; - if( iotrace==0 ) return; - va_start(ap, zFormat); - z = sqlite3_vmprintf(zFormat, ap); - va_end(ap); - utf8_printf(iotrace, "%s", z); - sqlite3_free(z); + va_list ap; + char *z; + if( iotrace==0 ) return; + va_start(ap, zFormat); + z = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + utf8_printf(iotrace, "%s", z); + sqlite3_free(z); } #endif @@ -581,25 +581,25 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ ** since with %*.*s the width is measured in bytes, not characters. */ static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ - int i; - int n; - int aw = w<0 ? -w : w; - for(i=n=0; zUtf[i]; i++){ - if( (zUtf[i]&0xc0)!=0x80 ){ - n++; - if( n==aw ){ - do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); - break; - } - } - } - if( n>=aw ){ - utf8_printf(pOut, "%.*s", i, zUtf); - }else if( w<0 ){ - utf8_printf(pOut, "%*s%s", aw-n, "", zUtf); - }else{ - utf8_printf(pOut, "%s%*s", zUtf, aw-n, ""); + int i; + int n; + int aw = w<0 ? -w : w; + for(i=n=0; zUtf[i]; i++){ + if( (zUtf[i]&0xc0)!=0x80 ){ + n++; + if( n==aw ){ + do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); + break; + } } + } + if( n>=aw ){ + utf8_printf(pOut, "%.*s", i, zUtf); + }else if( w<0 ){ + utf8_printf(pOut, "%*s%s", aw-n, "", zUtf); + }else{ + utf8_printf(pOut, "%s%*s", zUtf, aw-n, ""); + } } @@ -607,27 +607,27 @@ static void utf8_width_print(FILE *pOut, int w, const char *zUtf){ ** Determines if a string is a number of not. */ static int isNumber(const char *z, int *realnum){ - if( *z=='-' || *z=='+' ) z++; - if( !IsDigit(*z) ){ - return 0; - } + if( *z=='-' || *z=='+' ) z++; + if( !IsDigit(*z) ){ + return 0; + } + z++; + if( realnum ) *realnum = 0; + while( IsDigit(*z) ){ z++; } + if( *z=='.' ){ z++; - if( realnum ) *realnum = 0; + if( !IsDigit(*z) ) return 0; while( IsDigit(*z) ){ z++; } - if( *z=='.' ){ - z++; - if( !IsDigit(*z) ) return 0; - while( IsDigit(*z) ){ z++; } - if( realnum ) *realnum = 1; - } - if( *z=='e' || *z=='E' ){ - z++; - if( *z=='+' || *z=='-' ) z++; - if( !IsDigit(*z) ) return 0; - while( IsDigit(*z) ){ z++; } - if( realnum ) *realnum = 1; - } - return *z==0; + if( realnum ) *realnum = 1; + } + if( *z=='e' || *z=='E' ){ + z++; + if( *z=='+' || *z=='-' ) z++; + if( !IsDigit(*z) ) return 0; + while( IsDigit(*z) ){ z++; } + if( realnum ) *realnum = 1; + } + return *z==0; } /* @@ -635,9 +635,9 @@ static int isNumber(const char *z, int *realnum){ ** lower 30 bits of a 32-bit signed integer. */ static int strlen30(const char *z){ - const char *z2 = z; - while( *z2 ){ z2++; } - return 0x3fffffff & (int)(z2 - z); + const char *z2 = z; + while( *z2 ){ z2++; } + return 0x3fffffff & (int)(z2 - z); } /* @@ -645,11 +645,11 @@ static int strlen30(const char *z){ ** count as a single character. */ static int strlenChar(const char *z){ - int n = 0; - while( *z ){ - if( (0xc0&*(z++))!=0x80 ) n++; - } - return n; + int n = 0; + while( *z ){ + if( (0xc0&*(z++))!=0x80 ) n++; + } + return n; } /* @@ -659,29 +659,29 @@ static int strlenChar(const char *z){ */ static FILE * openChrSource(const char *zFile){ #ifdef _WIN32 - struct _stat x = {0}; + struct _stat x = {0}; # define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0) - /* On Windows, open first, then check the stream nature. This order + /* On Windows, open first, then check the stream nature. This order ** is necessary because _stat() and sibs, when checking a named pipe, ** effectively break the pipe as its supplier sees it. */ - FILE *rv = fopen(zFile, "rb"); - if( rv==0 ) return 0; - if( _fstat(_fileno(rv), &x) != 0 - || !STAT_CHR_SRC(x.st_mode)){ - fclose(rv); - rv = 0; - } - return rv; + FILE *rv = fopen(zFile, "rb"); + if( rv==0 ) return 0; + if( _fstat(_fileno(rv), &x) != 0 + || !STAT_CHR_SRC(x.st_mode)){ + fclose(rv); + rv = 0; + } + return rv; #else - struct stat x = {0}; - int rc = stat(zFile, &x); + struct stat x = {0}; + int rc = stat(zFile, &x); # define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode)) - if( rc!=0 ) return 0; - if( STAT_CHR_SRC(x.st_mode) ){ - return fopen(zFile, "rb"); - }else{ - return 0; - } + if( rc!=0 ) return 0; + if( STAT_CHR_SRC(x.st_mode) ){ + return fopen(zFile, "rb"); + }else{ + return 0; + } #endif #undef STAT_CHR_SRC } @@ -696,48 +696,48 @@ static FILE * openChrSource(const char *zFile){ ** a previous call to this routine that may be reused. */ static char *local_getline(char *zLine, FILE *in){ - int nLine = zLine==0 ? 0 : 100; - int n = 0; - - while( 1 ){ - if( n+100>nLine ){ - nLine = nLine*2 + 100; - zLine = realloc(zLine, nLine); - if( zLine==0 ) shell_out_of_memory(); - } - if( fgets(&zLine[n], nLine - n, in)==0 ){ - if( n==0 ){ - free(zLine); - return 0; - } - zLine[n] = 0; - break; - } - while( zLine[n] ) n++; - if( n>0 && zLine[n-1]=='\n' ){ - n--; - if( n>0 && zLine[n-1]=='\r' ) n--; - zLine[n] = 0; - break; - } - } + int nLine = zLine==0 ? 0 : 100; + int n = 0; + + while( 1 ){ + if( n+100>nLine ){ + nLine = nLine*2 + 100; + zLine = realloc(zLine, nLine); + if( zLine==0 ) shell_out_of_memory(); + } + if( fgets(&zLine[n], nLine - n, in)==0 ){ + if( n==0 ){ + free(zLine); + return 0; + } + zLine[n] = 0; + break; + } + while( zLine[n] ) n++; + if( n>0 && zLine[n-1]=='\n' ){ + n--; + if( n>0 && zLine[n-1]=='\r' ) n--; + zLine[n] = 0; + break; + } + } #if defined(_WIN32) || defined(WIN32) - /* For interactive input on Windows systems, translate the + /* For interactive input on Windows systems, translate the ** multi-byte characterset characters into UTF-8. */ - if( stdin_is_interactive && in==stdin ){ - char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); - if( zTrans ){ - int nTrans = strlen30(zTrans)+1; - if( nTrans>nLine ){ - zLine = realloc(zLine, nTrans); - if( zLine==0 ) shell_out_of_memory(); - } - memcpy(zLine, zTrans, nTrans); - sqlite3_free(zTrans); - } - } + if( stdin_is_interactive && in==stdin ){ + char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); + if( zTrans ){ + int nTrans = strlen30(zTrans)+1; + if( nTrans>nLine ){ + zLine = realloc(zLine, nTrans); + if( zLine==0 ) shell_out_of_memory(); + } + memcpy(zLine, zTrans, nTrans); + sqlite3_free(zTrans); + } + } #endif /* defined(_WIN32) || defined(WIN32) */ - return zLine; + return zLine; } /* @@ -755,23 +755,23 @@ static char *local_getline(char *zLine, FILE *in){ ** zPrior argument for reuse. */ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ - char *zPrompt; - char *zResult; - if( in!=0 ){ - zResult = local_getline(zPrior, in); - }else{ - zPrompt = isContinuation ? continuePrompt : mainPrompt; + char *zPrompt; + char *zResult; + if( in!=0 ){ + zResult = local_getline(zPrior, in); + }else{ + zPrompt = isContinuation ? continuePrompt : mainPrompt; #if SHELL_USE_LOCAL_GETLINE - printf("%s", zPrompt); - fflush(stdout); - zResult = local_getline(zPrior, stdin); + printf("%s", zPrompt); + fflush(stdout); + zResult = local_getline(zPrior, stdin); #else - free(zPrior); - zResult = shell_readline(zPrompt); - if( zResult && *zResult ) shell_add_history(zResult); + free(zPrior); + zResult = shell_readline(zPrompt); + if( zResult && *zResult ) shell_add_history(zResult); #endif - } - return zResult; + } + return zResult; } @@ -780,56 +780,56 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ ** is not a hex digit. */ static int hexDigitValue(char c){ - if( c>='0' && c<='9' ) return c - '0'; - if( c>='a' && c<='f' ) return c - 'a' + 10; - if( c>='A' && c<='F' ) return c - 'A' + 10; - return -1; + if( c>='0' && c<='9' ) return c - '0'; + if( c>='a' && c<='f' ) return c - 'a' + 10; + if( c>='A' && c<='F' ) return c - 'A' + 10; + return -1; } /* ** Interpret zArg as an integer value, possibly with suffixes. */ static sqlite3_int64 integerValue(const char *zArg){ - sqlite3_int64 v = 0; - static const struct { char *zSuffix; int iMult; } aMult[] = { - { "KiB", 1024 }, - { "MiB", 1024*1024 }, - { "GiB", 1024*1024*1024 }, - { "KB", 1000 }, - { "MB", 1000000 }, - { "GB", 1000000000 }, - { "K", 1000 }, - { "M", 1000000 }, - { "G", 1000000000 }, - }; - int i; - int isNeg = 0; - if( zArg[0]=='-' ){ - isNeg = 1; - zArg++; - }else if( zArg[0]=='+' ){ - zArg++; - } - if( zArg[0]=='0' && zArg[1]=='x' ){ - int x; - zArg += 2; - while( (x = hexDigitValue(zArg[0]))>=0 ){ - v = (v<<4) + x; - zArg++; - } - }else{ - while( IsDigit(zArg[0]) ){ - v = v*10 + zArg[0] - '0'; - zArg++; - } - } - for(i=0; i=0 ){ + v = (v<<4) + x; + zArg++; + } + }else{ + while( IsDigit(zArg[0]) ){ + v = v*10 + zArg[0] - '0'; + zArg++; + } + } + for(i=0; iz); - initText(p); + free(p->z); + initText(p); } /* zIn is either a pointer to a NULL-terminated string in memory obtained @@ -862,39 +862,39 @@ static void freeText(ShellText *p){ ** quote character for zAppend. */ static void appendText(ShellText *p, char const *zAppend, char quote){ - int len; - int i; - int nAppend = strlen30(zAppend); - - len = nAppend+p->n+1; - if( quote ){ - len += 2; - for(i=0; iz==0 || p->n+len>=p->nAlloc ){ - p->nAlloc = p->nAlloc*2 + len + 20; - p->z = realloc(p->z, p->nAlloc); - if( p->z==0 ) shell_out_of_memory(); - } - - if( quote ){ - char *zCsr = p->z+p->n; - *zCsr++ = quote; - for(i=0; in = (int)(zCsr - p->z); - *zCsr = '\0'; - }else{ - memcpy(p->z+p->n, zAppend, nAppend); - p->n += nAppend; - p->z[p->n] = '\0'; - } + int len; + int i; + int nAppend = strlen30(zAppend); + + len = nAppend+p->n+1; + if( quote ){ + len += 2; + for(i=0; iz==0 || p->n+len>=p->nAlloc ){ + p->nAlloc = p->nAlloc*2 + len + 20; + p->z = realloc(p->z, p->nAlloc); + if( p->z==0 ) shell_out_of_memory(); + } + + if( quote ){ + char *zCsr = p->z+p->n; + *zCsr++ = quote; + for(i=0; in = (int)(zCsr - p->z); + *zCsr = '\0'; + }else{ + memcpy(p->z+p->n, zAppend, nAppend); + p->n += nAppend; + p->z[p->n] = '\0'; + } } /* @@ -906,12 +906,12 @@ static void appendText(ShellText *p, char const *zAppend, char quote){ ** Return '"' if quoting is required. Return 0 if no quoting is required. */ static char quoteChar(const char *zName){ - int i; - if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"'; - for(i=0; zName[i]; i++){ - if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"'; - } - return sqlite3_keyword_check(zName, i) ? '"' : 0; + int i; + if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"'; + for(i=0; zName[i]; i++){ + if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"'; + } + return sqlite3_keyword_check(zName, i) ? '"' : 0; } /* @@ -919,45 +919,45 @@ static char quoteChar(const char *zName){ ** of the view, virtual table, or table valued function zSchema.zName. */ static char *shellFakeSchema( - sqlite3 *db, /* The database connection containing the vtab */ - const char *zSchema, /* Schema of the database holding the vtab */ - const char *zName /* The name of the virtual table */ + sqlite3 *db, /* The database connection containing the vtab */ + const char *zSchema, /* Schema of the database holding the vtab */ + const char *zName /* The name of the virtual table */ ){ - sqlite3_stmt *pStmt = 0; - char *zSql; - ShellText s; - char cQuote; - char *zDiv = "("; - int nRow = 0; - - zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", - zSchema ? zSchema : "main", zName); - sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - initText(&s); - if( zSchema ){ - cQuote = quoteChar(zSchema); - if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; - appendText(&s, zSchema, cQuote); - appendText(&s, ".", 0); - } - cQuote = quoteChar(zName); - appendText(&s, zName, cQuote); - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); - nRow++; - appendText(&s, zDiv, 0); - zDiv = ","; - cQuote = quoteChar(zCol); - appendText(&s, zCol, cQuote); - } - appendText(&s, ")", 0); - sqlite3_finalize(pStmt); - if( nRow==0 ){ - freeText(&s); - s.z = 0; - } - return s.z; + sqlite3_stmt *pStmt = 0; + char *zSql; + ShellText s; + char cQuote; + char *zDiv = "("; + int nRow = 0; + + zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", + zSchema ? zSchema : "main", zName); + sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + initText(&s); + if( zSchema ){ + cQuote = quoteChar(zSchema); + if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; + appendText(&s, zSchema, cQuote); + appendText(&s, ".", 0); + } + cQuote = quoteChar(zName); + appendText(&s, zName, cQuote); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); + nRow++; + appendText(&s, zDiv, 0); + zDiv = ","; + cQuote = quoteChar(zCol); + appendText(&s, zCol, cQuote); + } + appendText(&s, ")", 0); + sqlite3_finalize(pStmt); + if( nRow==0 ){ + freeText(&s); + s.z = 0; + } + return s.z; } /* @@ -967,18 +967,18 @@ static char *shellFakeSchema( ** table X. */ static void shellModuleSchema( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal ){ - const char *zName = (const char*)sqlite3_value_text(apVal[0]); - char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName); - UNUSED_PARAMETER(nVal); - if( zFake ){ - sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), - -1, sqlite3_free); - free(zFake); - } + const char *zName = (const char*)sqlite3_value_text(apVal[0]); + char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName); + UNUSED_PARAMETER(nVal); + if( zFake ){ + sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), + -1, sqlite3_free); + free(zFake); + } } /* @@ -1001,57 +1001,57 @@ static void shellModuleSchema( ** attached databases into the middle of the sqlite_schema.sql field. */ static void shellAddSchemaName( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal ){ - static const char *aPrefix[] = { - "TABLE", - "INDEX", - "UNIQUE INDEX", - "VIEW", - "TRIGGER", - "VIRTUAL TABLE" - }; - int i = 0; - const char *zIn = (const char*)sqlite3_value_text(apVal[0]); - const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); - const char *zName = (const char*)sqlite3_value_text(apVal[2]); - sqlite3 *db = sqlite3_context_db_handle(pCtx); - UNUSED_PARAMETER(nVal); - if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){ - for(i=0; idwSize ){ - /* + memset(value, 0, sizeof(value)); + dwRet = GetEnvironmentVariableA(name, value, dwSize); + if( dwRet==0 || dwRet>dwSize ){ + /* ** The function call to GetEnvironmentVariableA() failed -OR- ** the buffer is not large enough. Either way, return NULL. */ - return 0; - }else{ - /* + return 0; + }else{ + /* ** The function call to GetEnvironmentVariableA() succeeded ** -AND- the buffer contains the entire value. */ - return value; - } + return value; + } } /* ** Implementation of the POSIX opendir() function using the MSVCRT. */ LPDIR opendir( - const char *dirname + const char *dirname ){ - struct _finddata_t data; - LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); - SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); - - if( dirp==NULL ) return NULL; - memset(dirp, 0, sizeof(DIR)); + struct _finddata_t data; + LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); + SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); - /* TODO: Remove this if Unix-style root paths are not used. */ - if( sqlite3_stricmp(dirname, "/")==0 ){ - dirname = windirent_getenv("SystemDrive"); - } + if( dirp==NULL ) return NULL; + memset(dirp, 0, sizeof(DIR)); - memset(&data, 0, sizeof(struct _finddata_t)); - _snprintf(data.name, namesize, "%s\\*", dirname); - dirp->d_handle = _findfirst(data.name, &data); + /* TODO: Remove this if Unix-style root paths are not used. */ + if( sqlite3_stricmp(dirname, "/")==0 ){ + dirname = windirent_getenv("SystemDrive"); + } - if( dirp->d_handle==BAD_INTPTR_T ){ - closedir(dirp); - return NULL; - } + memset(&data, 0, sizeof(struct _finddata_t)); + _snprintf(data.name, namesize, "%s\\*", dirname); + dirp->d_handle = _findfirst(data.name, &data); - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ){ - next: + if( dirp->d_handle==BAD_INTPTR_T ){ + closedir(dirp); + return NULL; + } - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ){ - closedir(dirp); - return NULL; - } + /* TODO: Remove this block to allow hidden and/or system files. */ + if( is_filtered(data) ){ +next: - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; + memset(&data, 0, sizeof(struct _finddata_t)); + if( _findnext(dirp->d_handle, &data)==-1 ){ + closedir(dirp); + return NULL; } - dirp->d_first.d_attributes = data.attrib; - strncpy(dirp->d_first.d_name, data.name, NAME_MAX); - dirp->d_first.d_name[NAME_MAX] = '\0'; + /* TODO: Remove this block to allow hidden and/or system files. */ + if( is_filtered(data) ) goto next; + } + + dirp->d_first.d_attributes = data.attrib; + strncpy(dirp->d_first.d_name, data.name, NAME_MAX); + dirp->d_first.d_name[NAME_MAX] = '\0'; - return dirp; + return dirp; } /* ** Implementation of the POSIX readdir() function using the MSVCRT. */ LPDIRENT readdir( - LPDIR dirp + LPDIR dirp ){ - struct _finddata_t data; + struct _finddata_t data; - if( dirp==NULL ) return NULL; + if( dirp==NULL ) return NULL; - if( dirp->d_first.d_ino==0 ){ - dirp->d_first.d_ino++; - dirp->d_next.d_ino++; + if( dirp->d_first.d_ino==0 ){ + dirp->d_first.d_ino++; + dirp->d_next.d_ino++; - return &dirp->d_first; - } + return &dirp->d_first; + } next: - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; + memset(&data, 0, sizeof(struct _finddata_t)); + if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; + /* TODO: Remove this block to allow hidden and/or system files. */ + if( is_filtered(data) ) goto next; - dirp->d_next.d_ino++; - dirp->d_next.d_attributes = data.attrib; - strncpy(dirp->d_next.d_name, data.name, NAME_MAX); - dirp->d_next.d_name[NAME_MAX] = '\0'; + dirp->d_next.d_ino++; + dirp->d_next.d_attributes = data.attrib; + strncpy(dirp->d_next.d_name, data.name, NAME_MAX); + dirp->d_next.d_name[NAME_MAX] = '\0'; - return &dirp->d_next; + return &dirp->d_next; } /* ** Implementation of the POSIX readdir_r() function using the MSVCRT. */ INT readdir_r( - LPDIR dirp, - LPDIRENT entry, - LPDIRENT *result + LPDIR dirp, + LPDIRENT entry, + LPDIRENT *result ){ - struct _finddata_t data; + struct _finddata_t data; - if( dirp==NULL ) return EBADF; + if( dirp==NULL ) return EBADF; - if( dirp->d_first.d_ino==0 ){ - dirp->d_first.d_ino++; - dirp->d_next.d_ino++; + if( dirp->d_first.d_ino==0 ){ + dirp->d_first.d_ino++; + dirp->d_next.d_ino++; - entry->d_ino = dirp->d_first.d_ino; - entry->d_attributes = dirp->d_first.d_attributes; - strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); - entry->d_name[NAME_MAX] = '\0'; + entry->d_ino = dirp->d_first.d_ino; + entry->d_attributes = dirp->d_first.d_attributes; + strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); + entry->d_name[NAME_MAX] = '\0'; - *result = entry; - return 0; - } + *result = entry; + return 0; + } next: - memset(&data, 0, sizeof(struct _finddata_t)); - if( _findnext(dirp->d_handle, &data)==-1 ){ - *result = NULL; - return ENOENT; - } + memset(&data, 0, sizeof(struct _finddata_t)); + if( _findnext(dirp->d_handle, &data)==-1 ){ + *result = NULL; + return ENOENT; + } - /* TODO: Remove this block to allow hidden and/or system files. */ - if( is_filtered(data) ) goto next; + /* TODO: Remove this block to allow hidden and/or system files. */ + if( is_filtered(data) ) goto next; - entry->d_ino = (ino_t)-1; /* not available */ - entry->d_attributes = data.attrib; - strncpy(entry->d_name, data.name, NAME_MAX); - entry->d_name[NAME_MAX] = '\0'; + entry->d_ino = (ino_t)-1; /* not available */ + entry->d_attributes = data.attrib; + strncpy(entry->d_name, data.name, NAME_MAX); + entry->d_name[NAME_MAX] = '\0'; - *result = entry; - return 0; + *result = entry; + return 0; } /* ** Implementation of the POSIX closedir() function using the MSVCRT. */ INT closedir( - LPDIR dirp + LPDIR dirp ){ - INT result = 0; + INT result = 0; - if( dirp==NULL ) return EINVAL; + if( dirp==NULL ) return EINVAL; - if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){ - result = _findclose(dirp->d_handle); - } + if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){ + result = _findclose(dirp->d_handle); + } - sqlite3_free(dirp); - return result; + sqlite3_free(dirp); + return result; } #endif /* defined(WIN32) && defined(_MSC_VER) */ @@ -1492,37 +1492,37 @@ SQLITE_EXTENSION_INIT1 */ typedef struct SHA3Context SHA3Context; struct SHA3Context { - union { - u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */ - unsigned char x[1600]; /* ... or 1600 bytes */ - } u; - unsigned nRate; /* Bytes of input accepted per Keccak iteration */ - unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */ - unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */ + union { + u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */ + unsigned char x[1600]; /* ... or 1600 bytes */ + } u; + unsigned nRate; /* Bytes of input accepted per Keccak iteration */ + unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */ + unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */ }; /* ** A single step of the Keccak mixing function for a 1600-bit state */ static void KeccakF1600Step(SHA3Context *p){ - int i; - u64 b0, b1, b2, b3, b4; - u64 c0, c1, c2, c3, c4; - u64 d0, d1, d2, d3, d4; - static const u64 RC[] = { - 0x0000000000000001ULL, 0x0000000000008082ULL, - 0x800000000000808aULL, 0x8000000080008000ULL, - 0x000000000000808bULL, 0x0000000080000001ULL, - 0x8000000080008081ULL, 0x8000000000008009ULL, - 0x000000000000008aULL, 0x0000000000000088ULL, - 0x0000000080008009ULL, 0x000000008000000aULL, - 0x000000008000808bULL, 0x800000000000008bULL, - 0x8000000000008089ULL, 0x8000000000008003ULL, - 0x8000000000008002ULL, 0x8000000000000080ULL, - 0x000000000000800aULL, 0x800000008000000aULL, - 0x8000000080008081ULL, 0x8000000000008080ULL, - 0x0000000080000001ULL, 0x8000000080008008ULL - }; + int i; + u64 b0, b1, b2, b3, b4; + u64 c0, c1, c2, c3, c4; + u64 d0, d1, d2, d3, d4; + static const u64 RC[] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, + 0x800000000000808aULL, 0x8000000080008000ULL, + 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x000000000000008aULL, 0x0000000000000088ULL, + 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, + 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, + 0x0000000080000001ULL, 0x8000000080008008ULL + }; # define a00 (p->u.s[0]) # define a01 (p->u.s[1]) # define a02 (p->u.s[2]) @@ -1550,275 +1550,275 @@ static void KeccakF1600Step(SHA3Context *p){ # define a44 (p->u.s[24]) # define ROL64(a,x) ((a<>(64-x))) - for(i=0; i<24; i+=4){ - c0 = a00^a10^a20^a30^a40; - c1 = a01^a11^a21^a31^a41; - c2 = a02^a12^a22^a32^a42; - c3 = a03^a13^a23^a33^a43; - c4 = a04^a14^a24^a34^a44; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a11^d1), 44); - b2 = ROL64((a22^d2), 43); - b3 = ROL64((a33^d3), 21); - b4 = ROL64((a44^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i]; - a11 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a20^d0), 3); - b3 = ROL64((a31^d1), 45); - b4 = ROL64((a42^d2), 61); - b0 = ROL64((a03^d3), 28); - b1 = ROL64((a14^d4), 20); - a20 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a40^d0), 18); - b0 = ROL64((a01^d1), 1); - b1 = ROL64((a12^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a34^d4), 8); - a40 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a10^d0), 36); - b2 = ROL64((a21^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a43^d3), 56); - b0 = ROL64((a04^d4), 27); - a10 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a30^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a02^d2), 62); - b1 = ROL64((a13^d3), 55); - b2 = ROL64((a24^d4), 39); - a30 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - c0 = a00^a20^a40^a10^a30; - c1 = a11^a31^a01^a21^a41; - c2 = a22^a42^a12^a32^a02; - c3 = a33^a03^a23^a43^a13; - c4 = a44^a14^a34^a04^a24; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a31^d1), 44); - b2 = ROL64((a12^d2), 43); - b3 = ROL64((a43^d3), 21); - b4 = ROL64((a24^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+1]; - a31 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a40^d0), 3); - b3 = ROL64((a21^d1), 45); - b4 = ROL64((a02^d2), 61); - b0 = ROL64((a33^d3), 28); - b1 = ROL64((a14^d4), 20); - a40 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a30^d0), 18); - b0 = ROL64((a11^d1), 1); - b1 = ROL64((a42^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a04^d4), 8); - a30 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a20^d0), 36); - b2 = ROL64((a01^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a13^d3), 56); - b0 = ROL64((a44^d4), 27); - a20 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a10^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a22^d2), 62); - b1 = ROL64((a03^d3), 55); - b2 = ROL64((a34^d4), 39); - a10 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - c0 = a00^a40^a30^a20^a10; - c1 = a31^a21^a11^a01^a41; - c2 = a12^a02^a42^a32^a22; - c3 = a43^a33^a23^a13^a03; - c4 = a24^a14^a04^a44^a34; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a21^d1), 44); - b2 = ROL64((a42^d2), 43); - b3 = ROL64((a13^d3), 21); - b4 = ROL64((a34^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+2]; - a21 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a30^d0), 3); - b3 = ROL64((a01^d1), 45); - b4 = ROL64((a22^d2), 61); - b0 = ROL64((a43^d3), 28); - b1 = ROL64((a14^d4), 20); - a30 = b0 ^((~b1)& b2 ); - a01 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a10^d0), 18); - b0 = ROL64((a31^d1), 1); - b1 = ROL64((a02^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a44^d4), 8); - a10 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a40^d0), 36); - b2 = ROL64((a11^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a03^d3), 56); - b0 = ROL64((a24^d4), 27); - a40 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a20^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a12^d2), 62); - b1 = ROL64((a33^d3), 55); - b2 = ROL64((a04^d4), 39); - a20 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - c0 = a00^a30^a10^a40^a20; - c1 = a21^a01^a31^a11^a41; - c2 = a42^a22^a02^a32^a12; - c3 = a13^a43^a23^a03^a33; - c4 = a34^a14^a44^a24^a04; - d0 = c4^ROL64(c1, 1); - d1 = c0^ROL64(c2, 1); - d2 = c1^ROL64(c3, 1); - d3 = c2^ROL64(c4, 1); - d4 = c3^ROL64(c0, 1); - - b0 = (a00^d0); - b1 = ROL64((a01^d1), 44); - b2 = ROL64((a02^d2), 43); - b3 = ROL64((a03^d3), 21); - b4 = ROL64((a04^d4), 14); - a00 = b0 ^((~b1)& b2 ); - a00 ^= RC[i+3]; - a01 = b1 ^((~b2)& b3 ); - a02 = b2 ^((~b3)& b4 ); - a03 = b3 ^((~b4)& b0 ); - a04 = b4 ^((~b0)& b1 ); - - b2 = ROL64((a10^d0), 3); - b3 = ROL64((a11^d1), 45); - b4 = ROL64((a12^d2), 61); - b0 = ROL64((a13^d3), 28); - b1 = ROL64((a14^d4), 20); - a10 = b0 ^((~b1)& b2 ); - a11 = b1 ^((~b2)& b3 ); - a12 = b2 ^((~b3)& b4 ); - a13 = b3 ^((~b4)& b0 ); - a14 = b4 ^((~b0)& b1 ); - - b4 = ROL64((a20^d0), 18); - b0 = ROL64((a21^d1), 1); - b1 = ROL64((a22^d2), 6); - b2 = ROL64((a23^d3), 25); - b3 = ROL64((a24^d4), 8); - a20 = b0 ^((~b1)& b2 ); - a21 = b1 ^((~b2)& b3 ); - a22 = b2 ^((~b3)& b4 ); - a23 = b3 ^((~b4)& b0 ); - a24 = b4 ^((~b0)& b1 ); - - b1 = ROL64((a30^d0), 36); - b2 = ROL64((a31^d1), 10); - b3 = ROL64((a32^d2), 15); - b4 = ROL64((a33^d3), 56); - b0 = ROL64((a34^d4), 27); - a30 = b0 ^((~b1)& b2 ); - a31 = b1 ^((~b2)& b3 ); - a32 = b2 ^((~b3)& b4 ); - a33 = b3 ^((~b4)& b0 ); - a34 = b4 ^((~b0)& b1 ); - - b3 = ROL64((a40^d0), 41); - b4 = ROL64((a41^d1), 2); - b0 = ROL64((a42^d2), 62); - b1 = ROL64((a43^d3), 55); - b2 = ROL64((a44^d4), 39); - a40 = b0 ^((~b1)& b2 ); - a41 = b1 ^((~b2)& b3 ); - a42 = b2 ^((~b3)& b4 ); - a43 = b3 ^((~b4)& b0 ); - a44 = b4 ^((~b0)& b1 ); - } + for(i=0; i<24; i+=4){ + c0 = a00^a10^a20^a30^a40; + c1 = a01^a11^a21^a31^a41; + c2 = a02^a12^a22^a32^a42; + c3 = a03^a13^a23^a33^a43; + c4 = a04^a14^a24^a34^a44; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a11^d1), 44); + b2 = ROL64((a22^d2), 43); + b3 = ROL64((a33^d3), 21); + b4 = ROL64((a44^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i]; + a11 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a20^d0), 3); + b3 = ROL64((a31^d1), 45); + b4 = ROL64((a42^d2), 61); + b0 = ROL64((a03^d3), 28); + b1 = ROL64((a14^d4), 20); + a20 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a40^d0), 18); + b0 = ROL64((a01^d1), 1); + b1 = ROL64((a12^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a34^d4), 8); + a40 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a10^d0), 36); + b2 = ROL64((a21^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a43^d3), 56); + b0 = ROL64((a04^d4), 27); + a10 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a30^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a02^d2), 62); + b1 = ROL64((a13^d3), 55); + b2 = ROL64((a24^d4), 39); + a30 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + c0 = a00^a20^a40^a10^a30; + c1 = a11^a31^a01^a21^a41; + c2 = a22^a42^a12^a32^a02; + c3 = a33^a03^a23^a43^a13; + c4 = a44^a14^a34^a04^a24; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a31^d1), 44); + b2 = ROL64((a12^d2), 43); + b3 = ROL64((a43^d3), 21); + b4 = ROL64((a24^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+1]; + a31 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a40^d0), 3); + b3 = ROL64((a21^d1), 45); + b4 = ROL64((a02^d2), 61); + b0 = ROL64((a33^d3), 28); + b1 = ROL64((a14^d4), 20); + a40 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a30^d0), 18); + b0 = ROL64((a11^d1), 1); + b1 = ROL64((a42^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a04^d4), 8); + a30 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a20^d0), 36); + b2 = ROL64((a01^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a13^d3), 56); + b0 = ROL64((a44^d4), 27); + a20 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a10^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a22^d2), 62); + b1 = ROL64((a03^d3), 55); + b2 = ROL64((a34^d4), 39); + a10 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + c0 = a00^a40^a30^a20^a10; + c1 = a31^a21^a11^a01^a41; + c2 = a12^a02^a42^a32^a22; + c3 = a43^a33^a23^a13^a03; + c4 = a24^a14^a04^a44^a34; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a21^d1), 44); + b2 = ROL64((a42^d2), 43); + b3 = ROL64((a13^d3), 21); + b4 = ROL64((a34^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+2]; + a21 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a30^d0), 3); + b3 = ROL64((a01^d1), 45); + b4 = ROL64((a22^d2), 61); + b0 = ROL64((a43^d3), 28); + b1 = ROL64((a14^d4), 20); + a30 = b0 ^((~b1)& b2 ); + a01 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a10^d0), 18); + b0 = ROL64((a31^d1), 1); + b1 = ROL64((a02^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a44^d4), 8); + a10 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a40^d0), 36); + b2 = ROL64((a11^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a03^d3), 56); + b0 = ROL64((a24^d4), 27); + a40 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a20^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a12^d2), 62); + b1 = ROL64((a33^d3), 55); + b2 = ROL64((a04^d4), 39); + a20 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + c0 = a00^a30^a10^a40^a20; + c1 = a21^a01^a31^a11^a41; + c2 = a42^a22^a02^a32^a12; + c3 = a13^a43^a23^a03^a33; + c4 = a34^a14^a44^a24^a04; + d0 = c4^ROL64(c1, 1); + d1 = c0^ROL64(c2, 1); + d2 = c1^ROL64(c3, 1); + d3 = c2^ROL64(c4, 1); + d4 = c3^ROL64(c0, 1); + + b0 = (a00^d0); + b1 = ROL64((a01^d1), 44); + b2 = ROL64((a02^d2), 43); + b3 = ROL64((a03^d3), 21); + b4 = ROL64((a04^d4), 14); + a00 = b0 ^((~b1)& b2 ); + a00 ^= RC[i+3]; + a01 = b1 ^((~b2)& b3 ); + a02 = b2 ^((~b3)& b4 ); + a03 = b3 ^((~b4)& b0 ); + a04 = b4 ^((~b0)& b1 ); + + b2 = ROL64((a10^d0), 3); + b3 = ROL64((a11^d1), 45); + b4 = ROL64((a12^d2), 61); + b0 = ROL64((a13^d3), 28); + b1 = ROL64((a14^d4), 20); + a10 = b0 ^((~b1)& b2 ); + a11 = b1 ^((~b2)& b3 ); + a12 = b2 ^((~b3)& b4 ); + a13 = b3 ^((~b4)& b0 ); + a14 = b4 ^((~b0)& b1 ); + + b4 = ROL64((a20^d0), 18); + b0 = ROL64((a21^d1), 1); + b1 = ROL64((a22^d2), 6); + b2 = ROL64((a23^d3), 25); + b3 = ROL64((a24^d4), 8); + a20 = b0 ^((~b1)& b2 ); + a21 = b1 ^((~b2)& b3 ); + a22 = b2 ^((~b3)& b4 ); + a23 = b3 ^((~b4)& b0 ); + a24 = b4 ^((~b0)& b1 ); + + b1 = ROL64((a30^d0), 36); + b2 = ROL64((a31^d1), 10); + b3 = ROL64((a32^d2), 15); + b4 = ROL64((a33^d3), 56); + b0 = ROL64((a34^d4), 27); + a30 = b0 ^((~b1)& b2 ); + a31 = b1 ^((~b2)& b3 ); + a32 = b2 ^((~b3)& b4 ); + a33 = b3 ^((~b4)& b0 ); + a34 = b4 ^((~b0)& b1 ); + + b3 = ROL64((a40^d0), 41); + b4 = ROL64((a41^d1), 2); + b0 = ROL64((a42^d2), 62); + b1 = ROL64((a43^d3), 55); + b2 = ROL64((a44^d4), 39); + a40 = b0 ^((~b1)& b2 ); + a41 = b1 ^((~b2)& b3 ); + a42 = b2 ^((~b3)& b4 ); + a43 = b3 ^((~b4)& b0 ); + a44 = b4 ^((~b0)& b1 ); + } } /* @@ -1827,27 +1827,27 @@ static void KeccakF1600Step(SHA3Context *p){ ** can be zero to use the default hash size of 256 bits. */ static void SHA3Init(SHA3Context *p, int iSize){ - memset(p, 0, sizeof(*p)); - if( iSize>=128 && iSize<=512 ){ - p->nRate = (1600 - ((iSize + 31)&~31)*2)/8; - }else{ - p->nRate = (1600 - 2*256)/8; - } + memset(p, 0, sizeof(*p)); + if( iSize>=128 && iSize<=512 ){ + p->nRate = (1600 - ((iSize + 31)&~31)*2)/8; + }else{ + p->nRate = (1600 - 2*256)/8; + } #if SHA3_BYTEORDER==1234 - /* Known to be little-endian at compile-time. No-op */ + /* Known to be little-endian at compile-time. No-op */ #elif SHA3_BYTEORDER==4321 - p->ixMask = 7; /* Big-endian */ + p->ixMask = 7; /* Big-endian */ #else - { - static unsigned int one = 1; - if( 1==*(unsigned char*)&one ){ - /* Little endian. No byte swapping. */ - p->ixMask = 0; - }else{ - /* Big endian. Byte swap. */ - p->ixMask = 7; - } + { + static unsigned int one = 1; + if( 1==*(unsigned char*)&one ){ + /* Little endian. No byte swapping. */ + p->ixMask = 0; + }else{ + /* Big endian. Byte swap. */ + p->ixMask = 7; } + } #endif } @@ -1856,37 +1856,37 @@ static void SHA3Init(SHA3Context *p, int iSize){ ** to the hash */ static void SHA3Update( - SHA3Context *p, - const unsigned char *aData, - unsigned int nData + SHA3Context *p, + const unsigned char *aData, + unsigned int nData ){ - unsigned int i = 0; + unsigned int i = 0; #if SHA3_BYTEORDER==1234 - if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ - for(; i+7u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; - p->nLoaded += 8; - if( p->nLoaded>=p->nRate ){ - KeccakF1600Step(p); - p->nLoaded = 0; - } - } - } + if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ + for(; i+7u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; + p->nLoaded += 8; + if( p->nLoaded>=p->nRate ){ + KeccakF1600Step(p); + p->nLoaded = 0; + } + } + } #endif - for(; iu.x[p->nLoaded] ^= aData[i]; + p->u.x[p->nLoaded] ^= aData[i]; #elif SHA3_BYTEORDER==4321 - p->u.x[p->nLoaded^0x07] ^= aData[i]; + p->u.x[p->nLoaded^0x07] ^= aData[i]; #else - p->u.x[p->nLoaded^p->ixMask] ^= aData[i]; + p->u.x[p->nLoaded^p->ixMask] ^= aData[i]; #endif - p->nLoaded++; - if( p->nLoaded==p->nRate ){ - KeccakF1600Step(p); - p->nLoaded = 0; - } + p->nLoaded++; + if( p->nLoaded==p->nRate ){ + KeccakF1600Step(p); + p->nLoaded = 0; } + } } /* @@ -1895,21 +1895,21 @@ static void SHA3Update( ** hash value. */ static unsigned char *SHA3Final(SHA3Context *p){ - unsigned int i; - if( p->nLoaded==p->nRate-1 ){ - const unsigned char c1 = 0x86; - SHA3Update(p, &c1, 1); - }else{ - const unsigned char c2 = 0x06; - const unsigned char c3 = 0x80; - SHA3Update(p, &c2, 1); - p->nLoaded = p->nRate - 1; - SHA3Update(p, &c3, 1); - } - for(i=0; inRate; i++){ - p->u.x[i+p->nRate] = p->u.x[i^p->ixMask]; - } - return &p->u.x[p->nRate]; + unsigned int i; + if( p->nLoaded==p->nRate-1 ){ + const unsigned char c1 = 0x86; + SHA3Update(p, &c1, 1); + }else{ + const unsigned char c2 = 0x06; + const unsigned char c3 = 0x80; + SHA3Update(p, &c2, 1); + p->nLoaded = p->nRate - 1; + SHA3Update(p, &c3, 1); + } + for(i=0; inRate; i++){ + p->u.x[i+p->nRate] = p->u.x[i^p->ixMask]; + } + return &p->u.x[p->nRate]; } /* End of the hashing logic *****************************************************************************/ @@ -1918,56 +1918,56 @@ static unsigned char *SHA3Final(SHA3Context *p){ ** Implementation of the sha3(X,SIZE) function. ** ** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default -** size is 256. If X is a BLOB, it is hashed as is. +** size is 256. If X is a BLOB, it is hashed as is. ** For all other non-NULL types of input, X is converted into a UTF-8 string ** and the string is hashed without the trailing 0x00 terminator. The hash ** of a NULL value is NULL. */ static void sha3Func( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - SHA3Context cx; - int eType = sqlite3_value_type(argv[0]); - int nByte = sqlite3_value_bytes(argv[0]); - int iSize; - if( argc==1 ){ - iSize = 256; - }else{ - iSize = sqlite3_value_int(argv[1]); - if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ - sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " - "384 512", -1); - return; - } - } - if( eType==SQLITE_NULL ) return; - SHA3Init(&cx, iSize); - if( eType==SQLITE_BLOB ){ - SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte); - }else{ - SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte); - } - sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); + SHA3Context cx; + int eType = sqlite3_value_type(argv[0]); + int nByte = sqlite3_value_bytes(argv[0]); + int iSize; + if( argc==1 ){ + iSize = 256; + }else{ + iSize = sqlite3_value_int(argv[1]); + if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ + sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " + "384 512", -1); + return; + } + } + if( eType==SQLITE_NULL ) return; + SHA3Init(&cx, iSize); + if( eType==SQLITE_BLOB ){ + SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte); + }else{ + SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte); + } + sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); } /* Compute a string using sqlite3_vsnprintf() with a maximum length ** of 50 bytes and add it to the hash. */ static void hash_step_vformat( - SHA3Context *p, /* Add content to this context */ - const char *zFormat, - ... + SHA3Context *p, /* Add content to this context */ + const char *zFormat, + ... ){ - va_list ap; - int n; - char zBuf[50]; - va_start(ap, zFormat); - sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap); - va_end(ap); - n = (int)strlen(zBuf); - SHA3Update(p, (unsigned char*)zBuf, n); + va_list ap; + int n; + char zBuf[50]; + va_start(ap, zFormat); + sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap); + va_end(ap); + n = (int)strlen(zBuf); + SHA3Update(p, (unsigned char*)zBuf, n); } /* @@ -2003,115 +2003,115 @@ static void hash_step_vformat( ** with no delimiters of any kind. */ static void sha3QueryFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - sqlite3 *db = sqlite3_context_db_handle(context); - const char *zSql = (const char*)sqlite3_value_text(argv[0]); - sqlite3_stmt *pStmt = 0; - int nCol; /* Number of columns in the result set */ - int i; /* Loop counter */ - int rc; - int n; - const char *z; - SHA3Context cx; - int iSize; - - if( argc==1 ){ - iSize = 256; - }else{ - iSize = sqlite3_value_int(argv[1]); - if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ - sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " - "384 512", -1); - return; - } - } - if( zSql==0 ) return; - SHA3Init(&cx, iSize); - while( zSql[0] ){ - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); - if( rc ){ - char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", - zSql, sqlite3_errmsg(db)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - if( !sqlite3_stmt_readonly(pStmt) ){ - char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt)); - sqlite3_finalize(pStmt); - sqlite3_result_error(context, zMsg, -1); - sqlite3_free(zMsg); - return; - } - nCol = sqlite3_column_count(pStmt); - z = sqlite3_sql(pStmt); - if( z ){ - n = (int)strlen(z); - hash_step_vformat(&cx,"S%d:",n); - SHA3Update(&cx,(unsigned char*)z,n); - } - - /* Compute a hash over the result of the query */ - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - SHA3Update(&cx,(const unsigned char*)"R",1); - for(i=0; i=1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'I'; - SHA3Update(&cx, x, 9); - break; - } - case SQLITE_FLOAT: { - sqlite3_uint64 u; - int j; - unsigned char x[9]; - double r = sqlite3_column_double(pStmt,i); - memcpy(&u, &r, 8); - for(j=8; j>=1; j--){ - x[j] = u & 0xff; - u >>= 8; - } - x[0] = 'F'; - SHA3Update(&cx,x,9); - break; - } - case SQLITE_TEXT: { - int n2 = sqlite3_column_bytes(pStmt, i); - const unsigned char *z2 = sqlite3_column_text(pStmt, i); - hash_step_vformat(&cx,"T%d:",n2); - SHA3Update(&cx, z2, n2); - break; - } - case SQLITE_BLOB: { - int n2 = sqlite3_column_bytes(pStmt, i); - const unsigned char *z2 = sqlite3_column_blob(pStmt, i); - hash_step_vformat(&cx,"B%d:",n2); - SHA3Update(&cx, z2, n2); - break; - } - } - } + sqlite3 *db = sqlite3_context_db_handle(context); + const char *zSql = (const char*)sqlite3_value_text(argv[0]); + sqlite3_stmt *pStmt = 0; + int nCol; /* Number of columns in the result set */ + int i; /* Loop counter */ + int rc; + int n; + const char *z; + SHA3Context cx; + int iSize; + + if( argc==1 ){ + iSize = 256; + }else{ + iSize = sqlite3_value_int(argv[1]); + if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){ + sqlite3_result_error(context, "SHA3 size should be one of: 224 256 " + "384 512", -1); + return; + } + } + if( zSql==0 ) return; + SHA3Init(&cx, iSize); + while( zSql[0] ){ + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql); + if( rc ){ + char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s", + zSql, sqlite3_errmsg(db)); + sqlite3_finalize(pStmt); + sqlite3_result_error(context, zMsg, -1); + sqlite3_free(zMsg); + return; + } + if( !sqlite3_stmt_readonly(pStmt) ){ + char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt)); + sqlite3_finalize(pStmt); + sqlite3_result_error(context, zMsg, -1); + sqlite3_free(zMsg); + return; + } + nCol = sqlite3_column_count(pStmt); + z = sqlite3_sql(pStmt); + if( z ){ + n = (int)strlen(z); + hash_step_vformat(&cx,"S%d:",n); + SHA3Update(&cx,(unsigned char*)z,n); + } + + /* Compute a hash over the result of the query */ + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + SHA3Update(&cx,(const unsigned char*)"R",1); + for(i=0; i=1; j--){ + x[j] = u & 0xff; + u >>= 8; + } + x[0] = 'I'; + SHA3Update(&cx, x, 9); + break; + } + case SQLITE_FLOAT: { + sqlite3_uint64 u; + int j; + unsigned char x[9]; + double r = sqlite3_column_double(pStmt,i); + memcpy(&u, &r, 8); + for(j=8; j>=1; j--){ + x[j] = u & 0xff; + u >>= 8; + } + x[0] = 'F'; + SHA3Update(&cx,x,9); + break; + } + case SQLITE_TEXT: { + int n2 = sqlite3_column_bytes(pStmt, i); + const unsigned char *z2 = sqlite3_column_text(pStmt, i); + hash_step_vformat(&cx,"T%d:",n2); + SHA3Update(&cx, z2, n2); + break; + } + case SQLITE_BLOB: { + int n2 = sqlite3_column_bytes(pStmt, i); + const unsigned char *z2 = sqlite3_column_blob(pStmt, i); + hash_step_vformat(&cx,"B%d:",n2); + SHA3Update(&cx, z2, n2); + break; + } } - sqlite3_finalize(pStmt); + } } - sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); + sqlite3_finalize(pStmt); + } + sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); } @@ -2119,32 +2119,32 @@ static void sha3QueryFunc( #endif int sqlite3_shathree_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - rc = sqlite3_create_function(db, "sha3", 1, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, sha3Func, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3", 2, - SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, - 0, sha3Func, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_query", 1, - SQLITE_UTF8 | SQLITE_DIRECTONLY, - 0, sha3QueryFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "sha3_query", 2, - SQLITE_UTF8 | SQLITE_DIRECTONLY, - 0, sha3QueryFunc, 0, 0); - } - return rc; + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "sha3", 1, + SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, + 0, sha3Func, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "sha3", 2, + SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC, + 0, sha3Func, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "sha3_query", 1, + SQLITE_UTF8 | SQLITE_DIRECTONLY, + 0, sha3QueryFunc, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "sha3_query", 2, + SQLITE_UTF8 | SQLITE_DIRECTONLY, + 0, sha3QueryFunc, 0, 0); + } + return rc; } /************************* End ../ext/misc/shathree.c ********************/ @@ -2220,8 +2220,8 @@ int sqlite3_shathree_init( ** directory, NULL. ** ** If a non-NULL value is specified for the optional $dir parameter and -** $path is a relative path, then $path is interpreted relative to $dir. -** And the paths returned in the "name" column of the table are also +** $path is a relative path, then $path is interpreted relative to $dir. +** And the paths returned in the "name" column of the table are also ** relative to directory $dir. ** ** Notes on building this extension for Windows: @@ -2265,7 +2265,7 @@ SQLITE_EXTENSION_INIT1 /* ** Structure of the fsdir() table-valued function */ -/* 0 1 2 3 4 5 */ + /* 0 1 2 3 4 5 */ #define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)" #define FSDIR_COLUMN_NAME 0 /* Name of the file */ #define FSDIR_COLUMN_MODE 1 /* Access mode */ @@ -2276,7 +2276,7 @@ SQLITE_EXTENSION_INIT1 /* -** Set the result stored by context ctx to a blob containing the +** Set the result stored by context ctx to a blob containing the ** contents of file zName. Or, leave the result unchanged (NULL) ** if the file does not exist or is unreadable. ** @@ -2287,40 +2287,40 @@ SQLITE_EXTENSION_INIT1 ** off of disk. */ static void readFileContents(sqlite3_context *ctx, const char *zName){ - FILE *in; - sqlite3_int64 nIn; - void *pBuf; - sqlite3 *db; - int mxBlob; - - in = fopen(zName, "rb"); - if( in==0 ){ - /* File does not exist or is unreadable. Leave the result set to NULL. */ - return; - } - fseek(in, 0, SEEK_END); - nIn = ftell(in); - rewind(in); - db = sqlite3_context_db_handle(ctx); - mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1); - if( nIn>mxBlob ){ - sqlite3_result_error_code(ctx, SQLITE_TOOBIG); - fclose(in); - return; - } - pBuf = sqlite3_malloc64( nIn ? nIn : 1 ); - if( pBuf==0 ){ - sqlite3_result_error_nomem(ctx); - fclose(in); - return; - } - if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){ - sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free); - }else{ - sqlite3_result_error_code(ctx, SQLITE_IOERR); - sqlite3_free(pBuf); - } + FILE *in; + sqlite3_int64 nIn; + void *pBuf; + sqlite3 *db; + int mxBlob; + + in = fopen(zName, "rb"); + if( in==0 ){ + /* File does not exist or is unreadable. Leave the result set to NULL. */ + return; + } + fseek(in, 0, SEEK_END); + nIn = ftell(in); + rewind(in); + db = sqlite3_context_db_handle(ctx); + mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1); + if( nIn>mxBlob ){ + sqlite3_result_error_code(ctx, SQLITE_TOOBIG); fclose(in); + return; + } + pBuf = sqlite3_malloc64( nIn ? nIn : 1 ); + if( pBuf==0 ){ + sqlite3_result_error_nomem(ctx); + fclose(in); + return; + } + if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){ + sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free); + }else{ + sqlite3_result_error_code(ctx, SQLITE_IOERR); + sqlite3_free(pBuf); + } + fclose(in); } /* @@ -2329,15 +2329,15 @@ static void readFileContents(sqlite3_context *ctx, const char *zName){ ** if the file does not exist or is unreadable. */ static void readfileFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - const char *zName; - (void)(argc); /* Unused parameter */ - zName = (const char*)sqlite3_value_text(argv[0]); - if( zName==0 ) return; - readFileContents(context, zName); + const char *zName; + (void)(argc); /* Unused parameter */ + zName = (const char*)sqlite3_value_text(argv[0]); + if( zName==0 ) return; + readFileContents(context, zName); } /* @@ -2345,13 +2345,13 @@ static void readfileFunc( ** vprintf(zFmt, ...). */ static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){ - char *zMsg = 0; - va_list ap; - va_start(ap, zFmt); - zMsg = sqlite3_vmprintf(zFmt, ap); - sqlite3_result_error(ctx, zMsg, -1); - sqlite3_free(zMsg); - va_end(ap); + char *zMsg = 0; + va_list ap; + va_start(ap, zFmt); + zMsg = sqlite3_vmprintf(zFmt, ap); + sqlite3_result_error(ctx, zMsg, -1); + sqlite3_free(zMsg); + va_end(ap); } #if defined(_WIN32) @@ -2360,25 +2360,25 @@ static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){ ** number of seconds since the Unix Epoch (1970-01-01 00:00:00 UTC). */ static sqlite3_uint64 fileTimeToUnixTime( - LPFILETIME pFileTime + LPFILETIME pFileTime ){ - SYSTEMTIME epochSystemTime; - ULARGE_INTEGER epochIntervals; - FILETIME epochFileTime; - ULARGE_INTEGER fileIntervals; + SYSTEMTIME epochSystemTime; + ULARGE_INTEGER epochIntervals; + FILETIME epochFileTime; + ULARGE_INTEGER fileIntervals; - memset(&epochSystemTime, 0, sizeof(SYSTEMTIME)); - epochSystemTime.wYear = 1970; - epochSystemTime.wMonth = 1; - epochSystemTime.wDay = 1; - SystemTimeToFileTime(&epochSystemTime, &epochFileTime); - epochIntervals.LowPart = epochFileTime.dwLowDateTime; - epochIntervals.HighPart = epochFileTime.dwHighDateTime; + memset(&epochSystemTime, 0, sizeof(SYSTEMTIME)); + epochSystemTime.wYear = 1970; + epochSystemTime.wMonth = 1; + epochSystemTime.wDay = 1; + SystemTimeToFileTime(&epochSystemTime, &epochFileTime); + epochIntervals.LowPart = epochFileTime.dwLowDateTime; + epochIntervals.HighPart = epochFileTime.dwHighDateTime; - fileIntervals.LowPart = pFileTime->dwLowDateTime; - fileIntervals.HighPart = pFileTime->dwHighDateTime; + fileIntervals.LowPart = pFileTime->dwLowDateTime; + fileIntervals.HighPart = pFileTime->dwHighDateTime; - return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; + return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; } @@ -2388,12 +2388,12 @@ static sqlite3_uint64 fileTimeToUnixTime( # define sqlite3_win32_utf8_to_unicode utf8_to_utf16 # LPWSTR utf8_to_utf16(const char *z){ - int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0); - LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR)); - if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) ) - return rv; - sqlite3_free(rv); - return 0; + int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0); + LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR)); + if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) ) + return rv; + sqlite3_free(rv); + return 0; } #endif @@ -2403,25 +2403,25 @@ LPWSTR utf8_to_utf16(const char *z){ ** appears to return these values as local times. */ static void statTimesToUtc( - const char *zPath, - struct stat *pStatBuf + const char *zPath, + struct stat *pStatBuf ){ - HANDLE hFindFile; - WIN32_FIND_DATAW fd; - LPWSTR zUnicodeName; - extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); - zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath); - if( zUnicodeName ){ - memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); - hFindFile = FindFirstFileW(zUnicodeName, &fd); - if( hFindFile!=NULL ){ - pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); - pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); - pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); - FindClose(hFindFile); - } - sqlite3_free(zUnicodeName); - } + HANDLE hFindFile; + WIN32_FIND_DATAW fd; + LPWSTR zUnicodeName; + extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); + zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath); + if( zUnicodeName ){ + memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); + hFindFile = FindFirstFileW(zUnicodeName, &fd); + if( hFindFile!=NULL ){ + pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); + pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); + pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); + FindClose(hFindFile); + } + sqlite3_free(zUnicodeName); + } } #endif @@ -2431,15 +2431,15 @@ static void statTimesToUtc( ** other systems, this function simply calls stat(). */ static int fileStat( - const char *zPath, - struct stat *pStatBuf + const char *zPath, + struct stat *pStatBuf ){ #if defined(_WIN32) - int rc = stat(zPath, pStatBuf); - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); - return rc; + int rc = stat(zPath, pStatBuf); + if( rc==0 ) statTimesToUtc(zPath, pStatBuf); + return rc; #else - return stat(zPath, pStatBuf); + return stat(zPath, pStatBuf); #endif } @@ -2449,15 +2449,15 @@ static int fileStat( ** other systems, this function simply calls lstat(). */ static int fileLinkStat( - const char *zPath, - struct stat *pStatBuf + const char *zPath, + struct stat *pStatBuf ){ #if defined(_WIN32) - int rc = lstat(zPath, pStatBuf); - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); - return rc; + int rc = lstat(zPath, pStatBuf); + if( rc==0 ) statTimesToUtc(zPath, pStatBuf); + return rc; #else - return lstat(zPath, pStatBuf); + return lstat(zPath, pStatBuf); #endif } @@ -2473,201 +2473,201 @@ static int fileLinkStat( ** SQLITE_ERROR otherwise. */ static int makeDirectory( - const char *zFile + const char *zFile ){ - char *zCopy = sqlite3_mprintf("%s", zFile); - int rc = SQLITE_OK; + char *zCopy = sqlite3_mprintf("%s", zFile); + int rc = SQLITE_OK; - if( zCopy==0 ){ - rc = SQLITE_NOMEM; - }else{ - int nCopy = (int)strlen(zCopy); - int i = 1; + if( zCopy==0 ){ + rc = SQLITE_NOMEM; + }else{ + int nCopy = (int)strlen(zCopy); + int i = 1; - while( rc==SQLITE_OK ){ - struct stat sStat; - int rc2; + while( rc==SQLITE_OK ){ + struct stat sStat; + int rc2; - for(; zCopy[i]!='/' && i=0 ){ + } + }else{ + sqlite3_int64 nWrite = 0; + const char *z; + int rc = 0; + FILE *out = fopen(zFile, "wb"); + if( out==0 ) return 1; + z = (const char*)sqlite3_value_blob(pData); + if( z ){ + sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out); + nWrite = sqlite3_value_bytes(pData); + if( nWrite!=n ){ + rc = 1; + } + } + fclose(out); + if( rc==0 && mode && chmod(zFile, mode & 0777) ){ + rc = 1; + } + if( rc ) return 2; + sqlite3_result_int64(pCtx, nWrite); + } + } + + if( mtime>=0 ){ #if defined(_WIN32) #if !SQLITE_OS_WINRT - /* Windows */ - FILETIME lastAccess; - FILETIME lastWrite; - SYSTEMTIME currentTime; - LONGLONG intervals; - HANDLE hFile; - LPWSTR zUnicodeName; - extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); - - GetSystemTime(¤tTime); - SystemTimeToFileTime(¤tTime, &lastAccess); - intervals = Int32x32To64(mtime, 10000000) + 116444736000000000; - lastWrite.dwLowDateTime = (DWORD)intervals; - lastWrite.dwHighDateTime = intervals >> 32; - zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile); - if( zUnicodeName==0 ){ - return 1; - } - hFile = CreateFileW( - zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL - ); - sqlite3_free(zUnicodeName); - if( hFile!=INVALID_HANDLE_VALUE ){ - BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite); - CloseHandle(hFile); - return !bResult; - }else{ - return 1; - } + /* Windows */ + FILETIME lastAccess; + FILETIME lastWrite; + SYSTEMTIME currentTime; + LONGLONG intervals; + HANDLE hFile; + LPWSTR zUnicodeName; + extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); + + GetSystemTime(¤tTime); + SystemTimeToFileTime(¤tTime, &lastAccess); + intervals = Int32x32To64(mtime, 10000000) + 116444736000000000; + lastWrite.dwLowDateTime = (DWORD)intervals; + lastWrite.dwHighDateTime = intervals >> 32; + zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile); + if( zUnicodeName==0 ){ + return 1; + } + hFile = CreateFileW( + zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL + ); + sqlite3_free(zUnicodeName); + if( hFile!=INVALID_HANDLE_VALUE ){ + BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite); + CloseHandle(hFile); + return !bResult; + }else{ + return 1; + } #endif #elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */ - /* Recent unix */ - struct timespec times[2]; - times[0].tv_nsec = times[1].tv_nsec = 0; - times[0].tv_sec = time(0); - times[1].tv_sec = mtime; - if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){ - return 1; - } + /* Recent unix */ + struct timespec times[2]; + times[0].tv_nsec = times[1].tv_nsec = 0; + times[0].tv_sec = time(0); + times[1].tv_sec = mtime; + if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){ + return 1; + } #else - /* Legacy unix */ - struct timeval times[2]; - times[0].tv_usec = times[1].tv_usec = 0; - times[0].tv_sec = time(0); - times[1].tv_sec = mtime; - if( utimes(zFile, times) ){ - return 1; - } -#endif + /* Legacy unix */ + struct timeval times[2]; + times[0].tv_usec = times[1].tv_usec = 0; + times[0].tv_sec = time(0); + times[1].tv_sec = mtime; + if( utimes(zFile, times) ){ + return 1; } +#endif + } - return 0; + return 0; } /* -** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function. +** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function. ** Refer to header comments at the top of this file for details. */ static void writefileFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - const char *zFile; - mode_t mode = 0; - int res; - sqlite3_int64 mtime = -1; - - if( argc<2 || argc>4 ){ - sqlite3_result_error(context, - "wrong number of arguments to function writefile()", -1 - ); - return; - } - - zFile = (const char*)sqlite3_value_text(argv[0]); - if( zFile==0 ) return; - if( argc>=3 ){ - mode = (mode_t)sqlite3_value_int(argv[2]); - } - if( argc==4 ){ - mtime = sqlite3_value_int64(argv[3]); - } - - res = writeFile(context, zFile, argv[1], mode, mtime); - if( res==1 && errno==ENOENT ){ - if( makeDirectory(zFile)==SQLITE_OK ){ - res = writeFile(context, zFile, argv[1], mode, mtime); - } - } - - if( argc>2 && res!=0 ){ - if( S_ISLNK(mode) ){ - ctxErrorMsg(context, "failed to create symlink: %s", zFile); - }else if( S_ISDIR(mode) ){ - ctxErrorMsg(context, "failed to create directory: %s", zFile); - }else{ - ctxErrorMsg(context, "failed to write file: %s", zFile); - } + const char *zFile; + mode_t mode = 0; + int res; + sqlite3_int64 mtime = -1; + + if( argc<2 || argc>4 ){ + sqlite3_result_error(context, + "wrong number of arguments to function writefile()", -1 + ); + return; + } + + zFile = (const char*)sqlite3_value_text(argv[0]); + if( zFile==0 ) return; + if( argc>=3 ){ + mode = (mode_t)sqlite3_value_int(argv[2]); + } + if( argc==4 ){ + mtime = sqlite3_value_int64(argv[3]); + } + + res = writeFile(context, zFile, argv[1], mode, mtime); + if( res==1 && errno==ENOENT ){ + if( makeDirectory(zFile)==SQLITE_OK ){ + res = writeFile(context, zFile, argv[1], mode, mtime); + } + } + + if( argc>2 && res!=0 ){ + if( S_ISLNK(mode) ){ + ctxErrorMsg(context, "failed to create symlink: %s", zFile); + }else if( S_ISDIR(mode) ){ + ctxErrorMsg(context, "failed to create directory: %s", zFile); + }else{ + ctxErrorMsg(context, "failed to write file: %s", zFile); } + } } /* @@ -2677,114 +2677,114 @@ static void writefileFunc( ** text string in the style of "ls -l". */ static void lsModeFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - int i; - int iMode = sqlite3_value_int(argv[0]); - char z[16]; - (void)argc; - if( S_ISLNK(iMode) ){ - z[0] = 'l'; - }else if( S_ISREG(iMode) ){ - z[0] = '-'; - }else if( S_ISDIR(iMode) ){ - z[0] = 'd'; - }else{ - z[0] = '?'; - } - for(i=0; i<3; i++){ - int m = (iMode >> ((2-i)*3)); - char *a = &z[1 + i*3]; - a[0] = (m & 0x4) ? 'r' : '-'; - a[1] = (m & 0x2) ? 'w' : '-'; - a[2] = (m & 0x1) ? 'x' : '-'; - } - z[10] = '\0'; - sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); + int i; + int iMode = sqlite3_value_int(argv[0]); + char z[16]; + (void)argc; + if( S_ISLNK(iMode) ){ + z[0] = 'l'; + }else if( S_ISREG(iMode) ){ + z[0] = '-'; + }else if( S_ISDIR(iMode) ){ + z[0] = 'd'; + }else{ + z[0] = '?'; + } + for(i=0; i<3; i++){ + int m = (iMode >> ((2-i)*3)); + char *a = &z[1 + i*3]; + a[0] = (m & 0x4) ? 'r' : '-'; + a[1] = (m & 0x2) ? 'w' : '-'; + a[2] = (m & 0x1) ? 'x' : '-'; + } + z[10] = '\0'; + sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_VIRTUALTABLE -/* +/* ** Cursor type for recursively iterating through a directory structure. */ typedef struct fsdir_cursor fsdir_cursor; typedef struct FsdirLevel FsdirLevel; struct FsdirLevel { - DIR *pDir; /* From opendir() */ - char *zDir; /* Name of directory (nul-terminated) */ + DIR *pDir; /* From opendir() */ + char *zDir; /* Name of directory (nul-terminated) */ }; struct fsdir_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3_vtab_cursor base; /* Base class - must be first */ - int nLvl; /* Number of entries in aLvl[] array */ - int iLvl; /* Index of current entry */ - FsdirLevel *aLvl; /* Hierarchy of directories being traversed */ + int nLvl; /* Number of entries in aLvl[] array */ + int iLvl; /* Index of current entry */ + FsdirLevel *aLvl; /* Hierarchy of directories being traversed */ - const char *zBase; - int nBase; + const char *zBase; + int nBase; - struct stat sStat; /* Current lstat() results */ - char *zPath; /* Path to current entry */ - sqlite3_int64 iRowid; /* Current rowid */ + struct stat sStat; /* Current lstat() results */ + char *zPath; /* Path to current entry */ + sqlite3_int64 iRowid; /* Current rowid */ }; typedef struct fsdir_tab fsdir_tab; struct fsdir_tab { - sqlite3_vtab base; /* Base class - must be first */ + sqlite3_vtab base; /* Base class - must be first */ }; /* ** Construct a new fsdir virtual table object. */ static int fsdirConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr ){ - fsdir_tab *pNew = 0; - int rc; - (void)pAux; - (void)argc; - (void)argv; - (void)pzErr; - rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA); - if( rc==SQLITE_OK ){ - pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) ); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); - } - *ppVtab = (sqlite3_vtab*)pNew; - return rc; + fsdir_tab *pNew = 0; + int rc; + (void)pAux; + (void)argc; + (void)argv; + (void)pzErr; + rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA); + if( rc==SQLITE_OK ){ + pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) ); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); + } + *ppVtab = (sqlite3_vtab*)pNew; + return rc; } /* ** This method is the destructor for fsdir vtab objects. */ static int fsdirDisconnect(sqlite3_vtab *pVtab){ - sqlite3_free(pVtab); - return SQLITE_OK; + sqlite3_free(pVtab); + return SQLITE_OK; } /* ** Constructor for a new fsdir_cursor object. */ static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - fsdir_cursor *pCur; - (void)p; - pCur = sqlite3_malloc( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - pCur->iLvl = -1; - *ppCursor = &pCur->base; - return SQLITE_OK; + fsdir_cursor *pCur; + (void)p; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + pCur->iLvl = -1; + *ppCursor = &pCur->base; + return SQLITE_OK; } /* @@ -2792,32 +2792,32 @@ static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ ** by fsdirOpen(). */ static void fsdirResetCursor(fsdir_cursor *pCur){ - int i; - for(i=0; i<=pCur->iLvl; i++){ - FsdirLevel *pLvl = &pCur->aLvl[i]; - if( pLvl->pDir ) closedir(pLvl->pDir); - sqlite3_free(pLvl->zDir); - } - sqlite3_free(pCur->zPath); - sqlite3_free(pCur->aLvl); - pCur->aLvl = 0; - pCur->zPath = 0; - pCur->zBase = 0; - pCur->nBase = 0; - pCur->nLvl = 0; - pCur->iLvl = -1; - pCur->iRowid = 1; + int i; + for(i=0; i<=pCur->iLvl; i++){ + FsdirLevel *pLvl = &pCur->aLvl[i]; + if( pLvl->pDir ) closedir(pLvl->pDir); + sqlite3_free(pLvl->zDir); + } + sqlite3_free(pCur->zPath); + sqlite3_free(pCur->aLvl); + pCur->aLvl = 0; + pCur->zPath = 0; + pCur->zBase = 0; + pCur->nBase = 0; + pCur->nLvl = 0; + pCur->iLvl = -1; + pCur->iRowid = 1; } /* ** Destructor for an fsdir_cursor. */ static int fsdirClose(sqlite3_vtab_cursor *cur){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; + fsdir_cursor *pCur = (fsdir_cursor*)cur; - fsdirResetCursor(pCur); - sqlite3_free(pCur); - return SQLITE_OK; + fsdirResetCursor(pCur); + sqlite3_free(pCur); + return SQLITE_OK; } /* @@ -2825,10 +2825,10 @@ static int fsdirClose(sqlite3_vtab_cursor *cur){ ** pCur to the results of vprintf(zFmt, ...). */ static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){ - va_list ap; - va_start(ap, zFmt); - pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap); - va_end(ap); + va_list ap; + va_start(ap, zFmt); + pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap); + va_end(ap); } @@ -2836,63 +2836,63 @@ static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){ ** Advance an fsdir_cursor to its next row of output. */ static int fsdirNext(sqlite3_vtab_cursor *cur){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - mode_t m = pCur->sStat.st_mode; - - pCur->iRowid++; - if( S_ISDIR(m) ){ - /* Descend into this directory */ - int iNew = pCur->iLvl + 1; - FsdirLevel *pLvl; - if( iNew>=pCur->nLvl ){ - int nNew = iNew+1; - sqlite3_int64 nByte = nNew*sizeof(FsdirLevel); - FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte); - if( aNew==0 ) return SQLITE_NOMEM; - memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl)); - pCur->aLvl = aNew; - pCur->nLvl = nNew; - } - pCur->iLvl = iNew; - pLvl = &pCur->aLvl[iNew]; - - pLvl->zDir = pCur->zPath; - pCur->zPath = 0; - pLvl->pDir = opendir(pLvl->zDir); - if( pLvl->pDir==0 ){ - fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath); - return SQLITE_ERROR; - } + fsdir_cursor *pCur = (fsdir_cursor*)cur; + mode_t m = pCur->sStat.st_mode; + + pCur->iRowid++; + if( S_ISDIR(m) ){ + /* Descend into this directory */ + int iNew = pCur->iLvl + 1; + FsdirLevel *pLvl; + if( iNew>=pCur->nLvl ){ + int nNew = iNew+1; + sqlite3_int64 nByte = nNew*sizeof(FsdirLevel); + FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte); + if( aNew==0 ) return SQLITE_NOMEM; + memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl)); + pCur->aLvl = aNew; + pCur->nLvl = nNew; + } + pCur->iLvl = iNew; + pLvl = &pCur->aLvl[iNew]; + + pLvl->zDir = pCur->zPath; + pCur->zPath = 0; + pLvl->pDir = opendir(pLvl->zDir); + if( pLvl->pDir==0 ){ + fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath); + return SQLITE_ERROR; } + } - while( pCur->iLvl>=0 ){ - FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl]; - struct dirent *pEntry = readdir(pLvl->pDir); - if( pEntry ){ - if( pEntry->d_name[0]=='.' ){ - if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue; - if( pEntry->d_name[1]=='\0' ) continue; - } - sqlite3_free(pCur->zPath); - pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name); - if( pCur->zPath==0 ) return SQLITE_NOMEM; - if( fileLinkStat(pCur->zPath, &pCur->sStat) ){ - fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath); - return SQLITE_ERROR; - } - return SQLITE_OK; - } - closedir(pLvl->pDir); - sqlite3_free(pLvl->zDir); - pLvl->pDir = 0; - pLvl->zDir = 0; - pCur->iLvl--; + while( pCur->iLvl>=0 ){ + FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl]; + struct dirent *pEntry = readdir(pLvl->pDir); + if( pEntry ){ + if( pEntry->d_name[0]=='.' ){ + if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue; + if( pEntry->d_name[1]=='\0' ) continue; + } + sqlite3_free(pCur->zPath); + pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name); + if( pCur->zPath==0 ) return SQLITE_NOMEM; + if( fileLinkStat(pCur->zPath, &pCur->sStat) ){ + fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath); + return SQLITE_ERROR; + } + return SQLITE_OK; } + closedir(pLvl->pDir); + sqlite3_free(pLvl->zDir); + pLvl->pDir = 0; + pLvl->zDir = 0; + pCur->iLvl--; + } - /* EOF */ - sqlite3_free(pCur->zPath); - pCur->zPath = 0; - return SQLITE_OK; + /* EOF */ + sqlite3_free(pCur->zPath); + pCur->zPath = 0; + return SQLITE_OK; } /* @@ -2900,63 +2900,63 @@ static int fsdirNext(sqlite3_vtab_cursor *cur){ ** is currently pointing. */ static int fsdirColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ ){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - switch( i ){ - case FSDIR_COLUMN_NAME: { - sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT); - break; - } + fsdir_cursor *pCur = (fsdir_cursor*)cur; + switch( i ){ + case FSDIR_COLUMN_NAME: { + sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT); + break; + } - case FSDIR_COLUMN_MODE: - sqlite3_result_int64(ctx, pCur->sStat.st_mode); - break; + case FSDIR_COLUMN_MODE: + sqlite3_result_int64(ctx, pCur->sStat.st_mode); + break; - case FSDIR_COLUMN_MTIME: - sqlite3_result_int64(ctx, pCur->sStat.st_mtime); - break; + case FSDIR_COLUMN_MTIME: + sqlite3_result_int64(ctx, pCur->sStat.st_mtime); + break; - case FSDIR_COLUMN_DATA: { - mode_t m = pCur->sStat.st_mode; - if( S_ISDIR(m) ){ - sqlite3_result_null(ctx); + case FSDIR_COLUMN_DATA: { + mode_t m = pCur->sStat.st_mode; + if( S_ISDIR(m) ){ + sqlite3_result_null(ctx); #if !defined(_WIN32) && !defined(WIN32) - }else if( S_ISLNK(m) ){ - char aStatic[64]; - char *aBuf = aStatic; - sqlite3_int64 nBuf = 64; - int n; - - while( 1 ){ - n = readlink(pCur->zPath, aBuf, nBuf); - if( nzPath, aBuf, nBuf); + if( nzPath); - } - } - case FSDIR_COLUMN_PATH: - default: { - /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters. + }else{ + readFileContents(ctx, pCur->zPath); + } + } + case FSDIR_COLUMN_PATH: + default: { + /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters. ** always return their values as NULL */ - break; - } + break; } - return SQLITE_OK; + } + return SQLITE_OK; } /* @@ -2965,9 +2965,9 @@ static int fsdirColumn( ** row a value 1 more than that of the previous. */ static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - *pRowid = pCur->iRowid; - return SQLITE_OK; + fsdir_cursor *pCur = (fsdir_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; } /* @@ -2975,8 +2975,8 @@ static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ** row of output. */ static int fsdirEof(sqlite3_vtab_cursor *cur){ - fsdir_cursor *pCur = (fsdir_cursor*)cur; - return (pCur->zPath==0); + fsdir_cursor *pCur = (fsdir_cursor*)cur; + return (pCur->zPath==0); } /* @@ -2986,45 +2986,45 @@ static int fsdirEof(sqlite3_vtab_cursor *cur){ ** idxNum==2 Both PATH and DIR supplied */ static int fsdirFilter( - sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv ){ - const char *zDir = 0; - fsdir_cursor *pCur = (fsdir_cursor*)cur; - (void)idxStr; - fsdirResetCursor(pCur); - - if( idxNum==0 ){ - fsdirSetErrmsg(pCur, "table function fsdir requires an argument"); - return SQLITE_ERROR; - } + const char *zDir = 0; + fsdir_cursor *pCur = (fsdir_cursor*)cur; + (void)idxStr; + fsdirResetCursor(pCur); - assert( argc==idxNum && (argc==1 || argc==2) ); - zDir = (const char*)sqlite3_value_text(argv[0]); - if( zDir==0 ){ - fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument"); - return SQLITE_ERROR; - } - if( argc==2 ){ - pCur->zBase = (const char*)sqlite3_value_text(argv[1]); - } - if( pCur->zBase ){ - pCur->nBase = (int)strlen(pCur->zBase)+1; - pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir); - }else{ - pCur->zPath = sqlite3_mprintf("%s", zDir); - } + if( idxNum==0 ){ + fsdirSetErrmsg(pCur, "table function fsdir requires an argument"); + return SQLITE_ERROR; + } - if( pCur->zPath==0 ){ - return SQLITE_NOMEM; - } - if( fileLinkStat(pCur->zPath, &pCur->sStat) ){ - fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath); - return SQLITE_ERROR; - } + assert( argc==idxNum && (argc==1 || argc==2) ); + zDir = (const char*)sqlite3_value_text(argv[0]); + if( zDir==0 ){ + fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument"); + return SQLITE_ERROR; + } + if( argc==2 ){ + pCur->zBase = (const char*)sqlite3_value_text(argv[1]); + } + if( pCur->zBase ){ + pCur->nBase = (int)strlen(pCur->zBase)+1; + pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir); + }else{ + pCur->zPath = sqlite3_mprintf("%s", zDir); + } + + if( pCur->zPath==0 ){ + return SQLITE_NOMEM; + } + if( fileLinkStat(pCur->zPath, &pCur->sStat) ){ + fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath); + return SQLITE_ERROR; + } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -3042,101 +3042,101 @@ static int fsdirFilter( ** (2) Path is in argv[0] and dir is in argv[1] */ static int fsdirBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo ){ - int i; /* Loop over constraints */ - int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */ - int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */ - int seenPath = 0; /* True if an unusable PATH= constraint is seen */ - int seenDir = 0; /* True if an unusable DIR= constraint is seen */ - const struct sqlite3_index_constraint *pConstraint; - - (void)tab; - pConstraint = pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case FSDIR_COLUMN_PATH: { - if( pConstraint->usable ){ - idxPath = i; - seenPath = 0; - }else if( idxPath<0 ){ - seenPath = 1; - } - break; - } - case FSDIR_COLUMN_DIR: { - if( pConstraint->usable ){ - idxDir = i; - seenDir = 0; - }else if( idxDir<0 ){ - seenDir = 1; - } - break; - } - } - } - if( seenPath || seenDir ){ - /* If input parameters are unusable, disallow this plan */ - return SQLITE_CONSTRAINT; - } - - if( idxPath<0 ){ - pIdxInfo->idxNum = 0; - /* The pIdxInfo->estimatedCost should have been initialized to a huge + int i; /* Loop over constraints */ + int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */ + int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */ + int seenPath = 0; /* True if an unusable PATH= constraint is seen */ + int seenDir = 0; /* True if an unusable DIR= constraint is seen */ + const struct sqlite3_index_constraint *pConstraint; + + (void)tab; + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + switch( pConstraint->iColumn ){ + case FSDIR_COLUMN_PATH: { + if( pConstraint->usable ){ + idxPath = i; + seenPath = 0; + }else if( idxPath<0 ){ + seenPath = 1; + } + break; + } + case FSDIR_COLUMN_DIR: { + if( pConstraint->usable ){ + idxDir = i; + seenDir = 0; + }else if( idxDir<0 ){ + seenDir = 1; + } + break; + } + } + } + if( seenPath || seenDir ){ + /* If input parameters are unusable, disallow this plan */ + return SQLITE_CONSTRAINT; + } + + if( idxPath<0 ){ + pIdxInfo->idxNum = 0; + /* The pIdxInfo->estimatedCost should have been initialized to a huge ** number. Leave it unchanged. */ - pIdxInfo->estimatedRows = 0x7fffffff; + pIdxInfo->estimatedRows = 0x7fffffff; + }else{ + pIdxInfo->aConstraintUsage[idxPath].omit = 1; + pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1; + if( idxDir>=0 ){ + pIdxInfo->aConstraintUsage[idxDir].omit = 1; + pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2; + pIdxInfo->idxNum = 2; + pIdxInfo->estimatedCost = 10.0; }else{ - pIdxInfo->aConstraintUsage[idxPath].omit = 1; - pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1; - if( idxDir>=0 ){ - pIdxInfo->aConstraintUsage[idxDir].omit = 1; - pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2; - pIdxInfo->idxNum = 2; - pIdxInfo->estimatedCost = 10.0; - }else{ - pIdxInfo->idxNum = 1; - pIdxInfo->estimatedCost = 100.0; - } + pIdxInfo->idxNum = 1; + pIdxInfo->estimatedCost = 100.0; } + } - return SQLITE_OK; + return SQLITE_OK; } /* ** Register the "fsdir" virtual table. */ static int fsdirRegister(sqlite3 *db){ - static sqlite3_module fsdirModule = { - 0, /* iVersion */ - 0, /* xCreate */ - fsdirConnect, /* xConnect */ - fsdirBestIndex, /* xBestIndex */ - fsdirDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - fsdirOpen, /* xOpen - open a cursor */ - fsdirClose, /* xClose - close a cursor */ - fsdirFilter, /* xFilter - configure scan constraints */ - fsdirNext, /* xNext - advance a cursor */ - fsdirEof, /* xEof - check for end of scan */ - fsdirColumn, /* xColumn - read data */ - fsdirRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0, /* xShadowName */ - }; + static sqlite3_module fsdirModule = { + 0, /* iVersion */ + 0, /* xCreate */ + fsdirConnect, /* xConnect */ + fsdirBestIndex, /* xBestIndex */ + fsdirDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + fsdirOpen, /* xOpen - open a cursor */ + fsdirClose, /* xClose - close a cursor */ + fsdirFilter, /* xFilter - configure scan constraints */ + fsdirNext, /* xNext - advance a cursor */ + fsdirEof, /* xEof - check for end of scan */ + fsdirColumn, /* xColumn - read data */ + fsdirRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0, /* xShadowName */ + }; - int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0); - return rc; + int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0); + return rc; } #else /* SQLITE_OMIT_VIRTUALTABLE */ # define fsdirRegister(x) SQLITE_OK @@ -3146,29 +3146,29 @@ static int fsdirRegister(sqlite3 *db){ #endif int sqlite3_fileio_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - rc = sqlite3_create_function(db, "readfile", 1, - SQLITE_UTF8|SQLITE_DIRECTONLY, 0, - readfileFunc, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "writefile", -1, - SQLITE_UTF8|SQLITE_DIRECTONLY, 0, - writefileFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0, - lsModeFunc, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = fsdirRegister(db); - } - return rc; + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + rc = sqlite3_create_function(db, "readfile", 1, + SQLITE_UTF8|SQLITE_DIRECTONLY, 0, + readfileFunc, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "writefile", -1, + SQLITE_UTF8|SQLITE_DIRECTONLY, 0, + writefileFunc, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0, + lsModeFunc, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = fsdirRegister(db); + } + return rc; } #if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) @@ -3229,8 +3229,8 @@ SQLITE_EXTENSION_INIT1 */ typedef struct completion_vtab completion_vtab; struct completion_vtab { - sqlite3_vtab base; /* Base class - must be first */ - sqlite3 *db; /* Database connection for this completion vtab */ + sqlite3_vtab base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this completion vtab */ }; /* completion_cursor is a subclass of sqlite3_vtab_cursor which will @@ -3239,17 +3239,17 @@ struct completion_vtab { */ typedef struct completion_cursor completion_cursor; struct completion_cursor { - sqlite3_vtab_cursor base; /* Base class - must be first */ - sqlite3 *db; /* Database connection for this cursor */ - int nPrefix, nLine; /* Number of bytes in zPrefix and zLine */ - char *zPrefix; /* The prefix for the word we want to complete */ - char *zLine; /* The whole that we want to complete */ - const char *zCurrentRow; /* Current output row */ - int szRow; /* Length of the zCurrentRow string */ - sqlite3_stmt *pStmt; /* Current statement */ - sqlite3_int64 iRowid; /* The rowid */ - int ePhase; /* Current phase */ - int j; /* inter-phase counter */ + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3 *db; /* Database connection for this cursor */ + int nPrefix, nLine; /* Number of bytes in zPrefix and zLine */ + char *zPrefix; /* The prefix for the word we want to complete */ + char *zLine; /* The whole that we want to complete */ + const char *zCurrentRow; /* Current output row */ + int szRow; /* Length of the zCurrentRow string */ + sqlite3_stmt *pStmt; /* Current statement */ + sqlite3_int64 iRowid; /* The rowid */ + int ePhase; /* Current phase */ + int j; /* inter-phase counter */ }; /* Values for ePhase: @@ -3281,19 +3281,19 @@ struct completion_cursor { ** result set of queries against completion will look like. */ static int completionConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr ){ - completion_vtab *pNew; - int rc; + completion_vtab *pNew; + int rc; - (void)(pAux); /* Unused parameter */ - (void)(argc); /* Unused parameter */ - (void)(argv); /* Unused parameter */ - (void)(pzErr); /* Unused parameter */ + (void)(pAux); /* Unused parameter */ + (void)(argc); /* Unused parameter */ + (void)(argv); /* Unused parameter */ + (void)(pzErr); /* Unused parameter */ /* Column numbers */ #define COMPLETION_COLUMN_CANDIDATE 0 /* Suggested completion of the input */ @@ -3301,62 +3301,62 @@ static int completionConnect( #define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */ #define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */ - sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); - rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(" - " candidate TEXT," - " prefix TEXT HIDDEN," - " wholeline TEXT HIDDEN," - " phase INT HIDDEN" /* Used for debugging only */ - ")"); - if( rc==SQLITE_OK ){ - pNew = sqlite3_malloc( sizeof(*pNew) ); - *ppVtab = (sqlite3_vtab*)pNew; - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, sizeof(*pNew)); - pNew->db = db; - } - return rc; + sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(" + " candidate TEXT," + " prefix TEXT HIDDEN," + " wholeline TEXT HIDDEN," + " phase INT HIDDEN" /* Used for debugging only */ + ")"); + if( rc==SQLITE_OK ){ + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + pNew->db = db; + } + return rc; } /* ** This method is the destructor for completion_cursor objects. */ static int completionDisconnect(sqlite3_vtab *pVtab){ - sqlite3_free(pVtab); - return SQLITE_OK; + sqlite3_free(pVtab); + return SQLITE_OK; } /* ** Constructor for a new completion_cursor object. */ static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ - completion_cursor *pCur; - pCur = sqlite3_malloc( sizeof(*pCur) ); - if( pCur==0 ) return SQLITE_NOMEM; - memset(pCur, 0, sizeof(*pCur)); - pCur->db = ((completion_vtab*)p)->db; - *ppCursor = &pCur->base; - return SQLITE_OK; + completion_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + pCur->db = ((completion_vtab*)p)->db; + *ppCursor = &pCur->base; + return SQLITE_OK; } /* ** Reset the completion_cursor. */ static void completionCursorReset(completion_cursor *pCur){ - sqlite3_free(pCur->zPrefix); pCur->zPrefix = 0; pCur->nPrefix = 0; - sqlite3_free(pCur->zLine); pCur->zLine = 0; pCur->nLine = 0; - sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0; - pCur->j = 0; + sqlite3_free(pCur->zPrefix); pCur->zPrefix = 0; pCur->nPrefix = 0; + sqlite3_free(pCur->zLine); pCur->zLine = 0; pCur->nLine = 0; + sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0; + pCur->j = 0; } /* ** Destructor for a completion_cursor. */ static int completionClose(sqlite3_vtab_cursor *cur){ - completionCursorReset((completion_cursor*)cur); - sqlite3_free(cur); - return SQLITE_OK; + completionCursorReset((completion_cursor*)cur); + sqlite3_free(cur); + return SQLITE_OK; } /* @@ -3374,107 +3374,107 @@ static int completionClose(sqlite3_vtab_cursor *cur){ ** keywords based on what would be legal at the current point of input. */ static int completionNext(sqlite3_vtab_cursor *cur){ - completion_cursor *pCur = (completion_cursor*)cur; - int eNextPhase = 0; /* Next phase to try if current phase reaches end */ - int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */ - pCur->iRowid++; - while( pCur->ePhase!=COMPLETION_EOF ){ - switch( pCur->ePhase ){ - case COMPLETION_KEYWORDS: { - if( pCur->j >= sqlite3_keyword_count() ){ - pCur->zCurrentRow = 0; - pCur->ePhase = COMPLETION_DATABASES; - }else{ - sqlite3_keyword_name(pCur->j++, &pCur->zCurrentRow, &pCur->szRow); - } - iCol = -1; - break; - } - case COMPLETION_DATABASES: { - if( pCur->pStmt==0 ){ - sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, - &pCur->pStmt, 0); - } - iCol = 1; - eNextPhase = COMPLETION_TABLES; - break; - } - case COMPLETION_TABLES: { - if( pCur->pStmt==0 ){ - sqlite3_stmt *pS2; - char *zSql = 0; - const char *zSep = ""; - sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); - while( sqlite3_step(pS2)==SQLITE_ROW ){ - const char *zDb = (const char*)sqlite3_column_text(pS2, 1); - zSql = sqlite3_mprintf( - "%z%s" - "SELECT name FROM \"%w\".sqlite_schema", - zSql, zSep, zDb - ); - if( zSql==0 ) return SQLITE_NOMEM; - zSep = " UNION "; - } - sqlite3_finalize(pS2); - sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); - sqlite3_free(zSql); - } - iCol = 0; - eNextPhase = COMPLETION_COLUMNS; - break; - } - case COMPLETION_COLUMNS: { - if( pCur->pStmt==0 ){ - sqlite3_stmt *pS2; - char *zSql = 0; - const char *zSep = ""; - sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); - while( sqlite3_step(pS2)==SQLITE_ROW ){ - const char *zDb = (const char*)sqlite3_column_text(pS2, 1); - zSql = sqlite3_mprintf( - "%z%s" - "SELECT pti.name FROM \"%w\".sqlite_schema AS sm" - " JOIN pragma_table_info(sm.name,%Q) AS pti" - " WHERE sm.type='table'", - zSql, zSep, zDb, zDb - ); - if( zSql==0 ) return SQLITE_NOMEM; - zSep = " UNION "; - } - sqlite3_finalize(pS2); - sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); - sqlite3_free(zSql); - } - iCol = 0; - eNextPhase = COMPLETION_EOF; - break; - } - } - if( iCol<0 ){ - /* This case is when the phase presets zCurrentRow */ - if( pCur->zCurrentRow==0 ) continue; + completion_cursor *pCur = (completion_cursor*)cur; + int eNextPhase = 0; /* Next phase to try if current phase reaches end */ + int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */ + pCur->iRowid++; + while( pCur->ePhase!=COMPLETION_EOF ){ + switch( pCur->ePhase ){ + case COMPLETION_KEYWORDS: { + if( pCur->j >= sqlite3_keyword_count() ){ + pCur->zCurrentRow = 0; + pCur->ePhase = COMPLETION_DATABASES; }else{ - if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){ - /* Extract the next row of content */ - pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol); - pCur->szRow = sqlite3_column_bytes(pCur->pStmt, iCol); - }else{ - /* When all rows are finished, advance to the next phase */ - sqlite3_finalize(pCur->pStmt); - pCur->pStmt = 0; - pCur->ePhase = eNextPhase; - continue; - } - } - if( pCur->nPrefix==0 ) break; - if( pCur->nPrefix<=pCur->szRow - && sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0 - ){ - break; - } + sqlite3_keyword_name(pCur->j++, &pCur->zCurrentRow, &pCur->szRow); + } + iCol = -1; + break; + } + case COMPLETION_DATABASES: { + if( pCur->pStmt==0 ){ + sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, + &pCur->pStmt, 0); + } + iCol = 1; + eNextPhase = COMPLETION_TABLES; + break; + } + case COMPLETION_TABLES: { + if( pCur->pStmt==0 ){ + sqlite3_stmt *pS2; + char *zSql = 0; + const char *zSep = ""; + sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); + while( sqlite3_step(pS2)==SQLITE_ROW ){ + const char *zDb = (const char*)sqlite3_column_text(pS2, 1); + zSql = sqlite3_mprintf( + "%z%s" + "SELECT name FROM \"%w\".sqlite_schema", + zSql, zSep, zDb + ); + if( zSql==0 ) return SQLITE_NOMEM; + zSep = " UNION "; + } + sqlite3_finalize(pS2); + sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); + sqlite3_free(zSql); + } + iCol = 0; + eNextPhase = COMPLETION_COLUMNS; + break; + } + case COMPLETION_COLUMNS: { + if( pCur->pStmt==0 ){ + sqlite3_stmt *pS2; + char *zSql = 0; + const char *zSep = ""; + sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); + while( sqlite3_step(pS2)==SQLITE_ROW ){ + const char *zDb = (const char*)sqlite3_column_text(pS2, 1); + zSql = sqlite3_mprintf( + "%z%s" + "SELECT pti.name FROM \"%w\".sqlite_schema AS sm" + " JOIN pragma_table_info(sm.name,%Q) AS pti" + " WHERE sm.type='table'", + zSql, zSep, zDb, zDb + ); + if( zSql==0 ) return SQLITE_NOMEM; + zSep = " UNION "; + } + sqlite3_finalize(pS2); + sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); + sqlite3_free(zSql); + } + iCol = 0; + eNextPhase = COMPLETION_EOF; + break; + } + } + if( iCol<0 ){ + /* This case is when the phase presets zCurrentRow */ + if( pCur->zCurrentRow==0 ) continue; + }else{ + if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){ + /* Extract the next row of content */ + pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol); + pCur->szRow = sqlite3_column_bytes(pCur->pStmt, iCol); + }else{ + /* When all rows are finished, advance to the next phase */ + sqlite3_finalize(pCur->pStmt); + pCur->pStmt = 0; + pCur->ePhase = eNextPhase; + continue; + } + } + if( pCur->nPrefix==0 ) break; + if( pCur->nPrefix<=pCur->szRow + && sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0 + ){ + break; } + } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -3482,30 +3482,30 @@ static int completionNext(sqlite3_vtab_cursor *cur){ ** is currently pointing. */ static int completionColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ ){ - completion_cursor *pCur = (completion_cursor*)cur; - switch( i ){ - case COMPLETION_COLUMN_CANDIDATE: { - sqlite3_result_text(ctx, pCur->zCurrentRow, pCur->szRow,SQLITE_TRANSIENT); - break; - } - case COMPLETION_COLUMN_PREFIX: { - sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT); - break; - } - case COMPLETION_COLUMN_WHOLELINE: { - sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT); - break; - } - case COMPLETION_COLUMN_PHASE: { - sqlite3_result_int(ctx, pCur->ePhase); - break; - } + completion_cursor *pCur = (completion_cursor*)cur; + switch( i ){ + case COMPLETION_COLUMN_CANDIDATE: { + sqlite3_result_text(ctx, pCur->zCurrentRow, pCur->szRow,SQLITE_TRANSIENT); + break; } - return SQLITE_OK; + case COMPLETION_COLUMN_PREFIX: { + sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT); + break; + } + case COMPLETION_COLUMN_WHOLELINE: { + sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT); + break; + } + case COMPLETION_COLUMN_PHASE: { + sqlite3_result_int(ctx, pCur->ePhase); + break; + } + } + return SQLITE_OK; } /* @@ -3513,9 +3513,9 @@ static int completionColumn( ** rowid is the same as the output value. */ static int completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - completion_cursor *pCur = (completion_cursor*)cur; - *pRowid = pCur->iRowid; - return SQLITE_OK; + completion_cursor *pCur = (completion_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; } /* @@ -3523,55 +3523,55 @@ static int completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ** row of output. */ static int completionEof(sqlite3_vtab_cursor *cur){ - completion_cursor *pCur = (completion_cursor*)cur; - return pCur->ePhase >= COMPLETION_EOF; + completion_cursor *pCur = (completion_cursor*)cur; + return pCur->ePhase >= COMPLETION_EOF; } /* ** This method is called to "rewind" the completion_cursor object back ** to the first row of output. This method is always called at least -** once prior to any call to completionColumn() or completionRowid() or +** once prior to any call to completionColumn() or completionRowid() or ** completionEof(). */ static int completionFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv ){ - completion_cursor *pCur = (completion_cursor *)pVtabCursor; - int iArg = 0; - (void)(idxStr); /* Unused parameter */ - (void)(argc); /* Unused parameter */ - completionCursorReset(pCur); - if( idxNum & 1 ){ - pCur->nPrefix = sqlite3_value_bytes(argv[iArg]); - if( pCur->nPrefix>0 ){ - pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); - if( pCur->zPrefix==0 ) return SQLITE_NOMEM; - } - iArg = 1; - } - if( idxNum & 2 ){ - pCur->nLine = sqlite3_value_bytes(argv[iArg]); - if( pCur->nLine>0 ){ - pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); - if( pCur->zLine==0 ) return SQLITE_NOMEM; - } - } - if( pCur->zLine!=0 && pCur->zPrefix==0 ){ - int i = pCur->nLine; - while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){ - i--; - } - pCur->nPrefix = pCur->nLine - i; - if( pCur->nPrefix>0 ){ - pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i); - if( pCur->zPrefix==0 ) return SQLITE_NOMEM; - } - } - pCur->iRowid = 0; - pCur->ePhase = COMPLETION_FIRST_PHASE; - return completionNext(pVtabCursor); + completion_cursor *pCur = (completion_cursor *)pVtabCursor; + int iArg = 0; + (void)(idxStr); /* Unused parameter */ + (void)(argc); /* Unused parameter */ + completionCursorReset(pCur); + if( idxNum & 1 ){ + pCur->nPrefix = sqlite3_value_bytes(argv[iArg]); + if( pCur->nPrefix>0 ){ + pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); + if( pCur->zPrefix==0 ) return SQLITE_NOMEM; + } + iArg = 1; + } + if( idxNum & 2 ){ + pCur->nLine = sqlite3_value_bytes(argv[iArg]); + if( pCur->nLine>0 ){ + pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); + if( pCur->zLine==0 ) return SQLITE_NOMEM; + } + } + if( pCur->zLine!=0 && pCur->zPrefix==0 ){ + int i = pCur->nLine; + while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){ + i--; + } + pCur->nPrefix = pCur->nLine - i; + if( pCur->nPrefix>0 ){ + pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i); + if( pCur->zPrefix==0 ) return SQLITE_NOMEM; + } + } + pCur->iRowid = 0; + pCur->ePhase = COMPLETION_FIRST_PHASE; + return completionNext(pVtabCursor); } /* @@ -3585,102 +3585,102 @@ static int completionFilter( ** is available and bit 1 is set if "wholeline" is available. */ static int completionBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo ){ - int i; /* Loop over constraints */ - int idxNum = 0; /* The query plan bitmask */ - int prefixIdx = -1; /* Index of the start= constraint, or -1 if none */ - int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */ - int nArg = 0; /* Number of arguments that completeFilter() expects */ - const struct sqlite3_index_constraint *pConstraint; - - (void)(tab); /* Unused parameter */ - pConstraint = pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pConstraint++){ - if( pConstraint->usable==0 ) continue; - if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; - switch( pConstraint->iColumn ){ - case COMPLETION_COLUMN_PREFIX: - prefixIdx = i; - idxNum |= 1; - break; - case COMPLETION_COLUMN_WHOLELINE: - wholelineIdx = i; - idxNum |= 2; - break; - } - } - if( prefixIdx>=0 ){ - pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[prefixIdx].omit = 1; - } - if( wholelineIdx>=0 ){ - pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1; - } - pIdxInfo->idxNum = idxNum; - pIdxInfo->estimatedCost = (double)5000 - 1000*nArg; - pIdxInfo->estimatedRows = 500 - 100*nArg; - return SQLITE_OK; -} - -/* -** This following structure defines all the methods for the + int i; /* Loop over constraints */ + int idxNum = 0; /* The query plan bitmask */ + int prefixIdx = -1; /* Index of the start= constraint, or -1 if none */ + int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */ + int nArg = 0; /* Number of arguments that completeFilter() expects */ + const struct sqlite3_index_constraint *pConstraint; + + (void)(tab); /* Unused parameter */ + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + if( pConstraint->usable==0 ) continue; + if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; + switch( pConstraint->iColumn ){ + case COMPLETION_COLUMN_PREFIX: + prefixIdx = i; + idxNum |= 1; + break; + case COMPLETION_COLUMN_WHOLELINE: + wholelineIdx = i; + idxNum |= 2; + break; + } + } + if( prefixIdx>=0 ){ + pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg; + pIdxInfo->aConstraintUsage[prefixIdx].omit = 1; + } + if( wholelineIdx>=0 ){ + pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg; + pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1; + } + pIdxInfo->idxNum = idxNum; + pIdxInfo->estimatedCost = (double)5000 - 1000*nArg; + pIdxInfo->estimatedRows = 500 - 100*nArg; + return SQLITE_OK; +} + +/* +** This following structure defines all the methods for the ** completion virtual table. */ static sqlite3_module completionModule = { - 0, /* iVersion */ - 0, /* xCreate */ - completionConnect, /* xConnect */ - completionBestIndex, /* xBestIndex */ - completionDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - completionOpen, /* xOpen - open a cursor */ - completionClose, /* xClose - close a cursor */ - completionFilter, /* xFilter - configure scan constraints */ - completionNext, /* xNext - advance a cursor */ - completionEof, /* xEof - check for end of scan */ - completionColumn, /* xColumn - read data */ - completionRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* iVersion */ + 0, /* xCreate */ + completionConnect, /* xConnect */ + completionBestIndex, /* xBestIndex */ + completionDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + completionOpen, /* xOpen - open a cursor */ + completionClose, /* xClose - close a cursor */ + completionFilter, /* xFilter - configure scan constraints */ + completionNext, /* xNext - advance a cursor */ + completionEof, /* xEof - check for end of scan */ + completionColumn, /* xColumn - read data */ + completionRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ int sqlite3CompletionVtabInit(sqlite3 *db){ - int rc = SQLITE_OK; + int rc = SQLITE_OK; #ifndef SQLITE_OMIT_VIRTUALTABLE - rc = sqlite3_create_module(db, "completion", &completionModule, 0); + rc = sqlite3_create_module(db, "completion", &completionModule, 0); #endif - return rc; + return rc; } #ifdef _WIN32 #endif int sqlite3_completion_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)(pzErrMsg); /* Unused parameter */ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)(pzErrMsg); /* Unused parameter */ #ifndef SQLITE_OMIT_VIRTUALTABLE - rc = sqlite3CompletionVtabInit(db); + rc = sqlite3CompletionVtabInit(db); #endif - return rc; + return rc; } /************************* End ../ext/misc/completion.c ********************/ @@ -3813,10 +3813,10 @@ typedef struct ApndFile ApndFile; ** Or, iMark is -1 to indicate that it has not yet been written. */ struct ApndFile { - sqlite3_file base; /* Subclass. MUST BE FIRST! */ - sqlite3_int64 iPgOne; /* Offset to the start of the database */ - sqlite3_int64 iMark; /* Offset of the append mark. -1 if unwritten */ - /* Always followed by another sqlite3_file that describes the whole file */ + sqlite3_file base; /* Subclass. MUST BE FIRST! */ + sqlite3_int64 iPgOne; /* Offset to the start of the database */ + sqlite3_int64 iMark; /* Offset of the append mark. -1 if unwritten */ + /* Always followed by another sqlite3_file that describes the whole file */ }; /* @@ -3862,72 +3862,72 @@ static sqlite3_syscall_ptr apndGetSystemCall(sqlite3_vfs*, const char *z); static const char *apndNextSystemCall(sqlite3_vfs*, const char *zName); static sqlite3_vfs apnd_vfs = { - 3, /* iVersion (set when registered) */ - 0, /* szOsFile (set when registered) */ - 1024, /* mxPathname */ - 0, /* pNext */ - "apndvfs", /* zName */ - 0, /* pAppData (set when registered) */ - apndOpen, /* xOpen */ - apndDelete, /* xDelete */ - apndAccess, /* xAccess */ - apndFullPathname, /* xFullPathname */ - apndDlOpen, /* xDlOpen */ - apndDlError, /* xDlError */ - apndDlSym, /* xDlSym */ - apndDlClose, /* xDlClose */ - apndRandomness, /* xRandomness */ - apndSleep, /* xSleep */ - apndCurrentTime, /* xCurrentTime */ - apndGetLastError, /* xGetLastError */ - apndCurrentTimeInt64, /* xCurrentTimeInt64 */ - apndSetSystemCall, /* xSetSystemCall */ - apndGetSystemCall, /* xGetSystemCall */ - apndNextSystemCall /* xNextSystemCall */ + 3, /* iVersion (set when registered) */ + 0, /* szOsFile (set when registered) */ + 1024, /* mxPathname */ + 0, /* pNext */ + "apndvfs", /* zName */ + 0, /* pAppData (set when registered) */ + apndOpen, /* xOpen */ + apndDelete, /* xDelete */ + apndAccess, /* xAccess */ + apndFullPathname, /* xFullPathname */ + apndDlOpen, /* xDlOpen */ + apndDlError, /* xDlError */ + apndDlSym, /* xDlSym */ + apndDlClose, /* xDlClose */ + apndRandomness, /* xRandomness */ + apndSleep, /* xSleep */ + apndCurrentTime, /* xCurrentTime */ + apndGetLastError, /* xGetLastError */ + apndCurrentTimeInt64, /* xCurrentTimeInt64 */ + apndSetSystemCall, /* xSetSystemCall */ + apndGetSystemCall, /* xGetSystemCall */ + apndNextSystemCall /* xNextSystemCall */ }; static const sqlite3_io_methods apnd_io_methods = { - 3, /* iVersion */ - apndClose, /* xClose */ - apndRead, /* xRead */ - apndWrite, /* xWrite */ - apndTruncate, /* xTruncate */ - apndSync, /* xSync */ - apndFileSize, /* xFileSize */ - apndLock, /* xLock */ - apndUnlock, /* xUnlock */ - apndCheckReservedLock, /* xCheckReservedLock */ - apndFileControl, /* xFileControl */ - apndSectorSize, /* xSectorSize */ - apndDeviceCharacteristics, /* xDeviceCharacteristics */ - apndShmMap, /* xShmMap */ - apndShmLock, /* xShmLock */ - apndShmBarrier, /* xShmBarrier */ - apndShmUnmap, /* xShmUnmap */ - apndFetch, /* xFetch */ - apndUnfetch /* xUnfetch */ + 3, /* iVersion */ + apndClose, /* xClose */ + apndRead, /* xRead */ + apndWrite, /* xWrite */ + apndTruncate, /* xTruncate */ + apndSync, /* xSync */ + apndFileSize, /* xFileSize */ + apndLock, /* xLock */ + apndUnlock, /* xUnlock */ + apndCheckReservedLock, /* xCheckReservedLock */ + apndFileControl, /* xFileControl */ + apndSectorSize, /* xSectorSize */ + apndDeviceCharacteristics, /* xDeviceCharacteristics */ + apndShmMap, /* xShmMap */ + apndShmLock, /* xShmLock */ + apndShmBarrier, /* xShmBarrier */ + apndShmUnmap, /* xShmUnmap */ + apndFetch, /* xFetch */ + apndUnfetch /* xUnfetch */ }; /* ** Close an apnd-file. */ static int apndClose(sqlite3_file *pFile){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xClose(pFile); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xClose(pFile); } /* ** Read data from an apnd-file. */ static int apndRead( - sqlite3_file *pFile, - void *zBuf, - int iAmt, - sqlite_int64 iOfst + sqlite3_file *pFile, + void *zBuf, + int iAmt, + sqlite_int64 iOfst ){ - ApndFile *paf = (ApndFile *)pFile; - pFile = ORIGFILE(pFile); - return pFile->pMethods->xRead(pFile, zBuf, iAmt, paf->iPgOne+iOfst); + ApndFile *paf = (ApndFile *)pFile; + pFile = ORIGFILE(pFile); + return pFile->pMethods->xRead(pFile, zBuf, iAmt, paf->iPgOne+iOfst); } /* @@ -3936,67 +3936,67 @@ static int apndRead( * Parameter iWriteEnd is the appendvfs-relative offset of the new mark. */ static int apndWriteMark( - ApndFile *paf, - sqlite3_file *pFile, - sqlite_int64 iWriteEnd + ApndFile *paf, + sqlite3_file *pFile, + sqlite_int64 iWriteEnd ){ - sqlite_int64 iPgOne = paf->iPgOne; - unsigned char a[APND_MARK_SIZE]; - int i = APND_MARK_FOS_SZ; - int rc; - assert(pFile == ORIGFILE(paf)); - memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ); - while( --i >= 0 ){ - a[APND_MARK_PREFIX_SZ+i] = (unsigned char)(iPgOne & 0xff); - iPgOne >>= 8; - } - iWriteEnd += paf->iPgOne; - if( SQLITE_OK==(rc = pFile->pMethods->xWrite - (pFile, a, APND_MARK_SIZE, iWriteEnd)) ){ - paf->iMark = iWriteEnd; - } - return rc; + sqlite_int64 iPgOne = paf->iPgOne; + unsigned char a[APND_MARK_SIZE]; + int i = APND_MARK_FOS_SZ; + int rc; + assert(pFile == ORIGFILE(paf)); + memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ); + while( --i >= 0 ){ + a[APND_MARK_PREFIX_SZ+i] = (unsigned char)(iPgOne & 0xff); + iPgOne >>= 8; + } + iWriteEnd += paf->iPgOne; + if( SQLITE_OK==(rc = pFile->pMethods->xWrite + (pFile, a, APND_MARK_SIZE, iWriteEnd)) ){ + paf->iMark = iWriteEnd; + } + return rc; } /* ** Write data to an apnd-file. */ static int apndWrite( - sqlite3_file *pFile, - const void *zBuf, - int iAmt, - sqlite_int64 iOfst + sqlite3_file *pFile, + const void *zBuf, + int iAmt, + sqlite_int64 iOfst ){ - ApndFile *paf = (ApndFile *)pFile; - sqlite_int64 iWriteEnd = iOfst + iAmt; - if( iWriteEnd>=APND_MAX_SIZE ) return SQLITE_FULL; - pFile = ORIGFILE(pFile); - /* If append-mark is absent or will be overwritten, write it. */ - if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){ - int rc = apndWriteMark(paf, pFile, iWriteEnd); - if( SQLITE_OK!=rc ) return rc; - } - return pFile->pMethods->xWrite(pFile, zBuf, iAmt, paf->iPgOne+iOfst); + ApndFile *paf = (ApndFile *)pFile; + sqlite_int64 iWriteEnd = iOfst + iAmt; + if( iWriteEnd>=APND_MAX_SIZE ) return SQLITE_FULL; + pFile = ORIGFILE(pFile); + /* If append-mark is absent or will be overwritten, write it. */ + if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){ + int rc = apndWriteMark(paf, pFile, iWriteEnd); + if( SQLITE_OK!=rc ) return rc; + } + return pFile->pMethods->xWrite(pFile, zBuf, iAmt, paf->iPgOne+iOfst); } /* ** Truncate an apnd-file. */ static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){ - ApndFile *paf = (ApndFile *)pFile; - pFile = ORIGFILE(pFile); - /* The append mark goes out first so truncate failure does not lose it. */ - if( SQLITE_OK!=apndWriteMark(paf, pFile, size) ) return SQLITE_IOERR; - /* Truncate underlying file just past append mark */ - return pFile->pMethods->xTruncate(pFile, paf->iMark+APND_MARK_SIZE); + ApndFile *paf = (ApndFile *)pFile; + pFile = ORIGFILE(pFile); + /* The append mark goes out first so truncate failure does not lose it. */ + if( SQLITE_OK!=apndWriteMark(paf, pFile, size) ) return SQLITE_IOERR; + /* Truncate underlying file just past append mark */ + return pFile->pMethods->xTruncate(pFile, paf->iMark+APND_MARK_SIZE); } /* ** Sync an apnd-file. */ static int apndSync(sqlite3_file *pFile, int flags){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xSync(pFile, flags); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xSync(pFile, flags); } /* @@ -4004,116 +4004,116 @@ static int apndSync(sqlite3_file *pFile, int flags){ ** If the append mark is not yet there, the file-size is 0. */ static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ - ApndFile *paf = (ApndFile *)pFile; - *pSize = ( paf->iMark >= 0 )? (paf->iMark - paf->iPgOne) : 0; - return SQLITE_OK; + ApndFile *paf = (ApndFile *)pFile; + *pSize = ( paf->iMark >= 0 )? (paf->iMark - paf->iPgOne) : 0; + return SQLITE_OK; } /* ** Lock an apnd-file. */ static int apndLock(sqlite3_file *pFile, int eLock){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xLock(pFile, eLock); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xLock(pFile, eLock); } /* ** Unlock an apnd-file. */ static int apndUnlock(sqlite3_file *pFile, int eLock){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xUnlock(pFile, eLock); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xUnlock(pFile, eLock); } /* ** Check if another file-handle holds a RESERVED lock on an apnd-file. */ static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xCheckReservedLock(pFile, pResOut); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xCheckReservedLock(pFile, pResOut); } /* ** File control method. For custom operations on an apnd-file. */ static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){ - ApndFile *paf = (ApndFile *)pFile; - int rc; - pFile = ORIGFILE(pFile); - if( op==SQLITE_FCNTL_SIZE_HINT ) *(sqlite3_int64*)pArg += paf->iPgOne; - rc = pFile->pMethods->xFileControl(pFile, op, pArg); - if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ - *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", paf->iPgOne,*(char**)pArg); - } - return rc; + ApndFile *paf = (ApndFile *)pFile; + int rc; + pFile = ORIGFILE(pFile); + if( op==SQLITE_FCNTL_SIZE_HINT ) *(sqlite3_int64*)pArg += paf->iPgOne; + rc = pFile->pMethods->xFileControl(pFile, op, pArg); + if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ + *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", paf->iPgOne,*(char**)pArg); + } + return rc; } /* ** Return the sector-size in bytes for an apnd-file. */ static int apndSectorSize(sqlite3_file *pFile){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xSectorSize(pFile); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xSectorSize(pFile); } /* ** Return the device characteristic flags supported by an apnd-file. */ static int apndDeviceCharacteristics(sqlite3_file *pFile){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xDeviceCharacteristics(pFile); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xDeviceCharacteristics(pFile); } /* Create a shared memory file mapping */ static int apndShmMap( - sqlite3_file *pFile, - int iPg, - int pgsz, - int bExtend, - void volatile **pp + sqlite3_file *pFile, + int iPg, + int pgsz, + int bExtend, + void volatile **pp ){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); } /* Perform locking on a shared-memory segment */ static int apndShmLock(sqlite3_file *pFile, int offset, int n, int flags){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xShmLock(pFile,offset,n,flags); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmLock(pFile,offset,n,flags); } /* Memory barrier operation on shared memory */ static void apndShmBarrier(sqlite3_file *pFile){ - pFile = ORIGFILE(pFile); - pFile->pMethods->xShmBarrier(pFile); + pFile = ORIGFILE(pFile); + pFile->pMethods->xShmBarrier(pFile); } /* Unmap a shared memory segment */ static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){ - pFile = ORIGFILE(pFile); - return pFile->pMethods->xShmUnmap(pFile,deleteFlag); + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmUnmap(pFile,deleteFlag); } /* Fetch a page of a memory-mapped file */ static int apndFetch( - sqlite3_file *pFile, - sqlite3_int64 iOfst, - int iAmt, - void **pp + sqlite3_file *pFile, + sqlite3_int64 iOfst, + int iAmt, + void **pp ){ - ApndFile *p = (ApndFile *)pFile; - if( p->iMark < 0 || iOfst+iAmt > p->iMark ){ - return SQLITE_IOERR; /* Cannot read what is not yet there. */ - } - pFile = ORIGFILE(pFile); - return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp); + ApndFile *p = (ApndFile *)pFile; + if( p->iMark < 0 || iOfst+iAmt > p->iMark ){ + return SQLITE_IOERR; /* Cannot read what is not yet there. */ + } + pFile = ORIGFILE(pFile); + return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp); } /* Release a memory-mapped page */ static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ - ApndFile *p = (ApndFile *)pFile; - pFile = ORIGFILE(pFile); - return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage); + ApndFile *p = (ApndFile *)pFile; + pFile = ORIGFILE(pFile); + return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage); } /* @@ -4126,23 +4126,23 @@ static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ ** start-of-database value must be a multiple of 512. */ static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){ - int rc, i; - sqlite3_int64 iMark; - int msbs = 8 * (APND_MARK_FOS_SZ-1); - unsigned char a[APND_MARK_SIZE]; - - if( APND_MARK_SIZE!=(sz & 0x1ff) ) return -1; - rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE); - if( rc ) return -1; - if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1; - iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ] & 0x7f)) << msbs; - for(i=1; i<8; i++){ - msbs -= 8; - iMark |= (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]< (sz - APND_MARK_SIZE - 512) ) return -1; - if( iMark & 0x1ff ) return -1; - return iMark; + int rc, i; + sqlite3_int64 iMark; + int msbs = 8 * (APND_MARK_FOS_SZ-1); + unsigned char a[APND_MARK_SIZE]; + + if( APND_MARK_SIZE!=(sz & 0x1ff) ) return -1; + rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE); + if( rc ) return -1; + if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1; + iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ] & 0x7f)) << msbs; + for(i=1; i<8; i++){ + msbs -= 8; + iMark |= (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]< (sz - APND_MARK_SIZE - 512) ) return -1; + if( iMark & 0x1ff ) return -1; + return iMark; } static const char apvfsSqliteHdr[] = "SQLite format 3"; @@ -4151,24 +4151,24 @@ static const char apvfsSqliteHdr[] = "SQLite format 3"; ** Return true iff it is such. Parameter sz is the file's size. */ static int apndIsAppendvfsDatabase(sqlite3_int64 sz, sqlite3_file *pFile){ - int rc; - char zHdr[16]; - sqlite3_int64 iMark = apndReadMark(sz, pFile); - if( iMark>=0 ){ - /* If file has the correct end-marker, the expected odd size, and the + int rc; + char zHdr[16]; + sqlite3_int64 iMark = apndReadMark(sz, pFile); + if( iMark>=0 ){ + /* If file has the correct end-marker, the expected odd size, and the ** SQLite DB type marker where the end-marker puts it, then it ** is an appendvfs database. */ - rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), iMark); - if( SQLITE_OK==rc - && memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))==0 - && (sz & 0x1ff) == APND_MARK_SIZE - && sz>=512+APND_MARK_SIZE - ){ - return 1; /* It's an appendvfs database */ - } + rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), iMark); + if( SQLITE_OK==rc + && memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))==0 + && (sz & 0x1ff) == APND_MARK_SIZE + && sz>=512+APND_MARK_SIZE + ){ + return 1; /* It's an appendvfs database */ } - return 0; + } + return 0; } /* @@ -4176,80 +4176,80 @@ static int apndIsAppendvfsDatabase(sqlite3_int64 sz, sqlite3_file *pFile){ ** Return true iff so. Parameter sz is the file's size. */ static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){ - char zHdr[16]; - if( apndIsAppendvfsDatabase(sz, pFile) /* rule 2 */ - || (sz & 0x1ff) != 0 - || SQLITE_OK!=pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0) - || memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))!=0 - ){ - return 0; - }else{ - return 1; - } + char zHdr[16]; + if( apndIsAppendvfsDatabase(sz, pFile) /* rule 2 */ + || (sz & 0x1ff) != 0 + || SQLITE_OK!=pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0) + || memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))!=0 + ){ + return 0; + }else{ + return 1; + } } /* ** Open an apnd file handle. */ static int apndOpen( - sqlite3_vfs *pApndVfs, - const char *zName, - sqlite3_file *pFile, - int flags, - int *pOutFlags + sqlite3_vfs *pApndVfs, + const char *zName, + sqlite3_file *pFile, + int flags, + int *pOutFlags ){ - ApndFile *pApndFile = (ApndFile*)pFile; - sqlite3_file *pBaseFile = ORIGFILE(pFile); - sqlite3_vfs *pBaseVfs = ORIGVFS(pApndVfs); - int rc; - sqlite3_int64 sz = 0; - if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ - /* The appendvfs is not to be used for transient or temporary databases. + ApndFile *pApndFile = (ApndFile*)pFile; + sqlite3_file *pBaseFile = ORIGFILE(pFile); + sqlite3_vfs *pBaseVfs = ORIGVFS(pApndVfs); + int rc; + sqlite3_int64 sz = 0; + if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ + /* The appendvfs is not to be used for transient or temporary databases. ** Just use the base VFS open to initialize the given file object and ** open the underlying file. (Appendvfs is then unused for this file.) */ - return pBaseVfs->xOpen(pBaseVfs, zName, pFile, flags, pOutFlags); - } - memset(pApndFile, 0, sizeof(ApndFile)); - pFile->pMethods = &apnd_io_methods; - pApndFile->iMark = -1; /* Append mark not yet written */ - - rc = pBaseVfs->xOpen(pBaseVfs, zName, pBaseFile, flags, pOutFlags); - if( rc==SQLITE_OK ){ - rc = pBaseFile->pMethods->xFileSize(pBaseFile, &sz); - if( rc ){ - pBaseFile->pMethods->xClose(pBaseFile); - } - } + return pBaseVfs->xOpen(pBaseVfs, zName, pFile, flags, pOutFlags); + } + memset(pApndFile, 0, sizeof(ApndFile)); + pFile->pMethods = &apnd_io_methods; + pApndFile->iMark = -1; /* Append mark not yet written */ + + rc = pBaseVfs->xOpen(pBaseVfs, zName, pBaseFile, flags, pOutFlags); + if( rc==SQLITE_OK ){ + rc = pBaseFile->pMethods->xFileSize(pBaseFile, &sz); if( rc ){ - pFile->pMethods = 0; - return rc; + pBaseFile->pMethods->xClose(pBaseFile); } - if( apndIsOrdinaryDatabaseFile(sz, pBaseFile) ){ - /* The file being opened appears to be just an ordinary DB. Copy - ** the base dispatch-table so this instance mimics the base VFS. + } + if( rc ){ + pFile->pMethods = 0; + return rc; + } + if( apndIsOrdinaryDatabaseFile(sz, pBaseFile) ){ + /* The file being opened appears to be just an ordinary DB. Copy + ** the base dispatch-table so this instance mimics the base VFS. */ - memmove(pApndFile, pBaseFile, pBaseVfs->szOsFile); - return SQLITE_OK; - } - pApndFile->iPgOne = apndReadMark(sz, pFile); - if( pApndFile->iPgOne>=0 ){ - pApndFile->iMark = sz - APND_MARK_SIZE; /* Append mark found */ - return SQLITE_OK; - } - if( (flags & SQLITE_OPEN_CREATE)==0 ){ - pBaseFile->pMethods->xClose(pBaseFile); - rc = SQLITE_CANTOPEN; - pFile->pMethods = 0; - }else{ - /* Round newly added appendvfs location to #define'd page boundary. + memmove(pApndFile, pBaseFile, pBaseVfs->szOsFile); + return SQLITE_OK; + } + pApndFile->iPgOne = apndReadMark(sz, pFile); + if( pApndFile->iPgOne>=0 ){ + pApndFile->iMark = sz - APND_MARK_SIZE; /* Append mark found */ + return SQLITE_OK; + } + if( (flags & SQLITE_OPEN_CREATE)==0 ){ + pBaseFile->pMethods->xClose(pBaseFile); + rc = SQLITE_CANTOPEN; + pFile->pMethods = 0; + }else{ + /* Round newly added appendvfs location to #define'd page boundary. ** Note that nothing has yet been written to the underlying file. ** The append mark will be written along with first content write. ** Until then, paf->iMark value indicates it is not yet written. */ - pApndFile->iPgOne = APND_START_ROUNDUP(sz); - } - return rc; + pApndFile->iPgOne = APND_START_ROUNDUP(sz); + } + return rc; } /* @@ -4259,103 +4259,103 @@ static int apndOpen( ** For now, this code deletes the underlying file too. */ static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ - return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); + return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); } /* ** All other VFS methods are pass-thrus. */ static int apndAccess( - sqlite3_vfs *pVfs, - const char *zPath, - int flags, - int *pResOut + sqlite3_vfs *pVfs, + const char *zPath, + int flags, + int *pResOut ){ - return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); + return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); } static int apndFullPathname( - sqlite3_vfs *pVfs, - const char *zPath, - int nOut, - char *zOut + sqlite3_vfs *pVfs, + const char *zPath, + int nOut, + char *zOut ){ - return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); + return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); } static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){ - return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); + return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); } static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ - ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); + ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); } static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ - return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); + return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); } static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){ - ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); + ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); } static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ - return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); + return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); } static int apndSleep(sqlite3_vfs *pVfs, int nMicro){ - return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); + return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); } static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ - return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); + return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); } static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){ - return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); + return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); } static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ - return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p); + return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p); } static int apndSetSystemCall( - sqlite3_vfs *pVfs, - const char *zName, - sqlite3_syscall_ptr pCall + sqlite3_vfs *pVfs, + const char *zName, + sqlite3_syscall_ptr pCall ){ - return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); + return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); } static sqlite3_syscall_ptr apndGetSystemCall( - sqlite3_vfs *pVfs, - const char *zName + sqlite3_vfs *pVfs, + const char *zName ){ - return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); + return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); } static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ - return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); + return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); } - + #ifdef _WIN32 #endif -/* +/* ** This routine is called when the extension is loaded. ** Register the new VFS. */ int sqlite3_appendvfs_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - int rc = SQLITE_OK; - sqlite3_vfs *pOrig; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; - (void)db; - pOrig = sqlite3_vfs_find(0); - if( pOrig==0 ) return SQLITE_ERROR; - apnd_vfs.iVersion = pOrig->iVersion; - apnd_vfs.pAppData = pOrig; - apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile); - rc = sqlite3_vfs_register(&apnd_vfs, 0); + int rc = SQLITE_OK; + sqlite3_vfs *pOrig; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; + (void)db; + pOrig = sqlite3_vfs_find(0); + if( pOrig==0 ) return SQLITE_ERROR; + apnd_vfs.iVersion = pOrig->iVersion; + apnd_vfs.pAppData = pOrig; + apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile); + rc = sqlite3_vfs_register(&apnd_vfs, 0); #ifdef APPENDVFS_TEST - if( rc==SQLITE_OK ){ - rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister); - } + if( rc==SQLITE_OK ){ + rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister); + } #endif - if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; - return rc; + if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; + return rc; } /************************* End ../ext/misc/appendvfs.c ********************/ @@ -4393,80 +4393,80 @@ static FILE *memtraceOut; /* Methods that trace memory allocations */ static void *memtraceMalloc(int n){ - if( memtraceOut ){ - fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n", + if( memtraceOut ){ + fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n", memtraceBase.xRoundup(n)); - } - return memtraceBase.xMalloc(n); + } + return memtraceBase.xMalloc(n); } static void memtraceFree(void *p){ - if( p==0 ) return; - if( memtraceOut ){ - fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p)); - } - memtraceBase.xFree(p); + if( p==0 ) return; + if( memtraceOut ){ + fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p)); + } + memtraceBase.xFree(p); } static void *memtraceRealloc(void *p, int n){ - if( p==0 ) return memtraceMalloc(n); - if( n==0 ){ - memtraceFree(p); - return 0; - } - if( memtraceOut ){ - fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n", + if( p==0 ) return memtraceMalloc(n); + if( n==0 ){ + memtraceFree(p); + return 0; + } + if( memtraceOut ){ + fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n", memtraceBase.xSize(p), memtraceBase.xRoundup(n)); - } - return memtraceBase.xRealloc(p, n); + } + return memtraceBase.xRealloc(p, n); } static int memtraceSize(void *p){ - return memtraceBase.xSize(p); + return memtraceBase.xSize(p); } static int memtraceRoundup(int n){ - return memtraceBase.xRoundup(n); + return memtraceBase.xRoundup(n); } static int memtraceInit(void *p){ - return memtraceBase.xInit(p); + return memtraceBase.xInit(p); } static void memtraceShutdown(void *p){ - memtraceBase.xShutdown(p); + memtraceBase.xShutdown(p); } /* The substitute memory allocator */ static sqlite3_mem_methods ersaztMethods = { - memtraceMalloc, - memtraceFree, - memtraceRealloc, - memtraceSize, - memtraceRoundup, - memtraceInit, - memtraceShutdown, - 0 + memtraceMalloc, + memtraceFree, + memtraceRealloc, + memtraceSize, + memtraceRoundup, + memtraceInit, + memtraceShutdown, + 0 }; /* Begin tracing memory allocations to out. */ int sqlite3MemTraceActivate(FILE *out){ - int rc = SQLITE_OK; - if( memtraceBase.xMalloc==0 ){ - rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase); - if( rc==SQLITE_OK ){ - rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods); - } + int rc = SQLITE_OK; + if( memtraceBase.xMalloc==0 ){ + rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase); + if( rc==SQLITE_OK ){ + rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods); } - memtraceOut = out; - return rc; + } + memtraceOut = out; + return rc; } /* Deactivate memory tracing */ int sqlite3MemTraceDeactivate(void){ - int rc = SQLITE_OK; - if( memtraceBase.xMalloc!=0 ){ - rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase); - if( rc==SQLITE_OK ){ - memset(&memtraceBase, 0, sizeof(memtraceBase)); - } + int rc = SQLITE_OK; + if( memtraceBase.xMalloc!=0 ){ + rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase); + if( rc==SQLITE_OK ){ + memset(&memtraceBase, 0, sizeof(memtraceBase)); } - memtraceOut = 0; - return rc; + } + memtraceOut = 0; + return rc; } /************************* End ../ext/misc/memtrace.c ********************/ @@ -4511,57 +4511,57 @@ SQLITE_EXTENSION_INIT1 ** compare in numeric order. */ static int uintCollFunc( - void *notUsed, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 + void *notUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 ){ - const unsigned char *zA = (const unsigned char*)pKey1; - const unsigned char *zB = (const unsigned char*)pKey2; - int i=0, j=0, x; - (void)notUsed; - while( ia); + sqlite3_free(p->a); } /* ** Destroy a Decimal object */ static void decimal_free(Decimal *p){ - if( p ){ - decimal_clear(p); - sqlite3_free(p); - } + if( p ){ + decimal_clear(p); + sqlite3_free(p); + } } /* @@ -4630,172 +4630,172 @@ static void decimal_free(Decimal *p){ ** by the input string. */ static Decimal *decimal_new( - sqlite3_context *pCtx, - sqlite3_value *pIn, - int nAlt, - const unsigned char *zAlt + sqlite3_context *pCtx, + sqlite3_value *pIn, + int nAlt, + const unsigned char *zAlt ){ - Decimal *p; - int n, i; - const unsigned char *zIn; - int iExp = 0; - p = sqlite3_malloc( sizeof(*p) ); - if( p==0 ) goto new_no_mem; - p->sign = 0; - p->oom = 0; - p->isInit = 1; - p->isNull = 0; - p->nDigit = 0; - p->nFrac = 0; - if( zAlt ){ - n = nAlt, - zIn = zAlt; - }else{ - if( sqlite3_value_type(pIn)==SQLITE_NULL ){ - p->a = 0; - p->isNull = 1; - return p; - } - n = sqlite3_value_bytes(pIn); - zIn = sqlite3_value_text(pIn); - } - p->a = sqlite3_malloc64( n+1 ); - if( p->a==0 ) goto new_no_mem; - for(i=0; isspace(zIn[i]); i++){} - if( zIn[i]=='-' ){ - p->sign = 1; - i++; - }else if( zIn[i]=='+' ){ - i++; - } - while( i='0' && c<='9' ){ - p->a[p->nDigit++] = c - '0'; - }else if( c=='.' ){ - p->nFrac = p->nDigit + 1; - }else if( c=='e' || c=='E' ){ - int j = i+1; - int neg = 0; - if( j>=n ) break; - if( zIn[j]=='-' ){ - neg = 1; - j++; - }else if( zIn[j]=='+' ){ - j++; - } - while( j='0' && zIn[j]<='9' ){ - iExp = iExp*10 + zIn[j] - '0'; - } - j++; - } - if( neg ) iExp = -iExp; - break; + Decimal *p; + int n, i; + const unsigned char *zIn; + int iExp = 0; + p = sqlite3_malloc( sizeof(*p) ); + if( p==0 ) goto new_no_mem; + p->sign = 0; + p->oom = 0; + p->isInit = 1; + p->isNull = 0; + p->nDigit = 0; + p->nFrac = 0; + if( zAlt ){ + n = nAlt, + zIn = zAlt; + }else{ + if( sqlite3_value_type(pIn)==SQLITE_NULL ){ + p->a = 0; + p->isNull = 1; + return p; + } + n = sqlite3_value_bytes(pIn); + zIn = sqlite3_value_text(pIn); + } + p->a = sqlite3_malloc64( n+1 ); + if( p->a==0 ) goto new_no_mem; + for(i=0; isspace(zIn[i]); i++){} + if( zIn[i]=='-' ){ + p->sign = 1; + i++; + }else if( zIn[i]=='+' ){ + i++; + } + while( i='0' && c<='9' ){ + p->a[p->nDigit++] = c - '0'; + }else if( c=='.' ){ + p->nFrac = p->nDigit + 1; + }else if( c=='e' || c=='E' ){ + int j = i+1; + int neg = 0; + if( j>=n ) break; + if( zIn[j]=='-' ){ + neg = 1; + j++; + }else if( zIn[j]=='+' ){ + j++; + } + while( j='0' && zIn[j]<='9' ){ + iExp = iExp*10 + zIn[j] - '0'; } - i++; - } - if( p->nFrac ){ - p->nFrac = p->nDigit - (p->nFrac - 1); + j++; + } + if( neg ) iExp = -iExp; + break; + } + i++; + } + if( p->nFrac ){ + p->nFrac = p->nDigit - (p->nFrac - 1); + } + if( iExp>0 ){ + if( p->nFrac>0 ){ + if( iExp<=p->nFrac ){ + p->nFrac -= iExp; + iExp = 0; + }else{ + iExp -= p->nFrac; + p->nFrac = 0; + } + } + if( iExp>0 ){ + p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); + if( p->a==0 ) goto new_no_mem; + memset(p->a+p->nDigit, 0, iExp); + p->nDigit += iExp; + } + }else if( iExp<0 ){ + int nExtra; + iExp = -iExp; + nExtra = p->nDigit - p->nFrac - 1; + if( nExtra ){ + if( nExtra>=iExp ){ + p->nFrac += iExp; + iExp = 0; + }else{ + iExp -= nExtra; + p->nFrac = p->nDigit - 1; + } } if( iExp>0 ){ - if( p->nFrac>0 ){ - if( iExp<=p->nFrac ){ - p->nFrac -= iExp; - iExp = 0; - }else{ - iExp -= p->nFrac; - p->nFrac = 0; - } - } - if( iExp>0 ){ - p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); - if( p->a==0 ) goto new_no_mem; - memset(p->a+p->nDigit, 0, iExp); - p->nDigit += iExp; - } - }else if( iExp<0 ){ - int nExtra; - iExp = -iExp; - nExtra = p->nDigit - p->nFrac - 1; - if( nExtra ){ - if( nExtra>=iExp ){ - p->nFrac += iExp; - iExp = 0; - }else{ - iExp -= nExtra; - p->nFrac = p->nDigit - 1; - } - } - if( iExp>0 ){ - p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); - if( p->a==0 ) goto new_no_mem; - memmove(p->a+iExp, p->a, p->nDigit); - memset(p->a, 0, iExp); - p->nDigit += iExp; - p->nFrac += iExp; - } + p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); + if( p->a==0 ) goto new_no_mem; + memmove(p->a+iExp, p->a, p->nDigit); + memset(p->a, 0, iExp); + p->nDigit += iExp; + p->nFrac += iExp; } - return p; + } + return p; new_no_mem: - if( pCtx ) sqlite3_result_error_nomem(pCtx); - sqlite3_free(p); - return 0; + if( pCtx ) sqlite3_result_error_nomem(pCtx); + sqlite3_free(p); + return 0; } /* ** Make the given Decimal the result. */ static void decimal_result(sqlite3_context *pCtx, Decimal *p){ - char *z; - int i, j; - int n; - if( p==0 || p->oom ){ - sqlite3_result_error_nomem(pCtx); - return; - } - if( p->isNull ){ - sqlite3_result_null(pCtx); - return; - } - z = sqlite3_malloc( p->nDigit+4 ); - if( z==0 ){ - sqlite3_result_error_nomem(pCtx); - return; - } - i = 0; - if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){ - p->sign = 0; - } - if( p->sign ){ - z[0] = '-'; - i = 1; - } - n = p->nDigit - p->nFrac; - if( n<=0 ){ - z[i++] = '0'; - } - j = 0; - while( n>1 && p->a[j]==0 ){ - j++; - n--; - } - while( n>0 ){ - z[i++] = p->a[j] + '0'; - j++; - n--; - } - if( p->nFrac ){ - z[i++] = '.'; - do{ - z[i++] = p->a[j] + '0'; - j++; - }while( jnDigit ); - } - z[i] = 0; - sqlite3_result_text(pCtx, z, i, sqlite3_free); + char *z; + int i, j; + int n; + if( p==0 || p->oom ){ + sqlite3_result_error_nomem(pCtx); + return; + } + if( p->isNull ){ + sqlite3_result_null(pCtx); + return; + } + z = sqlite3_malloc( p->nDigit+4 ); + if( z==0 ){ + sqlite3_result_error_nomem(pCtx); + return; + } + i = 0; + if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){ + p->sign = 0; + } + if( p->sign ){ + z[0] = '-'; + i = 1; + } + n = p->nDigit - p->nFrac; + if( n<=0 ){ + z[i++] = '0'; + } + j = 0; + while( n>1 && p->a[j]==0 ){ + j++; + n--; + } + while( n>0 ){ + z[i++] = p->a[j] + '0'; + j++; + n--; + } + if( p->nFrac ){ + z[i++] = '.'; + do{ + z[i++] = p->a[j] + '0'; + j++; + }while( jnDigit ); + } + z[i] = 0; + sqlite3_result_text(pCtx, z, i, sqlite3_free); } /* @@ -4804,14 +4804,14 @@ static void decimal_result(sqlite3_context *pCtx, Decimal *p){ ** Convert input X into decimal and then back into text */ static void decimalFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *p = decimal_new(context, argv[0], 0, 0); - UNUSED_PARAMETER(argc); - decimal_result(context, p); - decimal_free(p); + Decimal *p = decimal_new(context, argv[0], 0, 0); + UNUSED_PARAMETER(argc); + decimal_result(context, p); + decimal_free(p); } /* @@ -4826,27 +4826,27 @@ static void decimalFunc( ** pB->isNull==0 */ static int decimal_cmp(const Decimal *pA, const Decimal *pB){ - int nASig, nBSig, rc, n; - if( pA->sign!=pB->sign ){ - return pA->sign ? -1 : +1; - } - if( pA->sign ){ - const Decimal *pTemp = pA; - pA = pB; - pB = pTemp; - } - nASig = pA->nDigit - pA->nFrac; - nBSig = pB->nDigit - pB->nFrac; - if( nASig!=nBSig ){ - return nASig - nBSig; - } - n = pA->nDigit; - if( n>pB->nDigit ) n = pB->nDigit; - rc = memcmp(pA->a, pB->a, n); - if( rc==0 ){ - rc = pA->nDigit - pB->nDigit; - } - return rc; + int nASig, nBSig, rc, n; + if( pA->sign!=pB->sign ){ + return pA->sign ? -1 : +1; + } + if( pA->sign ){ + const Decimal *pTemp = pA; + pA = pB; + pB = pTemp; + } + nASig = pA->nDigit - pA->nFrac; + nBSig = pB->nDigit - pB->nFrac; + if( nASig!=nBSig ){ + return nASig - nBSig; + } + n = pA->nDigit; + if( n>pB->nDigit ) n = pB->nDigit; + rc = memcmp(pA->a, pB->a, n); + if( rc==0 ){ + rc = pA->nDigit - pB->nDigit; + } + return rc; } /* @@ -4856,25 +4856,25 @@ static int decimal_cmp(const Decimal *pA, const Decimal *pB){ ** greater than Y. */ static void decimalCmpFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *pA = 0, *pB = 0; - int rc; - - UNUSED_PARAMETER(argc); - pA = decimal_new(context, argv[0], 0, 0); - if( pA==0 || pA->isNull ) goto cmp_done; - pB = decimal_new(context, argv[1], 0, 0); - if( pB==0 || pB->isNull ) goto cmp_done; - rc = decimal_cmp(pA, pB); - if( rc<0 ) rc = -1; - else if( rc>0 ) rc = +1; - sqlite3_result_int(context, rc); + Decimal *pA = 0, *pB = 0; + int rc; + + UNUSED_PARAMETER(argc); + pA = decimal_new(context, argv[0], 0, 0); + if( pA==0 || pA->isNull ) goto cmp_done; + pB = decimal_new(context, argv[1], 0, 0); + if( pB==0 || pB->isNull ) goto cmp_done; + rc = decimal_cmp(pA, pB); + if( rc<0 ) rc = -1; + else if( rc>0 ) rc = +1; + sqlite3_result_int(context, rc); cmp_done: - decimal_free(pA); - decimal_free(pB); + decimal_free(pA); + decimal_free(pB); } /* @@ -4882,27 +4882,27 @@ cmp_done: ** digits to the right of the decimal point. */ static void decimal_expand(Decimal *p, int nDigit, int nFrac){ - int nAddSig; - int nAddFrac; - if( p==0 ) return; - nAddFrac = nFrac - p->nFrac; - nAddSig = (nDigit - p->nDigit) - nAddFrac; - if( nAddFrac==0 && nAddSig==0 ) return; - p->a = sqlite3_realloc64(p->a, nDigit+1); - if( p->a==0 ){ - p->oom = 1; - return; - } - if( nAddSig ){ - memmove(p->a+nAddSig, p->a, p->nDigit); - memset(p->a, 0, nAddSig); - p->nDigit += nAddSig; - } - if( nAddFrac ){ - memset(p->a+p->nDigit, 0, nAddFrac); - p->nDigit += nAddFrac; - p->nFrac += nAddFrac; - } + int nAddSig; + int nAddFrac; + if( p==0 ) return; + nAddFrac = nFrac - p->nFrac; + nAddSig = (nDigit - p->nDigit) - nAddFrac; + if( nAddFrac==0 && nAddSig==0 ) return; + p->a = sqlite3_realloc64(p->a, nDigit+1); + if( p->a==0 ){ + p->oom = 1; + return; + } + if( nAddSig ){ + memmove(p->a+nAddSig, p->a, p->nDigit); + memset(p->a, 0, nAddSig); + p->nDigit += nAddSig; + } + if( nAddFrac ){ + memset(p->a+p->nDigit, 0, nAddFrac); + p->nDigit += nAddFrac; + p->nFrac += nAddFrac; + } } /* @@ -4911,92 +4911,92 @@ static void decimal_expand(Decimal *p, int nDigit, int nFrac){ ** Both pA and pB might become denormalized by this routine. */ static void decimal_add(Decimal *pA, Decimal *pB){ - int nSig, nFrac, nDigit; - int i, rc; - if( pA==0 ){ - return; - } - if( pA->oom || pB==0 || pB->oom ){ - pA->oom = 1; - return; - } - if( pA->isNull || pB->isNull ){ - pA->isNull = 1; - return; - } - nSig = pA->nDigit - pA->nFrac; - if( nSig && pA->a[0]==0 ) nSig--; - if( nSignDigit-pB->nFrac ){ - nSig = pB->nDigit - pB->nFrac; - } - nFrac = pA->nFrac; - if( nFracnFrac ) nFrac = pB->nFrac; - nDigit = nSig + nFrac + 1; - decimal_expand(pA, nDigit, nFrac); - decimal_expand(pB, nDigit, nFrac); - if( pA->oom || pB->oom ){ - pA->oom = 1; + int nSig, nFrac, nDigit; + int i, rc; + if( pA==0 ){ + return; + } + if( pA->oom || pB==0 || pB->oom ){ + pA->oom = 1; + return; + } + if( pA->isNull || pB->isNull ){ + pA->isNull = 1; + return; + } + nSig = pA->nDigit - pA->nFrac; + if( nSig && pA->a[0]==0 ) nSig--; + if( nSignDigit-pB->nFrac ){ + nSig = pB->nDigit - pB->nFrac; + } + nFrac = pA->nFrac; + if( nFracnFrac ) nFrac = pB->nFrac; + nDigit = nSig + nFrac + 1; + decimal_expand(pA, nDigit, nFrac); + decimal_expand(pB, nDigit, nFrac); + if( pA->oom || pB->oom ){ + pA->oom = 1; + }else{ + if( pA->sign==pB->sign ){ + int carry = 0; + for(i=nDigit-1; i>=0; i--){ + int x = pA->a[i] + pB->a[i] + carry; + if( x>=10 ){ + carry = 1; + pA->a[i] = x - 10; + }else{ + carry = 0; + pA->a[i] = x; + } + } }else{ - if( pA->sign==pB->sign ){ - int carry = 0; - for(i=nDigit-1; i>=0; i--){ - int x = pA->a[i] + pB->a[i] + carry; - if( x>=10 ){ - carry = 1; - pA->a[i] = x - 10; - }else{ - carry = 0; - pA->a[i] = x; - } - } + signed char *aA, *aB; + int borrow = 0; + rc = memcmp(pA->a, pB->a, nDigit); + if( rc<0 ){ + aA = pB->a; + aB = pA->a; + pA->sign = !pA->sign; + }else{ + aA = pA->a; + aB = pB->a; + } + for(i=nDigit-1; i>=0; i--){ + int x = aA[i] - aB[i] - borrow; + if( x<0 ){ + pA->a[i] = x+10; + borrow = 1; }else{ - signed char *aA, *aB; - int borrow = 0; - rc = memcmp(pA->a, pB->a, nDigit); - if( rc<0 ){ - aA = pB->a; - aB = pA->a; - pA->sign = !pA->sign; - }else{ - aA = pA->a; - aB = pB->a; - } - for(i=nDigit-1; i>=0; i--){ - int x = aA[i] - aB[i] - borrow; - if( x<0 ){ - pA->a[i] = x+10; - borrow = 1; - }else{ - pA->a[i] = x; - borrow = 0; - } - } + pA->a[i] = x; + borrow = 0; } + } } + } } /* ** Compare text in decimal order. */ static int decimalCollFunc( - void *notUsed, - int nKey1, const void *pKey1, - int nKey2, const void *pKey2 + void *notUsed, + int nKey1, const void *pKey1, + int nKey2, const void *pKey2 ){ - const unsigned char *zA = (const unsigned char*)pKey1; - const unsigned char *zB = (const unsigned char*)pKey2; - Decimal *pA = decimal_new(0, 0, nKey1, zA); - Decimal *pB = decimal_new(0, 0, nKey2, zB); - int rc; - UNUSED_PARAMETER(notUsed); - if( pA==0 || pB==0 ){ - rc = 0; - }else{ - rc = decimal_cmp(pA, pB); - } - decimal_free(pA); - decimal_free(pB); - return rc; + const unsigned char *zA = (const unsigned char*)pKey1; + const unsigned char *zB = (const unsigned char*)pKey2; + Decimal *pA = decimal_new(0, 0, nKey1, zA); + Decimal *pB = decimal_new(0, 0, nKey2, zB); + int rc; + UNUSED_PARAMETER(notUsed); + if( pA==0 || pB==0 ){ + rc = 0; + }else{ + rc = decimal_cmp(pA, pB); + } + decimal_free(pA); + decimal_free(pB); + return rc; } @@ -5007,33 +5007,33 @@ static int decimalCollFunc( ** Return the sum or difference of X and Y. */ static void decimalAddFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *pA = decimal_new(context, argv[0], 0, 0); - Decimal *pB = decimal_new(context, argv[1], 0, 0); - UNUSED_PARAMETER(argc); - decimal_add(pA, pB); - decimal_result(context, pA); - decimal_free(pA); - decimal_free(pB); + Decimal *pA = decimal_new(context, argv[0], 0, 0); + Decimal *pB = decimal_new(context, argv[1], 0, 0); + UNUSED_PARAMETER(argc); + decimal_add(pA, pB); + decimal_result(context, pA); + decimal_free(pA); + decimal_free(pB); } static void decimalSubFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *pA = decimal_new(context, argv[0], 0, 0); - Decimal *pB = decimal_new(context, argv[1], 0, 0); - UNUSED_PARAMETER(argc); - if( pB ){ - pB->sign = !pB->sign; - decimal_add(pA, pB); - decimal_result(context, pA); - } - decimal_free(pA); - decimal_free(pB); + Decimal *pA = decimal_new(context, argv[0], 0, 0); + Decimal *pB = decimal_new(context, argv[1], 0, 0); + UNUSED_PARAMETER(argc); + if( pB ){ + pB->sign = !pB->sign; + decimal_add(pA, pB); + decimal_result(context, pA); + } + decimal_free(pA); + decimal_free(pB); } /* Aggregate funcion: decimal_sum(X) @@ -5042,57 +5042,57 @@ static void decimalSubFunc( ** precision. */ static void decimalSumStep( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *p; - Decimal *pArg; - UNUSED_PARAMETER(argc); - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( !p->isInit ){ - p->isInit = 1; - p->a = sqlite3_malloc(2); - if( p->a==0 ){ - p->oom = 1; - }else{ - p->a[0] = 0; - } - p->nDigit = 1; - p->nFrac = 0; + Decimal *p; + Decimal *pArg; + UNUSED_PARAMETER(argc); + p = sqlite3_aggregate_context(context, sizeof(*p)); + if( p==0 ) return; + if( !p->isInit ){ + p->isInit = 1; + p->a = sqlite3_malloc(2); + if( p->a==0 ){ + p->oom = 1; + }else{ + p->a[0] = 0; } - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pArg = decimal_new(context, argv[0], 0, 0); - decimal_add(p, pArg); - decimal_free(pArg); + p->nDigit = 1; + p->nFrac = 0; + } + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + pArg = decimal_new(context, argv[0], 0, 0); + decimal_add(p, pArg); + decimal_free(pArg); } static void decimalSumInverse( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *p; - Decimal *pArg; - UNUSED_PARAMETER(argc); - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; - pArg = decimal_new(context, argv[0], 0, 0); - if( pArg ) pArg->sign = !pArg->sign; - decimal_add(p, pArg); - decimal_free(pArg); + Decimal *p; + Decimal *pArg; + UNUSED_PARAMETER(argc); + p = sqlite3_aggregate_context(context, sizeof(*p)); + if( p==0 ) return; + if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; + pArg = decimal_new(context, argv[0], 0, 0); + if( pArg ) pArg->sign = !pArg->sign; + decimal_add(p, pArg); + decimal_free(pArg); } static void decimalSumValue(sqlite3_context *context){ - Decimal *p = sqlite3_aggregate_context(context, 0); - if( p==0 ) return; - decimal_result(context, p); + Decimal *p = sqlite3_aggregate_context(context, 0); + if( p==0 ) return; + decimal_result(context, p); } static void decimalSumFinalize(sqlite3_context *context){ - Decimal *p = sqlite3_aggregate_context(context, 0); - if( p==0 ) return; - decimal_result(context, p); - decimal_clear(p); + Decimal *p = sqlite3_aggregate_context(context, 0); + if( p==0 ) return; + decimal_result(context, p); + decimal_clear(p); } /* @@ -5106,100 +5106,100 @@ static void decimalSumFinalize(sqlite3_context *context){ ** either the number of digits in either input. */ static void decimalMulFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - Decimal *pA = decimal_new(context, argv[0], 0, 0); - Decimal *pB = decimal_new(context, argv[1], 0, 0); - signed char *acc = 0; - int i, j, k; - int minFrac; - UNUSED_PARAMETER(argc); - if( pA==0 || pA->oom || pA->isNull - || pB==0 || pB->oom || pB->isNull - ){ - goto mul_end; - } - acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 ); - if( acc==0 ){ - sqlite3_result_error_nomem(context); - goto mul_end; - } - memset(acc, 0, pA->nDigit + pB->nDigit + 2); - minFrac = pA->nFrac; - if( pB->nFracnFrac; - for(i=pA->nDigit-1; i>=0; i--){ - signed char f = pA->a[i]; - int carry = 0, x; - for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){ - x = acc[k] + f*pB->a[j] + carry; - acc[k] = x%10; - carry = x/10; - } - x = acc[k] + carry; - acc[k] = x%10; - acc[k-1] += x/10; - } - sqlite3_free(pA->a); - pA->a = acc; - acc = 0; - pA->nDigit += pB->nDigit + 2; - pA->nFrac += pB->nFrac; - pA->sign ^= pB->sign; - while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){ - pA->nFrac--; - pA->nDigit--; - } - decimal_result(context, pA); + Decimal *pA = decimal_new(context, argv[0], 0, 0); + Decimal *pB = decimal_new(context, argv[1], 0, 0); + signed char *acc = 0; + int i, j, k; + int minFrac; + UNUSED_PARAMETER(argc); + if( pA==0 || pA->oom || pA->isNull + || pB==0 || pB->oom || pB->isNull + ){ + goto mul_end; + } + acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 ); + if( acc==0 ){ + sqlite3_result_error_nomem(context); + goto mul_end; + } + memset(acc, 0, pA->nDigit + pB->nDigit + 2); + minFrac = pA->nFrac; + if( pB->nFracnFrac; + for(i=pA->nDigit-1; i>=0; i--){ + signed char f = pA->a[i]; + int carry = 0, x; + for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){ + x = acc[k] + f*pB->a[j] + carry; + acc[k] = x%10; + carry = x/10; + } + x = acc[k] + carry; + acc[k] = x%10; + acc[k-1] += x/10; + } + sqlite3_free(pA->a); + pA->a = acc; + acc = 0; + pA->nDigit += pB->nDigit + 2; + pA->nFrac += pB->nFrac; + pA->sign ^= pB->sign; + while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){ + pA->nFrac--; + pA->nDigit--; + } + decimal_result(context, pA); mul_end: - sqlite3_free(acc); - decimal_free(pA); - decimal_free(pB); + sqlite3_free(acc); + decimal_free(pA); + decimal_free(pB); } #ifdef _WIN32 #endif int sqlite3_decimal_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - int rc = SQLITE_OK; - static const struct { - const char *zFuncName; - int nArg; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "decimal", 1, decimalFunc }, - { "decimal_cmp", 2, decimalCmpFunc }, - { "decimal_add", 2, decimalAddFunc }, - { "decimal_sub", 2, decimalSubFunc }, - { "decimal_mul", 2, decimalMulFunc }, - }; - unsigned int i; - (void)pzErrMsg; /* Unused parameter */ - - SQLITE_EXTENSION_INIT2(pApi); - - for(i=0; i>52; - m = a & ((((sqlite3_int64)1)<<52)-1); - if( e==0 ){ - m <<= 1; - }else{ - m |= ((sqlite3_int64)1)<<52; - } - while( e<1075 && m>0 && (m&1)==0 ){ - m >>= 1; - e++; - } - if( isNeg ) m = -m; - } - switch( *(int*)sqlite3_user_data(context) ){ - case 0: - sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", - m, e-1075); - sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); - break; - case 1: - sqlite3_result_int64(context, m); - break; - case 2: - sqlite3_result_int(context, e-1075); - break; - } + if( argc==1 ){ + sqlite3_int64 m, a; + double r; + int e; + int isNeg; + char zResult[100]; + assert( sizeof(m)==sizeof(r) ); + if( sqlite3_value_type(argv[0])==SQLITE_BLOB + && sqlite3_value_bytes(argv[0])==sizeof(r) + ){ + const unsigned char *x = sqlite3_value_blob(argv[0]); + unsigned int i; + sqlite3_uint64 v = 0; + for(i=0; i10000 ){ - e = 10000; - }else if( e<-10000 ){ - e = -10000; - } - - if( m<0 ){ - isNeg = 1; - m = -m; - if( m<0 ) return; - }else if( m==0 && e>-1000 && e<1000 ){ - sqlite3_result_double(context, 0.0); - return; - } - while( (m>>32)&0xffe00000 ){ - m >>= 1; - e++; - } - while( m!=0 && ((m>>32)&0xfff00000)==0 ){ - m <<= 1; - e--; - } - e += 1075; - if( e<=0 ){ - /* Subnormal */ - if( 1-e >= 64 ){ - m = 0; - }else{ - m >>= 1-e; - } - e = 0; - }else if( e>0x7ff ){ - e = 0x7ff; - } - a = m & ((((sqlite3_int64)1)<<52)-1); - a |= e<<52; - if( isNeg ) a |= ((sqlite3_uint64)1)<<63; - memcpy(&r, &a, sizeof(r)); - sqlite3_result_double(context, r); + r = sqlite3_value_double(argv[0]); + } + if( r<0.0 ){ + isNeg = 1; + r = -r; + }else{ + isNeg = 0; } + memcpy(&a,&r,sizeof(a)); + if( a==0 ){ + e = 0; + m = 0; + }else{ + e = a>>52; + m = a & ((((sqlite3_int64)1)<<52)-1); + if( e==0 ){ + m <<= 1; + }else{ + m |= ((sqlite3_int64)1)<<52; + } + while( e<1075 && m>0 && (m&1)==0 ){ + m >>= 1; + e++; + } + if( isNeg ) m = -m; + } + switch( *(int*)sqlite3_user_data(context) ){ + case 0: + sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", + m, e-1075); + sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); + break; + case 1: + sqlite3_result_int64(context, m); + break; + case 2: + sqlite3_result_int(context, e-1075); + break; + } + }else{ + sqlite3_int64 m, e, a; + double r; + int isNeg = 0; + m = sqlite3_value_int64(argv[0]); + e = sqlite3_value_int64(argv[1]); + + /* Limit the range of e. Ticket 22dea1cfdb9151e4 2021-03-02 */ + if( e>10000 ){ + e = 10000; + }else if( e<-10000 ){ + e = -10000; + } + + if( m<0 ){ + isNeg = 1; + m = -m; + if( m<0 ) return; + }else if( m==0 && e>-1000 && e<1000 ){ + sqlite3_result_double(context, 0.0); + return; + } + while( (m>>32)&0xffe00000 ){ + m >>= 1; + e++; + } + while( m!=0 && ((m>>32)&0xfff00000)==0 ){ + m <<= 1; + e--; + } + e += 1075; + if( e<=0 ){ + /* Subnormal */ + if( 1-e >= 64 ){ + m = 0; + }else{ + m >>= 1-e; + } + e = 0; + }else if( e>0x7ff ){ + e = 0x7ff; + } + a = m & ((((sqlite3_int64)1)<<52)-1); + a |= e<<52; + if( isNeg ) a |= ((sqlite3_uint64)1)<<63; + memcpy(&r, &a, sizeof(r)); + sqlite3_result_double(context, r); + } } /* ** Functions to convert between blobs and floats. */ static void ieee754func_from_blob( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - UNUSED_PARAMETER(argc); - if( sqlite3_value_type(argv[0])==SQLITE_BLOB - && sqlite3_value_bytes(argv[0])==sizeof(double) - ){ - double r; - const unsigned char *x = sqlite3_value_blob(argv[0]); - unsigned int i; - sqlite3_uint64 v = 0; - for(i=0; i>= 8; - } - sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT); + UNUSED_PARAMETER(argc); + if( sqlite3_value_type(argv[0])==SQLITE_FLOAT + || sqlite3_value_type(argv[0])==SQLITE_INTEGER + ){ + double r = sqlite3_value_double(argv[0]); + sqlite3_uint64 v; + unsigned char a[sizeof(r)]; + unsigned int i; + memcpy(&v, &r, sizeof(r)); + for(i=1; i<=sizeof(r); i++){ + a[sizeof(r)-i] = v&0xff; + v >>= 8; } + sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT); + } } @@ -5467,35 +5467,35 @@ static void ieee754func_to_blob( #endif int sqlite3_ieee_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - static const struct { - char *zFName; - int nArg; - int iAux; - void (*xFunc)(sqlite3_context*,int,sqlite3_value**); - } aFunc[] = { - { "ieee754", 1, 0, ieee754func }, - { "ieee754", 2, 0, ieee754func }, - { "ieee754_mantissa", 1, 1, ieee754func }, - { "ieee754_exponent", 1, 2, ieee754func }, - { "ieee754_to_blob", 1, 0, ieee754func_to_blob }, - { "ieee754_from_blob", 1, 0, ieee754func_from_blob }, - - }; - unsigned int i; - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - for(i=0; ibase; - return SQLITE_OK; + series_cursor *pCur; + (void)pUnused; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; + return SQLITE_OK; } /* ** Destructor for a series_cursor. */ static int seriesClose(sqlite3_vtab_cursor *cur){ - sqlite3_free(cur); - return SQLITE_OK; + sqlite3_free(cur); + return SQLITE_OK; } @@ -5671,14 +5671,14 @@ static int seriesClose(sqlite3_vtab_cursor *cur){ ** Advance a series_cursor to its next row of output. */ static int seriesNext(sqlite3_vtab_cursor *cur){ - series_cursor *pCur = (series_cursor*)cur; - if( pCur->isDesc ){ - pCur->iValue -= pCur->iStep; - }else{ - pCur->iValue += pCur->iStep; - } - pCur->iRowid++; - return SQLITE_OK; + series_cursor *pCur = (series_cursor*)cur; + if( pCur->isDesc ){ + pCur->iValue -= pCur->iStep; + }else{ + pCur->iValue += pCur->iStep; + } + pCur->iRowid++; + return SQLITE_OK; } /* @@ -5686,20 +5686,20 @@ static int seriesNext(sqlite3_vtab_cursor *cur){ ** is currently pointing. */ static int seriesColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ ){ - series_cursor *pCur = (series_cursor*)cur; - sqlite3_int64 x = 0; - switch( i ){ - case SERIES_COLUMN_START: x = pCur->mnValue; break; - case SERIES_COLUMN_STOP: x = pCur->mxValue; break; - case SERIES_COLUMN_STEP: x = pCur->iStep; break; - default: x = pCur->iValue; break; - } - sqlite3_result_int64(ctx, x); - return SQLITE_OK; + series_cursor *pCur = (series_cursor*)cur; + sqlite3_int64 x = 0; + switch( i ){ + case SERIES_COLUMN_START: x = pCur->mnValue; break; + case SERIES_COLUMN_STOP: x = pCur->mxValue; break; + case SERIES_COLUMN_STEP: x = pCur->iStep; break; + default: x = pCur->iValue; break; + } + sqlite3_result_int64(ctx, x); + return SQLITE_OK; } /* @@ -5708,9 +5708,9 @@ static int seriesColumn( ** row a value 1 more than that of the previous. */ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - series_cursor *pCur = (series_cursor*)cur; - *pRowid = pCur->iRowid; - return SQLITE_OK; + series_cursor *pCur = (series_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; } /* @@ -5718,15 +5718,15 @@ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ ** row of output. */ static int seriesEof(sqlite3_vtab_cursor *cur){ - series_cursor *pCur = (series_cursor*)cur; - if( pCur->isDesc ){ - return pCur->iValue < pCur->mnValue; - }else{ - return pCur->iValue > pCur->mxValue; - } + series_cursor *pCur = (series_cursor*)cur; + if( pCur->isDesc ){ + return pCur->iValue < pCur->mnValue; + }else{ + return pCur->iValue > pCur->mxValue; + } } -/* True to cause run-time checking of the start=, stop=, and/or step= +/* True to cause run-time checking of the start=, stop=, and/or step= ** parameters. The only reason to do this is for testing the ** constraint checking logic for virtual tables in the SQLite core. */ @@ -5737,7 +5737,7 @@ static int seriesEof(sqlite3_vtab_cursor *cur){ /* ** This method is called to "rewind" the series_cursor object back ** to the first row of output. This method is always called at least -** once prior to any call to seriesColumn() or seriesRowid() or +** once prior to any call to seriesColumn() or seriesRowid() or ** seriesEof(). ** ** The query plan selected by seriesBestIndex is passed in the idxNum @@ -5757,55 +5757,55 @@ static int seriesEof(sqlite3_vtab_cursor *cur){ ** (so that seriesEof() will return true) if the table is empty. */ static int seriesFilter( - sqlite3_vtab_cursor *pVtabCursor, - int idxNum, const char *idxStrUnused, - int argc, sqlite3_value **argv + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStrUnused, + int argc, sqlite3_value **argv ){ - series_cursor *pCur = (series_cursor *)pVtabCursor; - int i = 0; - (void)idxStrUnused; - if( idxNum & 1 ){ - pCur->mnValue = sqlite3_value_int64(argv[i++]); - }else{ - pCur->mnValue = 0; - } - if( idxNum & 2 ){ - pCur->mxValue = sqlite3_value_int64(argv[i++]); - }else{ - pCur->mxValue = 0xffffffff; - } - if( idxNum & 4 ){ - pCur->iStep = sqlite3_value_int64(argv[i++]); - if( pCur->iStep==0 ){ - pCur->iStep = 1; - }else if( pCur->iStep<0 ){ - pCur->iStep = -pCur->iStep; - if( (idxNum & 16)==0 ) idxNum |= 8; - } - }else{ - pCur->iStep = 1; - } - for(i=0; imnValue = sqlite3_value_int64(argv[i++]); + }else{ + pCur->mnValue = 0; + } + if( idxNum & 2 ){ + pCur->mxValue = sqlite3_value_int64(argv[i++]); + }else{ + pCur->mxValue = 0xffffffff; + } + if( idxNum & 4 ){ + pCur->iStep = sqlite3_value_int64(argv[i++]); + if( pCur->iStep==0 ){ + pCur->iStep = 1; + }else if( pCur->iStep<0 ){ + pCur->iStep = -pCur->iStep; + if( (idxNum & 16)==0 ) idxNum |= 8; + } + }else{ + pCur->iStep = 1; + } + for(i=0; imnValue = 1; - pCur->mxValue = 0; - break; - } + pCur->mnValue = 1; + pCur->mxValue = 0; + break; } - if( idxNum & 8 ){ - pCur->isDesc = 1; - pCur->iValue = pCur->mxValue; - if( pCur->iStep>0 ){ - pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep; - } - }else{ - pCur->isDesc = 0; - pCur->iValue = pCur->mnValue; + } + if( idxNum & 8 ){ + pCur->isDesc = 1; + pCur->iValue = pCur->mxValue; + if( pCur->iStep>0 ){ + pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep; } - pCur->iRowid = 1; - return SQLITE_OK; + }else{ + pCur->isDesc = 0; + pCur->iValue = pCur->mnValue; + } + pCur->iRowid = 1; + return SQLITE_OK; } /* @@ -5825,116 +5825,116 @@ static int seriesFilter( ** (8) output in descending order */ static int seriesBestIndex( - sqlite3_vtab *pVTab, - sqlite3_index_info *pIdxInfo + sqlite3_vtab *pVTab, + sqlite3_index_info *pIdxInfo ){ - int i, j; /* Loop over constraints */ - int idxNum = 0; /* The query plan bitmask */ - int bStartSeen = 0; /* EQ constraint seen on the START column */ - int unusableMask = 0; /* Mask of unusable constraints */ - int nArg = 0; /* Number of arguments that seriesFilter() expects */ - int aIdx[3]; /* Constraints on start, stop, and step */ - const struct sqlite3_index_constraint *pConstraint; - - /* This implementation assumes that the start, stop, and step columns + int i, j; /* Loop over constraints */ + int idxNum = 0; /* The query plan bitmask */ + int bStartSeen = 0; /* EQ constraint seen on the START column */ + int unusableMask = 0; /* Mask of unusable constraints */ + int nArg = 0; /* Number of arguments that seriesFilter() expects */ + int aIdx[3]; /* Constraints on start, stop, and step */ + const struct sqlite3_index_constraint *pConstraint; + + /* This implementation assumes that the start, stop, and step columns ** are the last three columns in the virtual table. */ - assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 ); - assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 ); - - aIdx[0] = aIdx[1] = aIdx[2] = -1; - pConstraint = pIdxInfo->aConstraint; - for(i=0; inConstraint; i++, pConstraint++){ - int iCol; /* 0 for start, 1 for stop, 2 for step */ - int iMask; /* bitmask for those column */ - if( pConstraint->iColumniColumn - SERIES_COLUMN_START; - assert( iCol>=0 && iCol<=2 ); - iMask = 1 << iCol; - if( iCol==0 ) bStartSeen = 1; - if( pConstraint->usable==0 ){ - unusableMask |= iMask; - continue; - }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ - idxNum |= iMask; - aIdx[iCol] = i; - } - } - for(i=0; i<3; i++){ - if( (j = aIdx[i])>=0 ){ - pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg; - pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY; - } - } - /* The current generate_column() implementation requires at least one + assert( SERIES_COLUMN_STOP == SERIES_COLUMN_START+1 ); + assert( SERIES_COLUMN_STEP == SERIES_COLUMN_START+2 ); + + aIdx[0] = aIdx[1] = aIdx[2] = -1; + pConstraint = pIdxInfo->aConstraint; + for(i=0; inConstraint; i++, pConstraint++){ + int iCol; /* 0 for start, 1 for stop, 2 for step */ + int iMask; /* bitmask for those column */ + if( pConstraint->iColumniColumn - SERIES_COLUMN_START; + assert( iCol>=0 && iCol<=2 ); + iMask = 1 << iCol; + if( iCol==0 ) bStartSeen = 1; + if( pConstraint->usable==0 ){ + unusableMask |= iMask; + continue; + }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + idxNum |= iMask; + aIdx[iCol] = i; + } + } + for(i=0; i<3; i++){ + if( (j = aIdx[i])>=0 ){ + pIdxInfo->aConstraintUsage[j].argvIndex = ++nArg; + pIdxInfo->aConstraintUsage[j].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY; + } + } + /* The current generate_column() implementation requires at least one ** argument (the START value). Legacy versions assumed START=0 if the ** first argument was omitted. Compile with -DZERO_ARGUMENT_GENERATE_SERIES ** to obtain the legacy behavior */ #ifndef ZERO_ARGUMENT_GENERATE_SERIES - if( !bStartSeen ){ - sqlite3_free(pVTab->zErrMsg); - pVTab->zErrMsg = sqlite3_mprintf( - "first argument to \"generate_series()\" missing or unusable"); - return SQLITE_ERROR; - } + if( !bStartSeen ){ + sqlite3_free(pVTab->zErrMsg); + pVTab->zErrMsg = sqlite3_mprintf( + "first argument to \"generate_series()\" missing or unusable"); + return SQLITE_ERROR; + } #endif - if( (unusableMask & ~idxNum)!=0 ){ - /* The start, stop, and step columns are inputs. Therefore if there + if( (unusableMask & ~idxNum)!=0 ){ + /* The start, stop, and step columns are inputs. Therefore if there ** are unusable constraints on any of start, stop, or step then ** this plan is unusable */ - return SQLITE_CONSTRAINT; - } - if( (idxNum & 3)==3 ){ - /* Both start= and stop= boundaries are available. This is the + return SQLITE_CONSTRAINT; + } + if( (idxNum & 3)==3 ){ + /* Both start= and stop= boundaries are available. This is the ** the preferred case */ - pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0)); - pIdxInfo->estimatedRows = 1000; - if( pIdxInfo->nOrderBy==1 ){ - if( pIdxInfo->aOrderBy[0].desc ){ - idxNum |= 8; - }else{ - idxNum |= 16; - } - pIdxInfo->orderByConsumed = 1; - } - }else{ - /* If either boundary is missing, we have to generate a huge span + pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0)); + pIdxInfo->estimatedRows = 1000; + if( pIdxInfo->nOrderBy==1 ){ + if( pIdxInfo->aOrderBy[0].desc ){ + idxNum |= 8; + }else{ + idxNum |= 16; + } + pIdxInfo->orderByConsumed = 1; + } + }else{ + /* If either boundary is missing, we have to generate a huge span ** of numbers. Make this case very expensive so that the query ** planner will work hard to avoid it. */ - pIdxInfo->estimatedRows = 2147483647; - } - pIdxInfo->idxNum = idxNum; - return SQLITE_OK; + pIdxInfo->estimatedRows = 2147483647; + } + pIdxInfo->idxNum = idxNum; + return SQLITE_OK; } /* -** This following structure defines all the methods for the +** This following structure defines all the methods for the ** generate_series virtual table. */ static sqlite3_module seriesModule = { - 0, /* iVersion */ - 0, /* xCreate */ - seriesConnect, /* xConnect */ - seriesBestIndex, /* xBestIndex */ - seriesDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - seriesOpen, /* xOpen - open a cursor */ - seriesClose, /* xClose - close a cursor */ - seriesFilter, /* xFilter - configure scan constraints */ - seriesNext, /* xNext - advance a cursor */ - seriesEof, /* xEof - check for end of scan */ - seriesColumn, /* xColumn - read data */ - seriesRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0 /* xShadowName */ + 0, /* iVersion */ + 0, /* xCreate */ + seriesConnect, /* xConnect */ + seriesBestIndex, /* xBestIndex */ + seriesDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + seriesOpen, /* xOpen - open a cursor */ + seriesClose, /* xClose - close a cursor */ + seriesFilter, /* xFilter - configure scan constraints */ + seriesNext, /* xNext - advance a cursor */ + seriesEof, /* xEof - check for end of scan */ + seriesColumn, /* xColumn - read data */ + seriesRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -5943,21 +5943,21 @@ static sqlite3_module seriesModule = { #endif int sqlite3_series_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( sqlite3_libversion_number()<3008012 && pzErrMsg!=0 ){ - *pzErrMsg = sqlite3_mprintf( - "generate_series() requires SQLite 3.8.12 or later"); - return SQLITE_ERROR; - } - rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0); + if( sqlite3_libversion_number()<3008012 && pzErrMsg!=0 ){ + *pzErrMsg = sqlite3_mprintf( + "generate_series() requires SQLite 3.8.12 or later"); + return SQLITE_ERROR; + } + rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0); #endif - return rc; + return rc; } /************************* End ../ext/misc/series.c ********************/ @@ -6067,17 +6067,17 @@ typedef unsigned short ReStateNumber; ** number of actives states is small. */ typedef struct ReStateSet { - unsigned nState; /* Number of current states */ - ReStateNumber *aState; /* Current states */ + unsigned nState; /* Number of current states */ + ReStateNumber *aState; /* Current states */ } ReStateSet; /* An input string read one character at a time. */ typedef struct ReInput ReInput; struct ReInput { - const unsigned char *z; /* All text */ - int i; /* Next byte to read */ - int mx; /* EOF when i>=mx */ + const unsigned char *z; /* All text */ + int i; /* Next byte to read */ + int mx; /* EOF when i>=mx */ }; /* A compiled NFA (or an NFA that is in the process of being compiled) is @@ -6085,265 +6085,265 @@ struct ReInput { */ typedef struct ReCompiled ReCompiled; struct ReCompiled { - ReInput sIn; /* Regular expression text */ - const char *zErr; /* Error message to return */ - char *aOp; /* Operators for the virtual machine */ - int *aArg; /* Arguments to each operator */ - unsigned (*xNextChar)(ReInput*); /* Next character function */ - unsigned char zInit[12]; /* Initial text to match */ - int nInit; /* Number of characters in zInit */ - unsigned nState; /* Number of entries in aOp[] and aArg[] */ - unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ + ReInput sIn; /* Regular expression text */ + const char *zErr; /* Error message to return */ + char *aOp; /* Operators for the virtual machine */ + int *aArg; /* Arguments to each operator */ + unsigned (*xNextChar)(ReInput*); /* Next character function */ + unsigned char zInit[12]; /* Initial text to match */ + int nInit; /* Number of characters in zInit */ + unsigned nState; /* Number of entries in aOp[] and aArg[] */ + unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ }; /* Add a state to the given state set if it is not already there */ static void re_add_state(ReStateSet *pSet, int newState){ - unsigned i; - for(i=0; inState; i++) if( pSet->aState[i]==newState ) return; - pSet->aState[pSet->nState++] = (ReStateNumber)newState; + unsigned i; + for(i=0; inState; i++) if( pSet->aState[i]==newState ) return; + pSet->aState[pSet->nState++] = (ReStateNumber)newState; } /* Extract the next unicode character from *pzIn and return it. Advance ** *pzIn to the first byte past the end of the character returned. To -** be clear: this routine converts utf8 to unicode. This routine is +** be clear: this routine converts utf8 to unicode. This routine is ** optimized for the common case where the next character is a single byte. */ static unsigned re_next_char(ReInput *p){ - unsigned c; - if( p->i>=p->mx ) return 0; - c = p->z[p->i++]; - if( c>=0x80 ){ - if( (c&0xe0)==0xc0 && p->imx && (p->z[p->i]&0xc0)==0x80 ){ - c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); - if( c<0x80 ) c = 0xfffd; - }else if( (c&0xf0)==0xe0 && p->i+1mx && (p->z[p->i]&0xc0)==0x80 - && (p->z[p->i+1]&0xc0)==0x80 ){ - c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); - p->i += 2; - if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd; - }else if( (c&0xf8)==0xf0 && p->i+3mx && (p->z[p->i]&0xc0)==0x80 - && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){ - c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6) - | (p->z[p->i+2]&0x3f); - p->i += 3; - if( c<=0xffff || c>0x10ffff ) c = 0xfffd; - }else{ - c = 0xfffd; - } + unsigned c; + if( p->i>=p->mx ) return 0; + c = p->z[p->i++]; + if( c>=0x80 ){ + if( (c&0xe0)==0xc0 && p->imx && (p->z[p->i]&0xc0)==0x80 ){ + c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); + if( c<0x80 ) c = 0xfffd; + }else if( (c&0xf0)==0xe0 && p->i+1mx && (p->z[p->i]&0xc0)==0x80 + && (p->z[p->i+1]&0xc0)==0x80 ){ + c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); + p->i += 2; + if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd; + }else if( (c&0xf8)==0xf0 && p->i+3mx && (p->z[p->i]&0xc0)==0x80 + && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){ + c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6) + | (p->z[p->i+2]&0x3f); + p->i += 3; + if( c<=0xffff || c>0x10ffff ) c = 0xfffd; + }else{ + c = 0xfffd; } - return c; + } + return c; } static unsigned re_next_char_nocase(ReInput *p){ - unsigned c = re_next_char(p); - if( c>='A' && c<='Z' ) c += 'a' - 'A'; - return c; + unsigned c = re_next_char(p); + if( c>='A' && c<='Z' ) c += 'a' - 'A'; + return c; } /* Return true if c is a perl "word" character: [A-Za-z0-9_] */ static int re_word_char(int c){ - return (c>='0' && c<='9') || (c>='a' && c<='z') - || (c>='A' && c<='Z') || c=='_'; + return (c>='0' && c<='9') || (c>='a' && c<='z') + || (c>='A' && c<='Z') || c=='_'; } /* Return true if c is a "digit" character: [0-9] */ static int re_digit_char(int c){ - return (c>='0' && c<='9'); + return (c>='0' && c<='9'); } /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */ static int re_space_char(int c){ - return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; + return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } /* Run a compiled regular expression on the zero-terminated input ** string zIn[]. Return true on a match and false if there is no match. */ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ - ReStateSet aStateSet[2], *pThis, *pNext; - ReStateNumber aSpace[100]; - ReStateNumber *pToFree; - unsigned int i = 0; - unsigned int iSwap = 0; - int c = RE_EOF+1; - int cPrev = 0; - int rc = 0; - ReInput in; - - in.z = zIn; - in.i = 0; - in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn); - - /* Look for the initial prefix match, if there is one. */ - if( pRe->nInit ){ - unsigned char x = pRe->zInit[0]; - while( in.i+pRe->nInit<=in.mx - && (zIn[in.i]!=x || - strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) - ){ - in.i++; + ReStateSet aStateSet[2], *pThis, *pNext; + ReStateNumber aSpace[100]; + ReStateNumber *pToFree; + unsigned int i = 0; + unsigned int iSwap = 0; + int c = RE_EOF+1; + int cPrev = 0; + int rc = 0; + ReInput in; + + in.z = zIn; + in.i = 0; + in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn); + + /* Look for the initial prefix match, if there is one. */ + if( pRe->nInit ){ + unsigned char x = pRe->zInit[0]; + while( in.i+pRe->nInit<=in.mx + && (zIn[in.i]!=x || + strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) + ){ + in.i++; + } + if( in.i+pRe->nInit>in.mx ) return 0; + } + + if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ + pToFree = 0; + aStateSet[0].aState = aSpace; + }else{ + pToFree = sqlite3_malloc64( sizeof(ReStateNumber)*2*pRe->nState ); + if( pToFree==0 ) return -1; + aStateSet[0].aState = pToFree; + } + aStateSet[1].aState = &aStateSet[0].aState[pRe->nState]; + pNext = &aStateSet[1]; + pNext->nState = 0; + re_add_state(pNext, 0); + while( c!=RE_EOF && pNext->nState>0 ){ + cPrev = c; + c = pRe->xNextChar(&in); + pThis = pNext; + pNext = &aStateSet[iSwap]; + iSwap = 1 - iSwap; + pNext->nState = 0; + for(i=0; inState; i++){ + int x = pThis->aState[i]; + switch( pRe->aOp[x] ){ + case RE_OP_MATCH: { + if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); + break; + } + case RE_OP_ANY: { + if( c!=0 ) re_add_state(pNext, x+1); + break; + } + case RE_OP_WORD: { + if( re_word_char(c) ) re_add_state(pNext, x+1); + break; + } + case RE_OP_NOTWORD: { + if( !re_word_char(c) && c!=0 ) re_add_state(pNext, x+1); + break; + } + case RE_OP_DIGIT: { + if( re_digit_char(c) ) re_add_state(pNext, x+1); + break; + } + case RE_OP_NOTDIGIT: { + if( !re_digit_char(c) && c!=0 ) re_add_state(pNext, x+1); + break; + } + case RE_OP_SPACE: { + if( re_space_char(c) ) re_add_state(pNext, x+1); + break; + } + case RE_OP_NOTSPACE: { + if( !re_space_char(c) && c!=0 ) re_add_state(pNext, x+1); + break; + } + case RE_OP_BOUNDARY: { + if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1); + break; + } + case RE_OP_ANYSTAR: { + re_add_state(pNext, x); + re_add_state(pThis, x+1); + break; + } + case RE_OP_FORK: { + re_add_state(pThis, x+pRe->aArg[x]); + re_add_state(pThis, x+1); + break; + } + case RE_OP_GOTO: { + re_add_state(pThis, x+pRe->aArg[x]); + break; + } + case RE_OP_ACCEPT: { + rc = 1; + goto re_match_end; + } + case RE_OP_CC_EXC: { + if( c==0 ) break; + /* fall-through */ goto re_op_cc_inc; + } + case RE_OP_CC_INC: re_op_cc_inc: { + int j = 1; + int n = pRe->aArg[x]; + int hit = 0; + for(j=1; j>0 && jaOp[x+j]==RE_OP_CC_VALUE ){ + if( pRe->aArg[x+j]==c ){ + hit = 1; + j = -1; + } + }else{ + if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){ + hit = 1; + j = -1; + }else{ + j++; + } + } + } + if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; + if( hit ) re_add_state(pNext, x+n); + break; } - if( in.i+pRe->nInit>in.mx ) return 0; + } } - - if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ - pToFree = 0; - aStateSet[0].aState = aSpace; - }else{ - pToFree = sqlite3_malloc64( sizeof(ReStateNumber)*2*pRe->nState ); - if( pToFree==0 ) return -1; - aStateSet[0].aState = pToFree; - } - aStateSet[1].aState = &aStateSet[0].aState[pRe->nState]; - pNext = &aStateSet[1]; - pNext->nState = 0; - re_add_state(pNext, 0); - while( c!=RE_EOF && pNext->nState>0 ){ - cPrev = c; - c = pRe->xNextChar(&in); - pThis = pNext; - pNext = &aStateSet[iSwap]; - iSwap = 1 - iSwap; - pNext->nState = 0; - for(i=0; inState; i++){ - int x = pThis->aState[i]; - switch( pRe->aOp[x] ){ - case RE_OP_MATCH: { - if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); - break; - } - case RE_OP_ANY: { - if( c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_WORD: { - if( re_word_char(c) ) re_add_state(pNext, x+1); - break; - } - case RE_OP_NOTWORD: { - if( !re_word_char(c) && c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_DIGIT: { - if( re_digit_char(c) ) re_add_state(pNext, x+1); - break; - } - case RE_OP_NOTDIGIT: { - if( !re_digit_char(c) && c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_SPACE: { - if( re_space_char(c) ) re_add_state(pNext, x+1); - break; - } - case RE_OP_NOTSPACE: { - if( !re_space_char(c) && c!=0 ) re_add_state(pNext, x+1); - break; - } - case RE_OP_BOUNDARY: { - if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1); - break; - } - case RE_OP_ANYSTAR: { - re_add_state(pNext, x); - re_add_state(pThis, x+1); - break; - } - case RE_OP_FORK: { - re_add_state(pThis, x+pRe->aArg[x]); - re_add_state(pThis, x+1); - break; - } - case RE_OP_GOTO: { - re_add_state(pThis, x+pRe->aArg[x]); - break; - } - case RE_OP_ACCEPT: { - rc = 1; - goto re_match_end; - } - case RE_OP_CC_EXC: { - if( c==0 ) break; - /* fall-through */ goto re_op_cc_inc; - } - case RE_OP_CC_INC: re_op_cc_inc: { - int j = 1; - int n = pRe->aArg[x]; - int hit = 0; - for(j=1; j>0 && jaOp[x+j]==RE_OP_CC_VALUE ){ - if( pRe->aArg[x+j]==c ){ - hit = 1; - j = -1; - } - }else{ - if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){ - hit = 1; - j = -1; - }else{ - j++; - } - } - } - if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; - if( hit ) re_add_state(pNext, x+n); - break; - } - } - } - } - for(i=0; inState; i++){ - if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } - } -re_match_end: - sqlite3_free(pToFree); - return rc; -} + } + for(i=0; inState; i++){ + if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } + } +re_match_end: + sqlite3_free(pToFree); + return rc; +} /* Resize the opcode and argument arrays for an RE under construction. */ static int re_resize(ReCompiled *p, int N){ - char *aOp; - int *aArg; - aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0])); - if( aOp==0 ) return 1; - p->aOp = aOp; - aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0])); - if( aArg==0 ) return 1; - p->aArg = aArg; - p->nAlloc = N; - return 0; + char *aOp; + int *aArg; + aOp = sqlite3_realloc64(p->aOp, N*sizeof(p->aOp[0])); + if( aOp==0 ) return 1; + p->aOp = aOp; + aArg = sqlite3_realloc64(p->aArg, N*sizeof(p->aArg[0])); + if( aArg==0 ) return 1; + p->aArg = aArg; + p->nAlloc = N; + return 0; } /* Insert a new opcode and argument into an RE under construction. The ** insertion point is just prior to existing opcode iBefore. */ static int re_insert(ReCompiled *p, int iBefore, int op, int arg){ - int i; - if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0; - for(i=p->nState; i>iBefore; i--){ - p->aOp[i] = p->aOp[i-1]; - p->aArg[i] = p->aArg[i-1]; - } - p->nState++; - p->aOp[iBefore] = (char)op; - p->aArg[iBefore] = arg; - return iBefore; + int i; + if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0; + for(i=p->nState; i>iBefore; i--){ + p->aOp[i] = p->aOp[i-1]; + p->aArg[i] = p->aArg[i-1]; + } + p->nState++; + p->aOp[iBefore] = (char)op; + p->aArg[iBefore] = arg; + return iBefore; } /* Append a new opcode and argument to the end of the RE under construction. */ static int re_append(ReCompiled *p, int op, int arg){ - return re_insert(p, p->nState, op, arg); + return re_insert(p, p->nState, op, arg); } /* Make a copy of N opcodes starting at iStart onto the end of the RE ** under construction. */ static void re_copy(ReCompiled *p, int iStart, int N){ - if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return; - memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0])); - memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0])); - p->nState += N; + if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return; + memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0])); + memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0])); + p->nState += N; } /* Return true if c is a hexadecimal digit character: [0-9a-fA-F] @@ -6351,57 +6351,57 @@ static void re_copy(ReCompiled *p, int iStart, int N){ ** c is not a hex digit *pV is unchanged. */ static int re_hex(int c, int *pV){ - if( c>='0' && c<='9' ){ - c -= '0'; - }else if( c>='a' && c<='f' ){ - c -= 'a' - 10; - }else if( c>='A' && c<='F' ){ - c -= 'A' - 10; - }else{ - return 0; - } - *pV = (*pV)*16 + (c & 0xff); - return 1; + if( c>='0' && c<='9' ){ + c -= '0'; + }else if( c>='a' && c<='f' ){ + c -= 'a' - 10; + }else if( c>='A' && c<='F' ){ + c -= 'A' - 10; + }else{ + return 0; + } + *pV = (*pV)*16 + (c & 0xff); + return 1; } /* A backslash character has been seen, read the next character and ** return its interpretation. */ static unsigned re_esc_char(ReCompiled *p){ - static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; - static const char zTrans[] = "\a\f\n\r\t\v"; - int i, v = 0; - char c; - if( p->sIn.i>=p->sIn.mx ) return 0; - c = p->sIn.z[p->sIn.i]; - if( c=='u' && p->sIn.i+4sIn.mx ){ - const unsigned char *zIn = p->sIn.z + p->sIn.i; - if( re_hex(zIn[1],&v) - && re_hex(zIn[2],&v) - && re_hex(zIn[3],&v) - && re_hex(zIn[4],&v) - ){ - p->sIn.i += 5; - return v; - } - } - if( c=='x' && p->sIn.i+2sIn.mx ){ - const unsigned char *zIn = p->sIn.z + p->sIn.i; - if( re_hex(zIn[1],&v) - && re_hex(zIn[2],&v) - ){ - p->sIn.i += 3; - return v; - } - } - for(i=0; zEsc[i] && zEsc[i]!=c; i++){} - if( zEsc[i] ){ - if( i<6 ) c = zTrans[i]; - p->sIn.i++; - }else{ - p->zErr = "unknown \\ escape"; + static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; + static const char zTrans[] = "\a\f\n\r\t\v"; + int i, v = 0; + char c; + if( p->sIn.i>=p->sIn.mx ) return 0; + c = p->sIn.z[p->sIn.i]; + if( c=='u' && p->sIn.i+4sIn.mx ){ + const unsigned char *zIn = p->sIn.z + p->sIn.i; + if( re_hex(zIn[1],&v) + && re_hex(zIn[2],&v) + && re_hex(zIn[3],&v) + && re_hex(zIn[4],&v) + ){ + p->sIn.i += 5; + return v; + } + } + if( c=='x' && p->sIn.i+2sIn.mx ){ + const unsigned char *zIn = p->sIn.z + p->sIn.i; + if( re_hex(zIn[1],&v) + && re_hex(zIn[2],&v) + ){ + p->sIn.i += 3; + return v; } - return c; + } + for(i=0; zEsc[i] && zEsc[i]!=c; i++){} + if( zEsc[i] ){ + if( i<6 ) c = zTrans[i]; + p->sIn.i++; + }else{ + p->zErr = "unknown \\ escape"; + } + return c; } /* Forward declaration */ @@ -6409,7 +6409,7 @@ static const char *re_subcompile_string(ReCompiled*); /* Peek at the next byte of input */ static unsigned char rePeek(ReCompiled *p){ - return p->sIn.isIn.mx ? p->sIn.z[p->sIn.i] : 0; + return p->sIn.isIn.mx ? p->sIn.z[p->sIn.i] : 0; } /* Compile RE text into a sequence of opcodes. Continue up to the @@ -6417,21 +6417,21 @@ static unsigned char rePeek(ReCompiled *p){ ** return a pointer to the error message string. */ static const char *re_subcompile_re(ReCompiled *p){ - const char *zErr; - int iStart, iEnd, iGoto; - iStart = p->nState; + const char *zErr; + int iStart, iEnd, iGoto; + iStart = p->nState; + zErr = re_subcompile_string(p); + if( zErr ) return zErr; + while( rePeek(p)=='|' ){ + iEnd = p->nState; + re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart); + iGoto = re_append(p, RE_OP_GOTO, 0); + p->sIn.i++; zErr = re_subcompile_string(p); if( zErr ) return zErr; - while( rePeek(p)=='|' ){ - iEnd = p->nState; - re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart); - iGoto = re_append(p, RE_OP_GOTO, 0); - p->sIn.i++; - zErr = re_subcompile_string(p); - if( zErr ) return zErr; - p->aArg[iGoto] = p->nState - iGoto; - } - return 0; + p->aArg[iGoto] = p->nState - iGoto; + } + return 0; } /* Compile an element of regular expression text (anything that can be @@ -6439,138 +6439,138 @@ static const char *re_subcompile_re(ReCompiled *p){ ** to the error message if there is a problem. */ static const char *re_subcompile_string(ReCompiled *p){ - int iPrev = -1; - int iStart; - unsigned c; - const char *zErr; - while( (c = p->xNextChar(&p->sIn))!=0 ){ - iStart = p->nState; - switch( c ){ - case '|': - case '$': - case ')': { - p->sIn.i--; - return 0; - } - case '(': { - zErr = re_subcompile_re(p); - if( zErr ) return zErr; - if( rePeek(p)!=')' ) return "unmatched '('"; - p->sIn.i++; - break; - } - case '.': { - if( rePeek(p)=='*' ){ - re_append(p, RE_OP_ANYSTAR, 0); - p->sIn.i++; - }else{ - re_append(p, RE_OP_ANY, 0); - } - break; - } - case '*': { - if( iPrev<0 ) return "'*' without operand"; - re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1); - re_append(p, RE_OP_FORK, iPrev - p->nState + 1); - break; - } - case '+': { - if( iPrev<0 ) return "'+' without operand"; - re_append(p, RE_OP_FORK, iPrev - p->nState); - break; - } - case '?': { - if( iPrev<0 ) return "'?' without operand"; - re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); - break; - } - case '{': { - int m = 0, n = 0; - int sz, j; - if( iPrev<0 ) return "'{m,n}' without operand"; - while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } - n = m; - if( c==',' ){ - p->sIn.i++; - n = 0; - while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } - } - if( c!='}' ) return "unmatched '{'"; - if( n>0 && nsIn.i++; - sz = p->nState - iPrev; - if( m==0 ){ - if( n==0 ) return "both m and n are zero in '{m,n}'"; - re_insert(p, iPrev, RE_OP_FORK, sz+1); - n--; - }else{ - for(j=1; j0 ){ - re_append(p, RE_OP_FORK, -sz); - } - break; - } - case '[': { - int iFirst = p->nState; - if( rePeek(p)=='^' ){ - re_append(p, RE_OP_CC_EXC, 0); - p->sIn.i++; - }else{ - re_append(p, RE_OP_CC_INC, 0); - } - while( (c = p->xNextChar(&p->sIn))!=0 ){ - if( c=='[' && rePeek(p)==':' ){ - return "POSIX character classes not supported"; - } - if( c=='\\' ) c = re_esc_char(p); - if( rePeek(p)=='-' ){ - re_append(p, RE_OP_CC_RANGE, c); - p->sIn.i++; - c = p->xNextChar(&p->sIn); - if( c=='\\' ) c = re_esc_char(p); - re_append(p, RE_OP_CC_RANGE, c); - }else{ - re_append(p, RE_OP_CC_VALUE, c); - } - if( rePeek(p)==']' ){ p->sIn.i++; break; } - } - if( c==0 ) return "unclosed '['"; - p->aArg[iFirst] = p->nState - iFirst; - break; - } - case '\\': { - int specialOp = 0; - switch( rePeek(p) ){ - case 'b': specialOp = RE_OP_BOUNDARY; break; - case 'd': specialOp = RE_OP_DIGIT; break; - case 'D': specialOp = RE_OP_NOTDIGIT; break; - case 's': specialOp = RE_OP_SPACE; break; - case 'S': specialOp = RE_OP_NOTSPACE; break; - case 'w': specialOp = RE_OP_WORD; break; - case 'W': specialOp = RE_OP_NOTWORD; break; - } - if( specialOp ){ - p->sIn.i++; - re_append(p, specialOp, 0); - }else{ - c = re_esc_char(p); - re_append(p, RE_OP_MATCH, c); - } - break; - } - default: { - re_append(p, RE_OP_MATCH, c); - break; - } + int iPrev = -1; + int iStart; + unsigned c; + const char *zErr; + while( (c = p->xNextChar(&p->sIn))!=0 ){ + iStart = p->nState; + switch( c ){ + case '|': + case '$': + case ')': { + p->sIn.i--; + return 0; + } + case '(': { + zErr = re_subcompile_re(p); + if( zErr ) return zErr; + if( rePeek(p)!=')' ) return "unmatched '('"; + p->sIn.i++; + break; + } + case '.': { + if( rePeek(p)=='*' ){ + re_append(p, RE_OP_ANYSTAR, 0); + p->sIn.i++; + }else{ + re_append(p, RE_OP_ANY, 0); + } + break; + } + case '*': { + if( iPrev<0 ) return "'*' without operand"; + re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1); + re_append(p, RE_OP_FORK, iPrev - p->nState + 1); + break; + } + case '+': { + if( iPrev<0 ) return "'+' without operand"; + re_append(p, RE_OP_FORK, iPrev - p->nState); + break; + } + case '?': { + if( iPrev<0 ) return "'?' without operand"; + re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); + break; + } + case '{': { + int m = 0, n = 0; + int sz, j; + if( iPrev<0 ) return "'{m,n}' without operand"; + while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } + n = m; + if( c==',' ){ + p->sIn.i++; + n = 0; + while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } + } + if( c!='}' ) return "unmatched '{'"; + if( n>0 && nsIn.i++; + sz = p->nState - iPrev; + if( m==0 ){ + if( n==0 ) return "both m and n are zero in '{m,n}'"; + re_insert(p, iPrev, RE_OP_FORK, sz+1); + n--; + }else{ + for(j=1; j0 ){ + re_append(p, RE_OP_FORK, -sz); + } + break; + } + case '[': { + int iFirst = p->nState; + if( rePeek(p)=='^' ){ + re_append(p, RE_OP_CC_EXC, 0); + p->sIn.i++; + }else{ + re_append(p, RE_OP_CC_INC, 0); + } + while( (c = p->xNextChar(&p->sIn))!=0 ){ + if( c=='[' && rePeek(p)==':' ){ + return "POSIX character classes not supported"; + } + if( c=='\\' ) c = re_esc_char(p); + if( rePeek(p)=='-' ){ + re_append(p, RE_OP_CC_RANGE, c); + p->sIn.i++; + c = p->xNextChar(&p->sIn); + if( c=='\\' ) c = re_esc_char(p); + re_append(p, RE_OP_CC_RANGE, c); + }else{ + re_append(p, RE_OP_CC_VALUE, c); + } + if( rePeek(p)==']' ){ p->sIn.i++; break; } + } + if( c==0 ) return "unclosed '['"; + p->aArg[iFirst] = p->nState - iFirst; + break; + } + case '\\': { + int specialOp = 0; + switch( rePeek(p) ){ + case 'b': specialOp = RE_OP_BOUNDARY; break; + case 'd': specialOp = RE_OP_DIGIT; break; + case 'D': specialOp = RE_OP_NOTDIGIT; break; + case 's': specialOp = RE_OP_SPACE; break; + case 'S': specialOp = RE_OP_NOTSPACE; break; + case 'w': specialOp = RE_OP_WORD; break; + case 'W': specialOp = RE_OP_NOTWORD; break; + } + if( specialOp ){ + p->sIn.i++; + re_append(p, specialOp, 0); + }else{ + c = re_esc_char(p); + re_append(p, RE_OP_MATCH, c); } - iPrev = iStart; + break; + } + default: { + re_append(p, RE_OP_MATCH, c); + break; + } } - return 0; + iPrev = iStart; + } + return 0; } /* Free and reclaim all the memory used by a previously compiled @@ -6578,11 +6578,11 @@ static const char *re_subcompile_string(ReCompiled *p){ ** for every call to re_compile() to avoid memory leaks. */ static void re_free(ReCompiled *pRe){ - if( pRe ){ - sqlite3_free(pRe->aOp); - sqlite3_free(pRe->aArg); - sqlite3_free(pRe); - } + if( pRe ){ + sqlite3_free(pRe->aOp); + sqlite3_free(pRe->aArg); + sqlite3_free(pRe); + } } /* @@ -6592,74 +6592,74 @@ static void re_free(ReCompiled *pRe){ ** error message if something goes wrong. */ static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){ - ReCompiled *pRe; - const char *zErr; - int i, j; - - *ppRe = 0; - pRe = sqlite3_malloc( sizeof(*pRe) ); - if( pRe==0 ){ - return "out of memory"; - } - memset(pRe, 0, sizeof(*pRe)); - pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char; - if( re_resize(pRe, 30) ){ - re_free(pRe); - return "out of memory"; - } - if( zIn[0]=='^' ){ - zIn++; - }else{ - re_append(pRe, RE_OP_ANYSTAR, 0); - } - pRe->sIn.z = (unsigned char*)zIn; - pRe->sIn.i = 0; - pRe->sIn.mx = (int)strlen(zIn); - zErr = re_subcompile_re(pRe); - if( zErr ){ - re_free(pRe); - return zErr; - } - if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ - re_append(pRe, RE_OP_MATCH, RE_EOF); - re_append(pRe, RE_OP_ACCEPT, 0); - *ppRe = pRe; - }else if( pRe->sIn.i>=pRe->sIn.mx ){ - re_append(pRe, RE_OP_ACCEPT, 0); - *ppRe = pRe; - }else{ - re_free(pRe); - return "unrecognized character"; - } - - /* The following is a performance optimization. If the regex begins with + ReCompiled *pRe; + const char *zErr; + int i, j; + + *ppRe = 0; + pRe = sqlite3_malloc( sizeof(*pRe) ); + if( pRe==0 ){ + return "out of memory"; + } + memset(pRe, 0, sizeof(*pRe)); + pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char; + if( re_resize(pRe, 30) ){ + re_free(pRe); + return "out of memory"; + } + if( zIn[0]=='^' ){ + zIn++; + }else{ + re_append(pRe, RE_OP_ANYSTAR, 0); + } + pRe->sIn.z = (unsigned char*)zIn; + pRe->sIn.i = 0; + pRe->sIn.mx = (int)strlen(zIn); + zErr = re_subcompile_re(pRe); + if( zErr ){ + re_free(pRe); + return zErr; + } + if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ + re_append(pRe, RE_OP_MATCH, RE_EOF); + re_append(pRe, RE_OP_ACCEPT, 0); + *ppRe = pRe; + }else if( pRe->sIn.i>=pRe->sIn.mx ){ + re_append(pRe, RE_OP_ACCEPT, 0); + *ppRe = pRe; + }else{ + re_free(pRe); + return "unrecognized character"; + } + + /* The following is a performance optimization. If the regex begins with ** ".*" (if the input regex lacks an initial "^") and afterwards there are ** one or more matching characters, enter those matching characters into - ** zInit[]. The re_match() routine can then search ahead in the input + ** zInit[]. The re_match() routine can then search ahead in the input ** string looking for the initial match without having to run the whole ** regex engine over the string. Do not worry able trying to match ** unicode characters beyond plane 0 - those are very rare and this is ** just an optimization. */ - if( pRe->aOp[0]==RE_OP_ANYSTAR && !noCase ){ - for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ - unsigned x = pRe->aArg[i]; - if( x<=127 ){ - pRe->zInit[j++] = (unsigned char)x; - }else if( x<=0xfff ){ - pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6)); - pRe->zInit[j++] = 0x80 | (x&0x3f); - }else if( x<=0xffff ){ - pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12)); - pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); - pRe->zInit[j++] = 0x80 | (x&0x3f); - }else{ - break; - } - } - if( j>0 && pRe->zInit[j-1]==0 ) j--; - pRe->nInit = j; - } - return pRe->zErr; + if( pRe->aOp[0]==RE_OP_ANYSTAR && !noCase ){ + for(j=0, i=1; j<(int)sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ + unsigned x = pRe->aArg[i]; + if( x<=127 ){ + pRe->zInit[j++] = (unsigned char)x; + }else if( x<=0xfff ){ + pRe->zInit[j++] = (unsigned char)(0xc0 | (x>>6)); + pRe->zInit[j++] = 0x80 | (x&0x3f); + }else if( x<=0xffff ){ + pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12)); + pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); + pRe->zInit[j++] = 0x80 | (x&0x3f); + }else{ + break; + } + } + if( j>0 && pRe->zInit[j-1]==0 ) j--; + pRe->nInit = j; + } + return pRe->zErr; } /* @@ -6672,40 +6672,40 @@ static const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){ ** is implemented as regexp(B,A). */ static void re_sql_func( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - ReCompiled *pRe; /* Compiled regular expression */ - const char *zPattern; /* The regular expression */ - const unsigned char *zStr;/* String being searched */ - const char *zErr; /* Compile error message */ - int setAux = 0; /* True to invoke sqlite3_set_auxdata() */ - - (void)argc; /* Unused */ - pRe = sqlite3_get_auxdata(context, 0); - if( pRe==0 ){ - zPattern = (const char*)sqlite3_value_text(argv[0]); - if( zPattern==0 ) return; - zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0); - if( zErr ){ - re_free(pRe); - sqlite3_result_error(context, zErr, -1); - return; - } - if( pRe==0 ){ - sqlite3_result_error_nomem(context); - return; - } - setAux = 1; - } - zStr = (const unsigned char*)sqlite3_value_text(argv[1]); - if( zStr!=0 ){ - sqlite3_result_int(context, re_match(pRe, zStr, -1)); + ReCompiled *pRe; /* Compiled regular expression */ + const char *zPattern; /* The regular expression */ + const unsigned char *zStr;/* String being searched */ + const char *zErr; /* Compile error message */ + int setAux = 0; /* True to invoke sqlite3_set_auxdata() */ + + (void)argc; /* Unused */ + pRe = sqlite3_get_auxdata(context, 0); + if( pRe==0 ){ + zPattern = (const char*)sqlite3_value_text(argv[0]); + if( zPattern==0 ) return; + zErr = re_compile(&pRe, zPattern, sqlite3_user_data(context)!=0); + if( zErr ){ + re_free(pRe); + sqlite3_result_error(context, zErr, -1); + return; } - if( setAux ){ - sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free); + if( pRe==0 ){ + sqlite3_result_error_nomem(context); + return; } + setAux = 1; + } + zStr = (const unsigned char*)sqlite3_value_text(argv[1]); + if( zStr!=0 ){ + sqlite3_result_int(context, re_match(pRe, zStr, -1)); + } + if( setAux ){ + sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free); + } } /* @@ -6716,22 +6716,22 @@ static void re_sql_func( #endif int sqlite3_regexp_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - int rc = SQLITE_OK; - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused */ - rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, - 0, re_sql_func, 0, 0); - if( rc==SQLITE_OK ){ - /* The regexpi(PATTERN,STRING) function is a case-insensitive version + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused */ + rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, + 0, re_sql_func, 0, 0); + if( rc==SQLITE_OK ){ + /* The regexpi(PATTERN,STRING) function is a case-insensitive version ** of regexp(PATTERN,STRING). */ - rc = sqlite3_create_function(db, "regexpi", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, - (void*)db, re_sql_func, 0, 0); - } - return rc; + rc = sqlite3_create_function(db, "regexpi", 2, SQLITE_UTF8|SQLITE_INNOCUOUS, + (void*)db, re_sql_func, 0, 0); + } + return rc; } /************************* End ../ext/misc/regexp.c ********************/ @@ -6814,10 +6814,10 @@ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ /* ** Definitions for mode bitmasks S_IFDIR, S_IFREG and S_IFLNK. ** -** In some ways it would be better to obtain these values from system +** In some ways it would be better to obtain these values from system ** header files. But, the dependency is undesirable and (a) these ** have been stable for decades, (b) the values are part of POSIX and -** are also made explicit in [man stat], and (c) are part of the +** are also made explicit in [man stat], and (c) are part of the ** file format for zip archives. */ #ifndef S_IFDIR @@ -6830,8 +6830,8 @@ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ # define S_IFLNK 0120000 #endif -static const char ZIPFILE_SCHEMA[] = - "CREATE TABLE y(" +static const char ZIPFILE_SCHEMA[] = + "CREATE TABLE y(" "name PRIMARY KEY," /* 0: Name of file in zip archive */ "mode," /* 1: POSIX mode for file */ "mtime," /* 2: Last modification time (secs since 1970)*/ @@ -6840,7 +6840,7 @@ static const char ZIPFILE_SCHEMA[] = "data," /* 5: Uncompressed data */ "method," /* 6: Compression method (integer) */ "z HIDDEN" /* 7: Name of zip file */ - ") WITHOUT ROWID;"; + ") WITHOUT ROWID;"; #define ZIPFILE_F_COLUMN_IDX 7 /* Index of column "file" in the above */ #define ZIPFILE_BUFFER_SIZE (64*1024) @@ -6851,8 +6851,8 @@ static const char ZIPFILE_SCHEMA[] = ** ** ZIPFILE_NEWENTRY_MADEBY: ** Use this value for the "version-made-by" field in new zip file -** entries. The upper byte indicates "unix", and the lower byte -** indicates that the zip file matches pkzip specification 3.0. +** entries. The upper byte indicates "unix", and the lower byte +** indicates that the zip file matches pkzip specification 3.0. ** This is what info-zip seems to do. ** ** ZIPFILE_NEWENTRY_REQUIRED: @@ -6881,7 +6881,7 @@ static const char ZIPFILE_SCHEMA[] = #define ZIPFILE_SIGNATURE_EOCD 0x06054b50 /* -** The sizes of the fixed-size part of each of the three main data +** The sizes of the fixed-size part of each of the three main data ** structures in a zip archive. */ #define ZIPFILE_LFH_FIXED_SZ 30 @@ -6908,12 +6908,12 @@ static const char ZIPFILE_SCHEMA[] = */ typedef struct ZipfileEOCD ZipfileEOCD; struct ZipfileEOCD { - u16 iDisk; - u16 iFirstDisk; - u16 nEntry; - u16 nEntryTotal; - u32 nSize; - u32 iOffset; + u16 iDisk; + u16 iFirstDisk; + u16 nEntry; + u16 nEntryTotal; + u32 nSize; + u32 iOffset; }; /* @@ -6941,23 +6941,23 @@ struct ZipfileEOCD { */ typedef struct ZipfileCDS ZipfileCDS; struct ZipfileCDS { - u16 iVersionMadeBy; - u16 iVersionExtract; - u16 flags; - u16 iCompression; - u16 mTime; - u16 mDate; - u32 crc32; - u32 szCompressed; - u32 szUncompressed; - u16 nFile; - u16 nExtra; - u16 nComment; - u16 iDiskStart; - u16 iInternalAttr; - u32 iExternalAttr; - u32 iOffset; - char *zFile; /* Filename (sqlite3_malloc()) */ + u16 iVersionMadeBy; + u16 iVersionExtract; + u16 flags; + u16 iCompression; + u16 mTime; + u16 mDate; + u32 crc32; + u32 szCompressed; + u32 szUncompressed; + u16 nFile; + u16 nExtra; + u16 nComment; + u16 iDiskStart; + u16 iInternalAttr; + u32 iExternalAttr; + u32 iOffset; + char *zFile; /* Filename (sqlite3_malloc()) */ }; /* @@ -6974,68 +6974,68 @@ struct ZipfileCDS { *** uncompressed size 4 bytes *** file name length 2 bytes *** extra field length 2 bytes -*** +*** */ typedef struct ZipfileLFH ZipfileLFH; struct ZipfileLFH { - u16 iVersionExtract; - u16 flags; - u16 iCompression; - u16 mTime; - u16 mDate; - u32 crc32; - u32 szCompressed; - u32 szUncompressed; - u16 nFile; - u16 nExtra; + u16 iVersionExtract; + u16 flags; + u16 iCompression; + u16 mTime; + u16 mDate; + u32 crc32; + u32 szCompressed; + u32 szUncompressed; + u16 nFile; + u16 nExtra; }; typedef struct ZipfileEntry ZipfileEntry; struct ZipfileEntry { - ZipfileCDS cds; /* Parsed CDS record */ - u32 mUnixTime; /* Modification time, in UNIX format */ - u8 *aExtra; /* cds.nExtra+cds.nComment bytes of extra data */ - i64 iDataOff; /* Offset to data in file (if aData==0) */ - u8 *aData; /* cds.szCompressed bytes of compressed data */ - ZipfileEntry *pNext; /* Next element in in-memory CDS */ + ZipfileCDS cds; /* Parsed CDS record */ + u32 mUnixTime; /* Modification time, in UNIX format */ + u8 *aExtra; /* cds.nExtra+cds.nComment bytes of extra data */ + i64 iDataOff; /* Offset to data in file (if aData==0) */ + u8 *aData; /* cds.szCompressed bytes of compressed data */ + ZipfileEntry *pNext; /* Next element in in-memory CDS */ }; -/* +/* ** Cursor type for zipfile tables. */ typedef struct ZipfileCsr ZipfileCsr; struct ZipfileCsr { - sqlite3_vtab_cursor base; /* Base class - must be first */ - i64 iId; /* Cursor ID */ - u8 bEof; /* True when at EOF */ - u8 bNoop; /* If next xNext() call is no-op */ - - /* Used outside of write transactions */ - FILE *pFile; /* Zip file */ - i64 iNextOff; /* Offset of next record in central directory */ - ZipfileEOCD eocd; /* Parse of central directory record */ - - ZipfileEntry *pFreeEntry; /* Free this list when cursor is closed or reset */ - ZipfileEntry *pCurrent; /* Current entry */ - ZipfileCsr *pCsrNext; /* Next cursor on same virtual table */ + sqlite3_vtab_cursor base; /* Base class - must be first */ + i64 iId; /* Cursor ID */ + u8 bEof; /* True when at EOF */ + u8 bNoop; /* If next xNext() call is no-op */ + + /* Used outside of write transactions */ + FILE *pFile; /* Zip file */ + i64 iNextOff; /* Offset of next record in central directory */ + ZipfileEOCD eocd; /* Parse of central directory record */ + + ZipfileEntry *pFreeEntry; /* Free this list when cursor is closed or reset */ + ZipfileEntry *pCurrent; /* Current entry */ + ZipfileCsr *pCsrNext; /* Next cursor on same virtual table */ }; typedef struct ZipfileTab ZipfileTab; struct ZipfileTab { - sqlite3_vtab base; /* Base class - must be first */ - char *zFile; /* Zip file this table accesses (may be NULL) */ - sqlite3 *db; /* Host database connection */ - u8 *aBuffer; /* Temporary buffer used for various tasks */ - - ZipfileCsr *pCsrList; /* List of cursors */ - i64 iNextCsrid; - - /* The following are used by write transactions only */ - ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */ - ZipfileEntry *pLastEntry; /* Last element in pFirstEntry list */ - FILE *pWriteFd; /* File handle open on zip archive */ - i64 szCurrent; /* Current size of zip archive */ - i64 szOrig; /* Size of archive at start of transaction */ + sqlite3_vtab base; /* Base class - must be first */ + char *zFile; /* Zip file this table accesses (may be NULL) */ + sqlite3 *db; /* Host database connection */ + u8 *aBuffer; /* Temporary buffer used for various tasks */ + + ZipfileCsr *pCsrList; /* List of cursors */ + i64 iNextCsrid; + + /* The following are used by write transactions only */ + ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */ + ZipfileEntry *pLastEntry; /* Last element in pFirstEntry list */ + FILE *pWriteFd; /* File handle open on zip archive */ + i64 szCurrent; /* Current size of zip archive */ + i64 szOrig; /* Size of archive at start of transaction */ }; /* @@ -7043,13 +7043,13 @@ struct ZipfileTab { ** vprintf(zFmt, ...). */ static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){ - char *zMsg = 0; - va_list ap; - va_start(ap, zFmt); - zMsg = sqlite3_vmprintf(zFmt, ap); - sqlite3_result_error(ctx, zMsg, -1); - sqlite3_free(zMsg); - va_end(ap); + char *zMsg = 0; + va_list ap; + va_start(ap, zFmt); + zMsg = sqlite3_vmprintf(zFmt, ap); + sqlite3_result_error(ctx, zMsg, -1); + sqlite3_free(zMsg); + va_end(ap); } /* @@ -7057,42 +7057,42 @@ static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){ ** is not quoted, do nothing. */ static void zipfileDequote(char *zIn){ - char q = zIn[0]; - if( q=='"' || q=='\'' || q=='`' || q=='[' ){ - int iIn = 1; - int iOut = 0; - if( q=='[' ) q = ']'; - while( ALWAYS(zIn[iIn]) ){ - char c = zIn[iIn++]; - if( c==q && zIn[iIn++]!=q ) break; - zIn[iOut++] = c; - } - zIn[iOut] = '\0'; + char q = zIn[0]; + if( q=='"' || q=='\'' || q=='`' || q=='[' ){ + int iIn = 1; + int iOut = 0; + if( q=='[' ) q = ']'; + while( ALWAYS(zIn[iIn]) ){ + char c = zIn[iIn++]; + if( c==q && zIn[iIn++]!=q ) break; + zIn[iOut++] = c; } + zIn[iOut] = '\0'; + } } /* ** Construct a new ZipfileTab virtual table object. -** +** ** argv[0] -> module name ("zipfile") ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> "column name" and other module argument fields. */ static int zipfileConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr ){ - int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; - int nFile = 0; - const char *zFile = 0; - ZipfileTab *pNew = 0; - int rc; + int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; + int nFile = 0; + const char *zFile = 0; + ZipfileTab *pNew = 0; + int rc; - /* If the table name is not "zipfile", require that the argument be + /* If the table name is not "zipfile", require that the argument be ** specified. This stops zipfile tables from being created as: ** ** CREATE VIRTUAL TABLE zzz USING zipfile(); @@ -7101,92 +7101,92 @@ static int zipfileConnect( ** ** CREATE VIRTUAL TABLE zipfile USING zipfile(); */ - assert( 0==sqlite3_stricmp(argv[0], "zipfile") ); - if( (0!=sqlite3_stricmp(argv[2], "zipfile") && argc<4) || argc>4 ){ - *pzErr = sqlite3_mprintf("zipfile constructor requires one argument"); - return SQLITE_ERROR; - } + assert( 0==sqlite3_stricmp(argv[0], "zipfile") ); + if( (0!=sqlite3_stricmp(argv[2], "zipfile") && argc<4) || argc>4 ){ + *pzErr = sqlite3_mprintf("zipfile constructor requires one argument"); + return SQLITE_ERROR; + } - if( argc>3 ){ - zFile = argv[3]; - nFile = (int)strlen(zFile)+1; - } + if( argc>3 ){ + zFile = argv[3]; + nFile = (int)strlen(zFile)+1; + } - rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA); - if( rc==SQLITE_OK ){ - pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile); - if( pNew==0 ) return SQLITE_NOMEM; - memset(pNew, 0, nByte+nFile); - pNew->db = db; - pNew->aBuffer = (u8*)&pNew[1]; - if( zFile ){ - pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE]; - memcpy(pNew->zFile, zFile, nFile); - zipfileDequote(pNew->zFile); - } + rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA); + if( rc==SQLITE_OK ){ + pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile); + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, nByte+nFile); + pNew->db = db; + pNew->aBuffer = (u8*)&pNew[1]; + if( zFile ){ + pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE]; + memcpy(pNew->zFile, zFile, nFile); + zipfileDequote(pNew->zFile); } - sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); - *ppVtab = (sqlite3_vtab*)pNew; - return rc; + } + sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY); + *ppVtab = (sqlite3_vtab*)pNew; + return rc; } /* ** Free the ZipfileEntry structure indicated by the only argument. */ static void zipfileEntryFree(ZipfileEntry *p){ - if( p ){ - sqlite3_free(p->cds.zFile); - sqlite3_free(p); - } + if( p ){ + sqlite3_free(p->cds.zFile); + sqlite3_free(p); + } } /* -** Release resources that should be freed at the end of a write +** Release resources that should be freed at the end of a write ** transaction. */ static void zipfileCleanupTransaction(ZipfileTab *pTab){ - ZipfileEntry *pEntry; - ZipfileEntry *pNext; + ZipfileEntry *pEntry; + ZipfileEntry *pNext; - if( pTab->pWriteFd ){ - fclose(pTab->pWriteFd); - pTab->pWriteFd = 0; - } - for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){ - pNext = pEntry->pNext; - zipfileEntryFree(pEntry); - } - pTab->pFirstEntry = 0; - pTab->pLastEntry = 0; - pTab->szCurrent = 0; - pTab->szOrig = 0; + if( pTab->pWriteFd ){ + fclose(pTab->pWriteFd); + pTab->pWriteFd = 0; + } + for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){ + pNext = pEntry->pNext; + zipfileEntryFree(pEntry); + } + pTab->pFirstEntry = 0; + pTab->pLastEntry = 0; + pTab->szCurrent = 0; + pTab->szOrig = 0; } /* ** This method is the destructor for zipfile vtab objects. */ static int zipfileDisconnect(sqlite3_vtab *pVtab){ - zipfileCleanupTransaction((ZipfileTab*)pVtab); - sqlite3_free(pVtab); - return SQLITE_OK; + zipfileCleanupTransaction((ZipfileTab*)pVtab); + sqlite3_free(pVtab); + return SQLITE_OK; } /* ** Constructor for a new ZipfileCsr object. */ static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){ - ZipfileTab *pTab = (ZipfileTab*)p; - ZipfileCsr *pCsr; - pCsr = sqlite3_malloc(sizeof(*pCsr)); - *ppCsr = (sqlite3_vtab_cursor*)pCsr; - if( pCsr==0 ){ - return SQLITE_NOMEM; - } - memset(pCsr, 0, sizeof(*pCsr)); - pCsr->iId = ++pTab->iNextCsrid; - pCsr->pCsrNext = pTab->pCsrList; - pTab->pCsrList = pCsr; - return SQLITE_OK; + ZipfileTab *pTab = (ZipfileTab*)p; + ZipfileCsr *pCsr; + pCsr = sqlite3_malloc(sizeof(*pCsr)); + *ppCsr = (sqlite3_vtab_cursor*)pCsr; + if( pCsr==0 ){ + return SQLITE_NOMEM; + } + memset(pCsr, 0, sizeof(*pCsr)); + pCsr->iId = ++pTab->iNextCsrid; + pCsr->pCsrNext = pTab->pCsrList; + pTab->pCsrList = pCsr; + return SQLITE_OK; } /* @@ -7194,38 +7194,38 @@ static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){ ** by zipfileOpen(). */ static void zipfileResetCursor(ZipfileCsr *pCsr){ - ZipfileEntry *p; - ZipfileEntry *pNext; + ZipfileEntry *p; + ZipfileEntry *pNext; - pCsr->bEof = 0; - if( pCsr->pFile ){ - fclose(pCsr->pFile); - pCsr->pFile = 0; - zipfileEntryFree(pCsr->pCurrent); - pCsr->pCurrent = 0; - } + pCsr->bEof = 0; + if( pCsr->pFile ){ + fclose(pCsr->pFile); + pCsr->pFile = 0; + zipfileEntryFree(pCsr->pCurrent); + pCsr->pCurrent = 0; + } - for(p=pCsr->pFreeEntry; p; p=pNext){ - pNext = p->pNext; - zipfileEntryFree(p); - } + for(p=pCsr->pFreeEntry; p; p=pNext){ + pNext = p->pNext; + zipfileEntryFree(p); + } } /* ** Destructor for an ZipfileCsr. */ static int zipfileClose(sqlite3_vtab_cursor *cur){ - ZipfileCsr *pCsr = (ZipfileCsr*)cur; - ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab); - ZipfileCsr **pp; - zipfileResetCursor(pCsr); + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab); + ZipfileCsr **pp; + zipfileResetCursor(pCsr); - /* Remove this cursor from the ZipfileTab.pCsrList list. */ - for(pp=&pTab->pCsrList; *pp!=pCsr; pp=&((*pp)->pCsrNext)); - *pp = pCsr->pCsrNext; + /* Remove this cursor from the ZipfileTab.pCsrList list. */ + for(pp=&pTab->pCsrList; *pp!=pCsr; pp=&((*pp)->pCsrNext)); + *pp = pCsr->pCsrNext; - sqlite3_free(pCsr); - return SQLITE_OK; + sqlite3_free(pCsr); + return SQLITE_OK; } /* @@ -7233,24 +7233,24 @@ static int zipfileClose(sqlite3_vtab_cursor *cur){ ** pCsr to the results of vprintf(zFmt, ...). */ static void zipfileTableErr(ZipfileTab *pTab, const char *zFmt, ...){ - va_list ap; - va_start(ap, zFmt); - sqlite3_free(pTab->base.zErrMsg); - pTab->base.zErrMsg = sqlite3_vmprintf(zFmt, ap); - va_end(ap); + va_list ap; + va_start(ap, zFmt); + sqlite3_free(pTab->base.zErrMsg); + pTab->base.zErrMsg = sqlite3_vmprintf(zFmt, ap); + va_end(ap); } static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){ - va_list ap; - va_start(ap, zFmt); - sqlite3_free(pCsr->base.pVtab->zErrMsg); - pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap); - va_end(ap); + va_list ap; + va_start(ap, zFmt); + sqlite3_free(pCsr->base.pVtab->zErrMsg); + pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap); + va_end(ap); } /* ** Read nRead bytes of data from offset iOff of file pFile into buffer ** aRead[]. Return SQLITE_OK if successful, or an SQLite error code -** otherwise. +** otherwise. ** ** If an error does occur, output variable (*pzErrmsg) may be set to point ** to an English language error message. It is the responsibility of the @@ -7258,74 +7258,74 @@ static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){ ** sqlite3_free(). */ static int zipfileReadData( - FILE *pFile, /* Read from this file */ - u8 *aRead, /* Read into this buffer */ - int nRead, /* Number of bytes to read */ - i64 iOff, /* Offset to read from */ - char **pzErrmsg /* OUT: Error message (from sqlite3_malloc) */ + FILE *pFile, /* Read from this file */ + u8 *aRead, /* Read into this buffer */ + int nRead, /* Number of bytes to read */ + i64 iOff, /* Offset to read from */ + char **pzErrmsg /* OUT: Error message (from sqlite3_malloc) */ ){ - size_t n; - fseek(pFile, (long)iOff, SEEK_SET); - n = fread(aRead, 1, nRead, pFile); - if( (int)n!=nRead ){ - *pzErrmsg = sqlite3_mprintf("error in fread()"); - return SQLITE_ERROR; - } - return SQLITE_OK; + size_t n; + fseek(pFile, (long)iOff, SEEK_SET); + n = fread(aRead, 1, nRead, pFile); + if( (int)n!=nRead ){ + *pzErrmsg = sqlite3_mprintf("error in fread()"); + return SQLITE_ERROR; + } + return SQLITE_OK; } static int zipfileAppendData( - ZipfileTab *pTab, - const u8 *aWrite, - int nWrite + ZipfileTab *pTab, + const u8 *aWrite, + int nWrite ){ - if( nWrite>0 ){ - size_t n = nWrite; - fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET); - n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd); - if( (int)n!=nWrite ){ - pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()"); - return SQLITE_ERROR; - } - pTab->szCurrent += nWrite; + if( nWrite>0 ){ + size_t n = nWrite; + fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET); + n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd); + if( (int)n!=nWrite ){ + pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()"); + return SQLITE_ERROR; } - return SQLITE_OK; + pTab->szCurrent += nWrite; + } + return SQLITE_OK; } /* ** Read and return a 16-bit little-endian unsigned integer from buffer aBuf. */ static u16 zipfileGetU16(const u8 *aBuf){ - return (aBuf[1] << 8) + aBuf[0]; + return (aBuf[1] << 8) + aBuf[0]; } /* ** Read and return a 32-bit little-endian unsigned integer from buffer aBuf. */ static u32 zipfileGetU32(const u8 *aBuf){ - if( aBuf==0 ) return 0; - return ((u32)(aBuf[3]) << 24) - + ((u32)(aBuf[2]) << 16) - + ((u32)(aBuf[1]) << 8) - + ((u32)(aBuf[0]) << 0); + if( aBuf==0 ) return 0; + return ((u32)(aBuf[3]) << 24) + + ((u32)(aBuf[2]) << 16) + + ((u32)(aBuf[1]) << 8) + + ((u32)(aBuf[0]) << 0); } /* ** Write a 16-bit little endiate integer into buffer aBuf. */ static void zipfilePutU16(u8 *aBuf, u16 val){ - aBuf[0] = val & 0xFF; - aBuf[1] = (val>>8) & 0xFF; + aBuf[0] = val & 0xFF; + aBuf[1] = (val>>8) & 0xFF; } /* ** Write a 32-bit little endiate integer into buffer aBuf. */ static void zipfilePutU32(u8 *aBuf, u32 val){ - aBuf[0] = val & 0xFF; - aBuf[1] = (val>>8) & 0xFF; - aBuf[2] = (val>>16) & 0xFF; - aBuf[3] = (val>>24) & 0xFF; + aBuf[0] = val & 0xFF; + aBuf[1] = (val>>8) & 0xFF; + aBuf[2] = (val>>16) & 0xFF; + aBuf[3] = (val>>24) & 0xFF; } #define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) ) @@ -7345,33 +7345,33 @@ static void zipfilePutU32(u8 *aBuf, u32 val){ ** if the record is not well-formed, or SQLITE_OK otherwise. */ static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){ - u8 *aRead = aBuf; - u32 sig = zipfileRead32(aRead); - int rc = SQLITE_OK; - if( sig!=ZIPFILE_SIGNATURE_CDS ){ - rc = SQLITE_ERROR; - }else{ - pCDS->iVersionMadeBy = zipfileRead16(aRead); - pCDS->iVersionExtract = zipfileRead16(aRead); - pCDS->flags = zipfileRead16(aRead); - pCDS->iCompression = zipfileRead16(aRead); - pCDS->mTime = zipfileRead16(aRead); - pCDS->mDate = zipfileRead16(aRead); - pCDS->crc32 = zipfileRead32(aRead); - pCDS->szCompressed = zipfileRead32(aRead); - pCDS->szUncompressed = zipfileRead32(aRead); - assert( aRead==&aBuf[ZIPFILE_CDS_NFILE_OFF] ); - pCDS->nFile = zipfileRead16(aRead); - pCDS->nExtra = zipfileRead16(aRead); - pCDS->nComment = zipfileRead16(aRead); - pCDS->iDiskStart = zipfileRead16(aRead); - pCDS->iInternalAttr = zipfileRead16(aRead); - pCDS->iExternalAttr = zipfileRead32(aRead); - pCDS->iOffset = zipfileRead32(aRead); - assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] ); - } - - return rc; + u8 *aRead = aBuf; + u32 sig = zipfileRead32(aRead); + int rc = SQLITE_OK; + if( sig!=ZIPFILE_SIGNATURE_CDS ){ + rc = SQLITE_ERROR; + }else{ + pCDS->iVersionMadeBy = zipfileRead16(aRead); + pCDS->iVersionExtract = zipfileRead16(aRead); + pCDS->flags = zipfileRead16(aRead); + pCDS->iCompression = zipfileRead16(aRead); + pCDS->mTime = zipfileRead16(aRead); + pCDS->mDate = zipfileRead16(aRead); + pCDS->crc32 = zipfileRead32(aRead); + pCDS->szCompressed = zipfileRead32(aRead); + pCDS->szUncompressed = zipfileRead32(aRead); + assert( aRead==&aBuf[ZIPFILE_CDS_NFILE_OFF] ); + pCDS->nFile = zipfileRead16(aRead); + pCDS->nExtra = zipfileRead16(aRead); + pCDS->nComment = zipfileRead16(aRead); + pCDS->iDiskStart = zipfileRead16(aRead); + pCDS->iInternalAttr = zipfileRead16(aRead); + pCDS->iExternalAttr = zipfileRead32(aRead); + pCDS->iOffset = zipfileRead32(aRead); + assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] ); + } + + return rc; } /* @@ -7379,28 +7379,28 @@ static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){ ** if the record is not well-formed, or SQLITE_OK otherwise. */ static int zipfileReadLFH( - u8 *aBuffer, - ZipfileLFH *pLFH + u8 *aBuffer, + ZipfileLFH *pLFH ){ - u8 *aRead = aBuffer; - int rc = SQLITE_OK; + u8 *aRead = aBuffer; + int rc = SQLITE_OK; - u32 sig = zipfileRead32(aRead); - if( sig!=ZIPFILE_SIGNATURE_LFH ){ - rc = SQLITE_ERROR; - }else{ - pLFH->iVersionExtract = zipfileRead16(aRead); - pLFH->flags = zipfileRead16(aRead); - pLFH->iCompression = zipfileRead16(aRead); - pLFH->mTime = zipfileRead16(aRead); - pLFH->mDate = zipfileRead16(aRead); - pLFH->crc32 = zipfileRead32(aRead); - pLFH->szCompressed = zipfileRead32(aRead); - pLFH->szUncompressed = zipfileRead32(aRead); - pLFH->nFile = zipfileRead16(aRead); - pLFH->nExtra = zipfileRead16(aRead); - } - return rc; + u32 sig = zipfileRead32(aRead); + if( sig!=ZIPFILE_SIGNATURE_LFH ){ + rc = SQLITE_ERROR; + }else{ + pLFH->iVersionExtract = zipfileRead16(aRead); + pLFH->flags = zipfileRead16(aRead); + pLFH->iCompression = zipfileRead16(aRead); + pLFH->mTime = zipfileRead16(aRead); + pLFH->mDate = zipfileRead16(aRead); + pLFH->crc32 = zipfileRead32(aRead); + pLFH->szCompressed = zipfileRead32(aRead); + pLFH->szUncompressed = zipfileRead32(aRead); + pLFH->nFile = zipfileRead16(aRead); + pLFH->nExtra = zipfileRead16(aRead); + } + return rc; } @@ -7420,28 +7420,28 @@ static int zipfileReadLFH( ** Data N bytes */ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){ - int ret = 0; - u8 *p = aExtra; - u8 *pEnd = &aExtra[nExtra]; - - while( p modtime is present */ - *pmTime = zipfileGetU32(&p[1]); - ret = 1; - } - break; - } - } + int ret = 0; + u8 *p = aExtra; + u8 *pEnd = &aExtra[nExtra]; + + while( p modtime is present */ + *pmTime = zipfileGetU32(&p[1]); + ret = 1; + } + break; + } } - return ret; + + p += nByte; + } + return ret; } /* @@ -7458,29 +7458,29 @@ static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){ ** File modification date: ** Bits 00-04: day ** Bits 05-08: month (1-12) -** Bits 09-15: years from 1980 +** Bits 09-15: years from 1980 ** ** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx */ static u32 zipfileMtime(ZipfileCDS *pCDS){ - int Y,M,D,X1,X2,A,B,sec,min,hr; - i64 JDsec; - Y = (1980 + ((pCDS->mDate >> 9) & 0x7F)); - M = ((pCDS->mDate >> 5) & 0x0F); - D = (pCDS->mDate & 0x1F); - sec = (pCDS->mTime & 0x1F)*2; - min = (pCDS->mTime >> 5) & 0x3F; - hr = (pCDS->mTime >> 11) & 0x1F; - if( M<=2 ){ - Y--; - M += 12; - } - X1 = 36525*(Y+4716)/100; - X2 = 306001*(M+1)/10000; - A = Y/100; - B = 2 - A + (A/4); - JDsec = (i64)((X1 + X2 + D + B - 1524.5)*86400) + hr*3600 + min*60 + sec; - return (u32)(JDsec - (i64)24405875*(i64)8640); + int Y,M,D,X1,X2,A,B,sec,min,hr; + i64 JDsec; + Y = (1980 + ((pCDS->mDate >> 9) & 0x7F)); + M = ((pCDS->mDate >> 5) & 0x0F); + D = (pCDS->mDate & 0x1F); + sec = (pCDS->mTime & 0x1F)*2; + min = (pCDS->mTime >> 5) & 0x3F; + hr = (pCDS->mTime >> 11) & 0x1F; + if( M<=2 ){ + Y--; + M += 12; + } + X1 = 36525*(Y+4716)/100; + X2 = 306001*(M+1)/10000; + A = Y/100; + B = 2 - A + (A/4); + JDsec = (i64)((X1 + X2 + D + B - 1524.5)*86400) + hr*3600 + min*60 + sec; + return (u32)(JDsec - (i64)24405875*(i64)8640); } /* @@ -7489,40 +7489,40 @@ static u32 zipfileMtime(ZipfileCDS *pCDS){ ** to the UNIX timestamp value passed as the second. */ static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){ - /* Convert unix timestamp to JD (2440588 is noon on 1/1/1970) */ - i64 JD = (i64)2440588 + mUnixTime / (24*60*60); - - int A, B, C, D, E; - int yr, mon, day; - int hr, min, sec; - - A = (int)((JD - 1867216.25)/36524.25); - A = (int)(JD + 1 + A - (A/4)); - B = A + 1524; - C = (int)((B - 122.1)/365.25); - D = (36525*(C&32767))/100; - E = (int)((B-D)/30.6001); - - day = B - D - (int)(30.6001*E); - mon = (E<14 ? E-1 : E-13); - yr = mon>2 ? C-4716 : C-4715; - - hr = (mUnixTime % (24*60*60)) / (60*60); - min = (mUnixTime % (60*60)) / 60; - sec = (mUnixTime % 60); - - if( yr>=1980 ){ - pCds->mDate = (u16)(day + (mon << 5) + ((yr-1980) << 9)); - pCds->mTime = (u16)(sec/2 + (min<<5) + (hr<<11)); - }else{ - pCds->mDate = pCds->mTime = 0; - } + /* Convert unix timestamp to JD (2440588 is noon on 1/1/1970) */ + i64 JD = (i64)2440588 + mUnixTime / (24*60*60); - assert( mUnixTime<315507600 - || mUnixTime==zipfileMtime(pCds) - || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds)) - /* || (mUnixTime % 2) */ - ); + int A, B, C, D, E; + int yr, mon, day; + int hr, min, sec; + + A = (int)((JD - 1867216.25)/36524.25); + A = (int)(JD + 1 + A - (A/4)); + B = A + 1524; + C = (int)((B - 122.1)/365.25); + D = (36525*(C&32767))/100; + E = (int)((B-D)/30.6001); + + day = B - D - (int)(30.6001*E); + mon = (E<14 ? E-1 : E-13); + yr = mon>2 ? C-4716 : C-4715; + + hr = (mUnixTime % (24*60*60)) / (60*60); + min = (mUnixTime % (60*60)) / 60; + sec = (mUnixTime % 60); + + if( yr>=1980 ){ + pCds->mDate = (u16)(day + (mon << 5) + ((yr-1980) << 9)); + pCds->mTime = (u16)(sec/2 + (min<<5) + (hr<<11)); + }else{ + pCds->mDate = pCds->mTime = 0; + } + + assert( mUnixTime<315507600 + || mUnixTime==zipfileMtime(pCds) + || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds)) + /* || (mUnixTime % 2) */ + ); } /* @@ -7537,138 +7537,138 @@ static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){ ** final value of (*ppEntry) undefined. */ static int zipfileGetEntry( - ZipfileTab *pTab, /* Store any error message here */ - const u8 *aBlob, /* Pointer to in-memory file image */ - int nBlob, /* Size of aBlob[] in bytes */ - FILE *pFile, /* If aBlob==0, read from this file */ - i64 iOff, /* Offset of CDS record */ - ZipfileEntry **ppEntry /* OUT: Pointer to new object */ + ZipfileTab *pTab, /* Store any error message here */ + const u8 *aBlob, /* Pointer to in-memory file image */ + int nBlob, /* Size of aBlob[] in bytes */ + FILE *pFile, /* If aBlob==0, read from this file */ + i64 iOff, /* Offset of CDS record */ + ZipfileEntry **ppEntry /* OUT: Pointer to new object */ ){ - u8 *aRead; - char **pzErr = &pTab->base.zErrMsg; - int rc = SQLITE_OK; + u8 *aRead; + char **pzErr = &pTab->base.zErrMsg; + int rc = SQLITE_OK; + + if( aBlob==0 ){ + aRead = pTab->aBuffer; + rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); + }else{ + aRead = (u8*)&aBlob[iOff]; + } + + if( rc==SQLITE_OK ){ + sqlite3_int64 nAlloc; + ZipfileEntry *pNew; + + int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]); + int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]); + nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]); + + nAlloc = sizeof(ZipfileEntry) + nExtra; + if( aBlob ){ + nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]); + } - if( aBlob==0 ){ - aRead = pTab->aBuffer; - rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); + pNew = (ZipfileEntry*)sqlite3_malloc64(nAlloc); + if( pNew==0 ){ + rc = SQLITE_NOMEM; }else{ - aRead = (u8*)&aBlob[iOff]; + memset(pNew, 0, sizeof(ZipfileEntry)); + rc = zipfileReadCDS(aRead, &pNew->cds); + if( rc!=SQLITE_OK ){ + *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff); + }else if( aBlob==0 ){ + rc = zipfileReadData( + pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr + ); + }else{ + aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ]; + } } if( rc==SQLITE_OK ){ - sqlite3_int64 nAlloc; - ZipfileEntry *pNew; - - int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]); - int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]); - nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]); - - nAlloc = sizeof(ZipfileEntry) + nExtra; - if( aBlob ){ - nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]); - } - - pNew = (ZipfileEntry*)sqlite3_malloc64(nAlloc); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(pNew, 0, sizeof(ZipfileEntry)); - rc = zipfileReadCDS(aRead, &pNew->cds); - if( rc!=SQLITE_OK ){ - *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff); - }else if( aBlob==0 ){ - rc = zipfileReadData( - pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr - ); - }else{ - aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ]; - } - } - - if( rc==SQLITE_OK ){ - u32 *pt = &pNew->mUnixTime; - pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); - pNew->aExtra = (u8*)&pNew[1]; - memcpy(pNew->aExtra, &aRead[nFile], nExtra); - if( pNew->cds.zFile==0 ){ - rc = SQLITE_NOMEM; - }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ - pNew->mUnixTime = zipfileMtime(&pNew->cds); - } - } - - if( rc==SQLITE_OK ){ - static const int szFix = ZIPFILE_LFH_FIXED_SZ; - ZipfileLFH lfh; - if( pFile ){ - rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr); - }else{ - aRead = (u8*)&aBlob[pNew->cds.iOffset]; - } + u32 *pt = &pNew->mUnixTime; + pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead); + pNew->aExtra = (u8*)&pNew[1]; + memcpy(pNew->aExtra, &aRead[nFile], nExtra); + if( pNew->cds.zFile==0 ){ + rc = SQLITE_NOMEM; + }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){ + pNew->mUnixTime = zipfileMtime(&pNew->cds); + } + } - if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh); - if( rc==SQLITE_OK ){ - pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ; - pNew->iDataOff += lfh.nFile + lfh.nExtra; - if( aBlob && pNew->cds.szCompressed ){ - pNew->aData = &pNew->aExtra[nExtra]; - memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed); - } - }else{ - *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", - (int)pNew->cds.iOffset - ); - } - } + if( rc==SQLITE_OK ){ + static const int szFix = ZIPFILE_LFH_FIXED_SZ; + ZipfileLFH lfh; + if( pFile ){ + rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr); + }else{ + aRead = (u8*)&aBlob[pNew->cds.iOffset]; + } + + if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh); + if( rc==SQLITE_OK ){ + pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ; + pNew->iDataOff += lfh.nFile + lfh.nExtra; + if( aBlob && pNew->cds.szCompressed ){ + pNew->aData = &pNew->aExtra[nExtra]; + memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed); + } + }else{ + *pzErr = sqlite3_mprintf("failed to read LFH at offset %d", + (int)pNew->cds.iOffset + ); + } + } - if( rc!=SQLITE_OK ){ - zipfileEntryFree(pNew); - }else{ - *ppEntry = pNew; - } + if( rc!=SQLITE_OK ){ + zipfileEntryFree(pNew); + }else{ + *ppEntry = pNew; } + } - return rc; + return rc; } /* ** Advance an ZipfileCsr to its next row of output. */ static int zipfileNext(sqlite3_vtab_cursor *cur){ - ZipfileCsr *pCsr = (ZipfileCsr*)cur; - int rc = SQLITE_OK; - - if( pCsr->pFile ){ - i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize; - zipfileEntryFree(pCsr->pCurrent); - pCsr->pCurrent = 0; - if( pCsr->iNextOff>=iEof ){ - pCsr->bEof = 1; - }else{ - ZipfileEntry *p = 0; - ZipfileTab *pTab = (ZipfileTab*)(cur->pVtab); - rc = zipfileGetEntry(pTab, 0, 0, pCsr->pFile, pCsr->iNextOff, &p); - if( rc==SQLITE_OK ){ - pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ; - pCsr->iNextOff += (int)p->cds.nExtra + p->cds.nFile + p->cds.nComment; - } - pCsr->pCurrent = p; - } + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + int rc = SQLITE_OK; + + if( pCsr->pFile ){ + i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize; + zipfileEntryFree(pCsr->pCurrent); + pCsr->pCurrent = 0; + if( pCsr->iNextOff>=iEof ){ + pCsr->bEof = 1; }else{ - if( !pCsr->bNoop ){ - pCsr->pCurrent = pCsr->pCurrent->pNext; - } - if( pCsr->pCurrent==0 ){ - pCsr->bEof = 1; - } + ZipfileEntry *p = 0; + ZipfileTab *pTab = (ZipfileTab*)(cur->pVtab); + rc = zipfileGetEntry(pTab, 0, 0, pCsr->pFile, pCsr->iNextOff, &p); + if( rc==SQLITE_OK ){ + pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ; + pCsr->iNextOff += (int)p->cds.nExtra + p->cds.nFile + p->cds.nComment; + } + pCsr->pCurrent = p; + } + }else{ + if( !pCsr->bNoop ){ + pCsr->pCurrent = pCsr->pCurrent->pNext; } + if( pCsr->pCurrent==0 ){ + pCsr->bEof = 1; + } + } - pCsr->bNoop = 0; - return rc; + pCsr->bNoop = 0; + return rc; } -static void zipfileFree(void *p) { - sqlite3_free(p); +static void zipfileFree(void *p) { + sqlite3_free(p); } /* @@ -7679,46 +7679,46 @@ static void zipfileFree(void *p) { ** If an error occurs, an error code is left in pCtx instead. */ static void zipfileInflate( - sqlite3_context *pCtx, /* Store result here */ - const u8 *aIn, /* Compressed data */ - int nIn, /* Size of buffer aIn[] in bytes */ - int nOut /* Expected output size */ + sqlite3_context *pCtx, /* Store result here */ + const u8 *aIn, /* Compressed data */ + int nIn, /* Size of buffer aIn[] in bytes */ + int nOut /* Expected output size */ ){ - u8 *aRes = sqlite3_malloc(nOut); - if( aRes==0 ){ - sqlite3_result_error_nomem(pCtx); + u8 *aRes = sqlite3_malloc(nOut); + if( aRes==0 ){ + sqlite3_result_error_nomem(pCtx); + }else{ + int err; + z_stream str; + memset(&str, 0, sizeof(str)); + + str.next_in = (Byte*)aIn; + str.avail_in = nIn; + str.next_out = (Byte*)aRes; + str.avail_out = nOut; + + err = inflateInit2(&str, -15); + if( err!=Z_OK ){ + zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err); }else{ - int err; - z_stream str; - memset(&str, 0, sizeof(str)); - - str.next_in = (Byte*)aIn; - str.avail_in = nIn; - str.next_out = (Byte*)aRes; - str.avail_out = nOut; - - err = inflateInit2(&str, -15); - if( err!=Z_OK ){ - zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err); - }else{ - err = inflate(&str, Z_NO_FLUSH); - if( err!=Z_STREAM_END ){ - zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err); - }else{ - sqlite3_result_blob(pCtx, aRes, nOut, zipfileFree); - aRes = 0; - } - } - sqlite3_free(aRes); - inflateEnd(&str); + err = inflate(&str, Z_NO_FLUSH); + if( err!=Z_STREAM_END ){ + zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err); + }else{ + sqlite3_result_blob(pCtx, aRes, nOut, zipfileFree); + aRes = 0; + } } + sqlite3_free(aRes); + inflateEnd(&str); + } } /* ** Buffer aIn (size nIn bytes) contains uncompressed data. This function ** compresses it and sets (*ppOut) to point to a buffer containing the ** compressed data. The caller is responsible for eventually calling -** sqlite3_free() to release buffer (*ppOut). Before returning, (*pnOut) +** sqlite3_free() to release buffer (*ppOut). Before returning, (*pnOut) ** is set to the size of buffer (*ppOut) in bytes. ** ** If no error occurs, SQLITE_OK is returned. Otherwise, an SQLite error @@ -7727,41 +7727,41 @@ static void zipfileInflate( ** case. */ static int zipfileDeflate( - const u8 *aIn, int nIn, /* Input */ - u8 **ppOut, int *pnOut, /* Output */ - char **pzErr /* OUT: Error message */ + const u8 *aIn, int nIn, /* Input */ + u8 **ppOut, int *pnOut, /* Output */ + char **pzErr /* OUT: Error message */ ){ - int rc = SQLITE_OK; - sqlite3_int64 nAlloc; - z_stream str; - u8 *aOut; - - memset(&str, 0, sizeof(str)); - str.next_in = (Bytef*)aIn; - str.avail_in = nIn; - deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); - - nAlloc = deflateBound(&str, nIn); - aOut = (u8*)sqlite3_malloc64(nAlloc); - if( aOut==0 ){ - rc = SQLITE_NOMEM; + int rc = SQLITE_OK; + sqlite3_int64 nAlloc; + z_stream str; + u8 *aOut; + + memset(&str, 0, sizeof(str)); + str.next_in = (Bytef*)aIn; + str.avail_in = nIn; + deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + + nAlloc = deflateBound(&str, nIn); + aOut = (u8*)sqlite3_malloc64(nAlloc); + if( aOut==0 ){ + rc = SQLITE_NOMEM; + }else{ + int res; + str.next_out = aOut; + str.avail_out = nAlloc; + res = deflate(&str, Z_FINISH); + if( res==Z_STREAM_END ){ + *ppOut = aOut; + *pnOut = (int)str.total_out; }else{ - int res; - str.next_out = aOut; - str.avail_out = nAlloc; - res = deflate(&str, Z_FINISH); - if( res==Z_STREAM_END ){ - *ppOut = aOut; - *pnOut = (int)str.total_out; - }else{ - sqlite3_free(aOut); - *pzErr = sqlite3_mprintf("zipfile: deflate() error"); - rc = SQLITE_ERROR; - } - deflateEnd(&str); + sqlite3_free(aOut); + *pzErr = sqlite3_mprintf("zipfile: deflate() error"); + rc = SQLITE_ERROR; } + deflateEnd(&str); + } - return rc; + return rc; } @@ -7770,95 +7770,95 @@ static int zipfileDeflate( ** is currently pointing. */ static int zipfileColumn( - sqlite3_vtab_cursor *cur, /* The cursor */ - sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ - int i /* Which column to return */ + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ ){ - ZipfileCsr *pCsr = (ZipfileCsr*)cur; - ZipfileCDS *pCDS = &pCsr->pCurrent->cds; - int rc = SQLITE_OK; - switch( i ){ - case 0: /* name */ - sqlite3_result_text(ctx, pCDS->zFile, -1, SQLITE_TRANSIENT); - break; - case 1: /* mode */ - /* TODO: Whether or not the following is correct surely depends on + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + ZipfileCDS *pCDS = &pCsr->pCurrent->cds; + int rc = SQLITE_OK; + switch( i ){ + case 0: /* name */ + sqlite3_result_text(ctx, pCDS->zFile, -1, SQLITE_TRANSIENT); + break; + case 1: /* mode */ + /* TODO: Whether or not the following is correct surely depends on ** the platform on which the archive was created. */ - sqlite3_result_int(ctx, pCDS->iExternalAttr >> 16); - break; - case 2: { /* mtime */ - sqlite3_result_int64(ctx, pCsr->pCurrent->mUnixTime); - break; - } - case 3: { /* sz */ - if( sqlite3_vtab_nochange(ctx)==0 ){ - sqlite3_result_int64(ctx, pCDS->szUncompressed); + sqlite3_result_int(ctx, pCDS->iExternalAttr >> 16); + break; + case 2: { /* mtime */ + sqlite3_result_int64(ctx, pCsr->pCurrent->mUnixTime); + break; + } + case 3: { /* sz */ + if( sqlite3_vtab_nochange(ctx)==0 ){ + sqlite3_result_int64(ctx, pCDS->szUncompressed); + } + break; + } + case 4: /* rawdata */ + if( sqlite3_vtab_nochange(ctx) ) break; + case 5: { /* data */ + if( i==4 || pCDS->iCompression==0 || pCDS->iCompression==8 ){ + int sz = pCDS->szCompressed; + int szFinal = pCDS->szUncompressed; + if( szFinal>0 ){ + u8 *aBuf; + u8 *aFree = 0; + if( pCsr->pCurrent->aData ){ + aBuf = pCsr->pCurrent->aData; + }else{ + aBuf = aFree = sqlite3_malloc64(sz); + if( aBuf==0 ){ + rc = SQLITE_NOMEM; + }else{ + FILE *pFile = pCsr->pFile; + if( pFile==0 ){ + pFile = ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd; + } + rc = zipfileReadData(pFile, aBuf, sz, pCsr->pCurrent->iDataOff, + &pCsr->base.pVtab->zErrMsg + ); + } + } + if( rc==SQLITE_OK ){ + if( i==5 && pCDS->iCompression ){ + zipfileInflate(ctx, aBuf, sz, szFinal); + }else{ + sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT); } - break; - } - case 4: /* rawdata */ - if( sqlite3_vtab_nochange(ctx) ) break; - case 5: { /* data */ - if( i==4 || pCDS->iCompression==0 || pCDS->iCompression==8 ){ - int sz = pCDS->szCompressed; - int szFinal = pCDS->szUncompressed; - if( szFinal>0 ){ - u8 *aBuf; - u8 *aFree = 0; - if( pCsr->pCurrent->aData ){ - aBuf = pCsr->pCurrent->aData; - }else{ - aBuf = aFree = sqlite3_malloc64(sz); - if( aBuf==0 ){ - rc = SQLITE_NOMEM; - }else{ - FILE *pFile = pCsr->pFile; - if( pFile==0 ){ - pFile = ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd; - } - rc = zipfileReadData(pFile, aBuf, sz, pCsr->pCurrent->iDataOff, - &pCsr->base.pVtab->zErrMsg - ); - } - } - if( rc==SQLITE_OK ){ - if( i==5 && pCDS->iCompression ){ - zipfileInflate(ctx, aBuf, sz, szFinal); - }else{ - sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT); - } - } - sqlite3_free(aFree); - }else{ - /* Figure out if this is a directory or a zero-sized file. Consider + } + sqlite3_free(aFree); + }else{ + /* Figure out if this is a directory or a zero-sized file. Consider ** it to be a directory either if the mode suggests so, or if ** the final character in the name is '/'. */ - u32 mode = pCDS->iExternalAttr >> 16; - if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){ - sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC); - } - } - } - break; + u32 mode = pCDS->iExternalAttr >> 16; + if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){ + sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC); + } } - case 6: /* method */ - sqlite3_result_int(ctx, pCDS->iCompression); - break; - default: /* z */ - assert( i==7 ); - sqlite3_result_int64(ctx, pCsr->iId); - break; + } + break; } + case 6: /* method */ + sqlite3_result_int(ctx, pCDS->iCompression); + break; + default: /* z */ + assert( i==7 ); + sqlite3_result_int64(ctx, pCsr->iId); + break; + } - return rc; + return rc; } /* ** Return TRUE if the cursor is at EOF. */ static int zipfileEof(sqlite3_vtab_cursor *cur){ - ZipfileCsr *pCsr = (ZipfileCsr*)cur; - return pCsr->bEof; + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + return pCsr->bEof; } /* @@ -7872,309 +7872,309 @@ static int zipfileEof(sqlite3_vtab_cursor *cur){ ** an English language error message may be left in virtual-table pTab. */ static int zipfileReadEOCD( - ZipfileTab *pTab, /* Return errors here */ - const u8 *aBlob, /* Pointer to in-memory file image */ - int nBlob, /* Size of aBlob[] in bytes */ - FILE *pFile, /* Read from this file if aBlob==0 */ - ZipfileEOCD *pEOCD /* Object to populate */ + ZipfileTab *pTab, /* Return errors here */ + const u8 *aBlob, /* Pointer to in-memory file image */ + int nBlob, /* Size of aBlob[] in bytes */ + FILE *pFile, /* Read from this file if aBlob==0 */ + ZipfileEOCD *pEOCD /* Object to populate */ ){ - u8 *aRead = pTab->aBuffer; /* Temporary buffer */ - int nRead; /* Bytes to read from file */ - int rc = SQLITE_OK; - - memset(pEOCD, 0, sizeof(ZipfileEOCD)); - if( aBlob==0 ){ - i64 iOff; /* Offset to read from */ - i64 szFile; /* Total size of file in bytes */ - fseek(pFile, 0, SEEK_END); - szFile = (i64)ftell(pFile); - if( szFile==0 ){ - return SQLITE_OK; - } - nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE)); - iOff = szFile - nRead; - rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg); - }else{ - nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE)); - aRead = (u8*)&aBlob[nBlob-nRead]; + u8 *aRead = pTab->aBuffer; /* Temporary buffer */ + int nRead; /* Bytes to read from file */ + int rc = SQLITE_OK; + + memset(pEOCD, 0, sizeof(ZipfileEOCD)); + if( aBlob==0 ){ + i64 iOff; /* Offset to read from */ + i64 szFile; /* Total size of file in bytes */ + fseek(pFile, 0, SEEK_END); + szFile = (i64)ftell(pFile); + if( szFile==0 ){ + return SQLITE_OK; + } + nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE)); + iOff = szFile - nRead; + rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg); + }else{ + nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE)); + aRead = (u8*)&aBlob[nBlob-nRead]; + } + + if( rc==SQLITE_OK ){ + int i; + + /* Scan backwards looking for the signature bytes */ + for(i=nRead-20; i>=0; i--){ + if( aRead[i]==0x50 && aRead[i+1]==0x4b + && aRead[i+2]==0x05 && aRead[i+3]==0x06 + ){ + break; + } + } + if( i<0 ){ + pTab->base.zErrMsg = sqlite3_mprintf( + "cannot find end of central directory record" + ); + return SQLITE_ERROR; } - if( rc==SQLITE_OK ){ - int i; + aRead += i+4; + pEOCD->iDisk = zipfileRead16(aRead); + pEOCD->iFirstDisk = zipfileRead16(aRead); + pEOCD->nEntry = zipfileRead16(aRead); + pEOCD->nEntryTotal = zipfileRead16(aRead); + pEOCD->nSize = zipfileRead32(aRead); + pEOCD->iOffset = zipfileRead32(aRead); + } - /* Scan backwards looking for the signature bytes */ - for(i=nRead-20; i>=0; i--){ - if( aRead[i]==0x50 && aRead[i+1]==0x4b - && aRead[i+2]==0x05 && aRead[i+3]==0x06 - ){ - break; - } - } - if( i<0 ){ - pTab->base.zErrMsg = sqlite3_mprintf( - "cannot find end of central directory record" - ); - return SQLITE_ERROR; - } - - aRead += i+4; - pEOCD->iDisk = zipfileRead16(aRead); - pEOCD->iFirstDisk = zipfileRead16(aRead); - pEOCD->nEntry = zipfileRead16(aRead); - pEOCD->nEntryTotal = zipfileRead16(aRead); - pEOCD->nSize = zipfileRead32(aRead); - pEOCD->iOffset = zipfileRead32(aRead); - } - - return rc; + return rc; } /* -** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry +** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry ** and ends with pLastEntry. If argument pBefore is NULL, then pNew is added ** to the end of the list. Otherwise, it is added to the list immediately ** before pBefore (which is guaranteed to be a part of said list). */ static void zipfileAddEntry( - ZipfileTab *pTab, - ZipfileEntry *pBefore, - ZipfileEntry *pNew + ZipfileTab *pTab, + ZipfileEntry *pBefore, + ZipfileEntry *pNew ){ - assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) ); - assert( pNew->pNext==0 ); - if( pBefore==0 ){ - if( pTab->pFirstEntry==0 ){ - pTab->pFirstEntry = pTab->pLastEntry = pNew; - }else{ - assert( pTab->pLastEntry->pNext==0 ); - pTab->pLastEntry->pNext = pNew; - pTab->pLastEntry = pNew; - } + assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) ); + assert( pNew->pNext==0 ); + if( pBefore==0 ){ + if( pTab->pFirstEntry==0 ){ + pTab->pFirstEntry = pTab->pLastEntry = pNew; }else{ - ZipfileEntry **pp; - for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext)); - pNew->pNext = pBefore; - *pp = pNew; + assert( pTab->pLastEntry->pNext==0 ); + pTab->pLastEntry->pNext = pNew; + pTab->pLastEntry = pNew; } + }else{ + ZipfileEntry **pp; + for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext)); + pNew->pNext = pBefore; + *pp = pNew; + } } static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){ - ZipfileEOCD eocd; - int rc; - int i; - i64 iOff; + ZipfileEOCD eocd; + int rc; + int i; + i64 iOff; - rc = zipfileReadEOCD(pTab, aBlob, nBlob, pTab->pWriteFd, &eocd); - iOff = eocd.iOffset; - for(i=0; rc==SQLITE_OK && ipWriteFd, iOff, &pNew); + rc = zipfileReadEOCD(pTab, aBlob, nBlob, pTab->pWriteFd, &eocd); + iOff = eocd.iOffset; + for(i=0; rc==SQLITE_OK && ipWriteFd, iOff, &pNew); - if( rc==SQLITE_OK ){ - zipfileAddEntry(pTab, 0, pNew); - iOff += ZIPFILE_CDS_FIXED_SZ; - iOff += (int)pNew->cds.nExtra + pNew->cds.nFile + pNew->cds.nComment; - } + if( rc==SQLITE_OK ){ + zipfileAddEntry(pTab, 0, pNew); + iOff += ZIPFILE_CDS_FIXED_SZ; + iOff += (int)pNew->cds.nExtra + pNew->cds.nFile + pNew->cds.nComment; } - return rc; + } + return rc; } /* ** xFilter callback. */ static int zipfileFilter( - sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv ){ - ZipfileTab *pTab = (ZipfileTab*)cur->pVtab; - ZipfileCsr *pCsr = (ZipfileCsr*)cur; - const char *zFile = 0; /* Zip file to scan */ - int rc = SQLITE_OK; /* Return Code */ - int bInMemory = 0; /* True for an in-memory zipfile */ - - zipfileResetCursor(pCsr); - - if( pTab->zFile ){ - zFile = pTab->zFile; - }else if( idxNum==0 ){ - zipfileCursorErr(pCsr, "zipfile() function requires an argument"); - return SQLITE_ERROR; - }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ - const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]); - int nBlob = sqlite3_value_bytes(argv[0]); - assert( pTab->pFirstEntry==0 ); - rc = zipfileLoadDirectory(pTab, aBlob, nBlob); - pCsr->pFreeEntry = pTab->pFirstEntry; - pTab->pFirstEntry = pTab->pLastEntry = 0; - if( rc!=SQLITE_OK ) return rc; - bInMemory = 1; - }else{ - zFile = (const char*)sqlite3_value_text(argv[0]); - } + ZipfileTab *pTab = (ZipfileTab*)cur->pVtab; + ZipfileCsr *pCsr = (ZipfileCsr*)cur; + const char *zFile = 0; /* Zip file to scan */ + int rc = SQLITE_OK; /* Return Code */ + int bInMemory = 0; /* True for an in-memory zipfile */ + + zipfileResetCursor(pCsr); + + if( pTab->zFile ){ + zFile = pTab->zFile; + }else if( idxNum==0 ){ + zipfileCursorErr(pCsr, "zipfile() function requires an argument"); + return SQLITE_ERROR; + }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ + const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]); + int nBlob = sqlite3_value_bytes(argv[0]); + assert( pTab->pFirstEntry==0 ); + rc = zipfileLoadDirectory(pTab, aBlob, nBlob); + pCsr->pFreeEntry = pTab->pFirstEntry; + pTab->pFirstEntry = pTab->pLastEntry = 0; + if( rc!=SQLITE_OK ) return rc; + bInMemory = 1; + }else{ + zFile = (const char*)sqlite3_value_text(argv[0]); + } - if( 0==pTab->pWriteFd && 0==bInMemory ){ - pCsr->pFile = fopen(zFile, "rb"); - if( pCsr->pFile==0 ){ - zipfileCursorErr(pCsr, "cannot open file: %s", zFile); - rc = SQLITE_ERROR; + if( 0==pTab->pWriteFd && 0==bInMemory ){ + pCsr->pFile = fopen(zFile, "rb"); + if( pCsr->pFile==0 ){ + zipfileCursorErr(pCsr, "cannot open file: %s", zFile); + rc = SQLITE_ERROR; + }else{ + rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd); + if( rc==SQLITE_OK ){ + if( pCsr->eocd.nEntry==0 ){ + pCsr->bEof = 1; }else{ - rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd); - if( rc==SQLITE_OK ){ - if( pCsr->eocd.nEntry==0 ){ - pCsr->bEof = 1; - }else{ - pCsr->iNextOff = pCsr->eocd.iOffset; - rc = zipfileNext(cur); - } - } + pCsr->iNextOff = pCsr->eocd.iOffset; + rc = zipfileNext(cur); } - }else{ - pCsr->bNoop = 1; - pCsr->pCurrent = pCsr->pFreeEntry ? pCsr->pFreeEntry : pTab->pFirstEntry; - rc = zipfileNext(cur); + } } + }else{ + pCsr->bNoop = 1; + pCsr->pCurrent = pCsr->pFreeEntry ? pCsr->pFreeEntry : pTab->pFirstEntry; + rc = zipfileNext(cur); + } - return rc; + return rc; } /* ** xBestIndex callback. */ static int zipfileBestIndex( - sqlite3_vtab *tab, - sqlite3_index_info *pIdxInfo + sqlite3_vtab *tab, + sqlite3_index_info *pIdxInfo ){ - int i; - int idx = -1; - int unusable = 0; - - for(i=0; inConstraint; i++){ - const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; - if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue; - if( pCons->usable==0 ){ - unusable = 1; - }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ - idx = i; - } - } - pIdxInfo->estimatedCost = 1000.0; - if( idx>=0 ){ - pIdxInfo->aConstraintUsage[idx].argvIndex = 1; - pIdxInfo->aConstraintUsage[idx].omit = 1; - pIdxInfo->idxNum = 1; - }else if( unusable ){ - return SQLITE_CONSTRAINT; - } - return SQLITE_OK; + int i; + int idx = -1; + int unusable = 0; + + for(i=0; inConstraint; i++){ + const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; + if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue; + if( pCons->usable==0 ){ + unusable = 1; + }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + idx = i; + } + } + pIdxInfo->estimatedCost = 1000.0; + if( idx>=0 ){ + pIdxInfo->aConstraintUsage[idx].argvIndex = 1; + pIdxInfo->aConstraintUsage[idx].omit = 1; + pIdxInfo->idxNum = 1; + }else if( unusable ){ + return SQLITE_CONSTRAINT; + } + return SQLITE_OK; } static ZipfileEntry *zipfileNewEntry(const char *zPath){ - ZipfileEntry *pNew; - pNew = sqlite3_malloc(sizeof(ZipfileEntry)); - if( pNew ){ - memset(pNew, 0, sizeof(ZipfileEntry)); - pNew->cds.zFile = sqlite3_mprintf("%s", zPath); - if( pNew->cds.zFile==0 ){ - sqlite3_free(pNew); - pNew = 0; - } + ZipfileEntry *pNew; + pNew = sqlite3_malloc(sizeof(ZipfileEntry)); + if( pNew ){ + memset(pNew, 0, sizeof(ZipfileEntry)); + pNew->cds.zFile = sqlite3_mprintf("%s", zPath); + if( pNew->cds.zFile==0 ){ + sqlite3_free(pNew); + pNew = 0; } - return pNew; + } + return pNew; } static int zipfileSerializeLFH(ZipfileEntry *pEntry, u8 *aBuf){ - ZipfileCDS *pCds = &pEntry->cds; - u8 *a = aBuf; - - pCds->nExtra = 9; - - /* Write the LFH itself */ - zipfileWrite32(a, ZIPFILE_SIGNATURE_LFH); - zipfileWrite16(a, pCds->iVersionExtract); - zipfileWrite16(a, pCds->flags); - zipfileWrite16(a, pCds->iCompression); - zipfileWrite16(a, pCds->mTime); - zipfileWrite16(a, pCds->mDate); - zipfileWrite32(a, pCds->crc32); - zipfileWrite32(a, pCds->szCompressed); - zipfileWrite32(a, pCds->szUncompressed); - zipfileWrite16(a, (u16)pCds->nFile); - zipfileWrite16(a, pCds->nExtra); - assert( a==&aBuf[ZIPFILE_LFH_FIXED_SZ] ); - - /* Add the file name */ - memcpy(a, pCds->zFile, (int)pCds->nFile); - a += (int)pCds->nFile; - - /* The "extra" data */ - zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP); - zipfileWrite16(a, 5); - *a++ = 0x01; - zipfileWrite32(a, pEntry->mUnixTime); - - return a-aBuf; + ZipfileCDS *pCds = &pEntry->cds; + u8 *a = aBuf; + + pCds->nExtra = 9; + + /* Write the LFH itself */ + zipfileWrite32(a, ZIPFILE_SIGNATURE_LFH); + zipfileWrite16(a, pCds->iVersionExtract); + zipfileWrite16(a, pCds->flags); + zipfileWrite16(a, pCds->iCompression); + zipfileWrite16(a, pCds->mTime); + zipfileWrite16(a, pCds->mDate); + zipfileWrite32(a, pCds->crc32); + zipfileWrite32(a, pCds->szCompressed); + zipfileWrite32(a, pCds->szUncompressed); + zipfileWrite16(a, (u16)pCds->nFile); + zipfileWrite16(a, pCds->nExtra); + assert( a==&aBuf[ZIPFILE_LFH_FIXED_SZ] ); + + /* Add the file name */ + memcpy(a, pCds->zFile, (int)pCds->nFile); + a += (int)pCds->nFile; + + /* The "extra" data */ + zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP); + zipfileWrite16(a, 5); + *a++ = 0x01; + zipfileWrite32(a, pEntry->mUnixTime); + + return a-aBuf; } static int zipfileAppendEntry( - ZipfileTab *pTab, - ZipfileEntry *pEntry, - const u8 *pData, - int nData + ZipfileTab *pTab, + ZipfileEntry *pEntry, + const u8 *pData, + int nData ){ - u8 *aBuf = pTab->aBuffer; - int nBuf; - int rc; + u8 *aBuf = pTab->aBuffer; + int nBuf; + int rc; - nBuf = zipfileSerializeLFH(pEntry, aBuf); - rc = zipfileAppendData(pTab, aBuf, nBuf); - if( rc==SQLITE_OK ){ - pEntry->iDataOff = pTab->szCurrent; - rc = zipfileAppendData(pTab, pData, nData); - } + nBuf = zipfileSerializeLFH(pEntry, aBuf); + rc = zipfileAppendData(pTab, aBuf, nBuf); + if( rc==SQLITE_OK ){ + pEntry->iDataOff = pTab->szCurrent; + rc = zipfileAppendData(pTab, pData, nData); + } - return rc; + return rc; } static int zipfileGetMode( - sqlite3_value *pVal, - int bIsDir, /* If true, default to directory */ - u32 *pMode, /* OUT: Mode value */ - char **pzErr /* OUT: Error message */ + sqlite3_value *pVal, + int bIsDir, /* If true, default to directory */ + u32 *pMode, /* OUT: Mode value */ + char **pzErr /* OUT: Error message */ ){ - const char *z = (const char*)sqlite3_value_text(pVal); - u32 mode = 0; - if( z==0 ){ - mode = (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644)); - }else if( z[0]>='0' && z[0]<='9' ){ - mode = (unsigned int)sqlite3_value_int(pVal); - }else{ - const char zTemplate[11] = "-rwxrwxrwx"; - int i; - if( strlen(z)!=10 ) goto parse_error; - switch( z[0] ){ - case '-': mode |= S_IFREG; break; - case 'd': mode |= S_IFDIR; break; - case 'l': mode |= S_IFLNK; break; - default: goto parse_error; - } - for(i=1; i<10; i++){ - if( z[i]==zTemplate[i] ) mode |= 1 << (9-i); - else if( z[i]!='-' ) goto parse_error; - } - } - if( ((mode & S_IFDIR)==0)==bIsDir ){ - /* The "mode" attribute is a directory, but data has been specified. + const char *z = (const char*)sqlite3_value_text(pVal); + u32 mode = 0; + if( z==0 ){ + mode = (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644)); + }else if( z[0]>='0' && z[0]<='9' ){ + mode = (unsigned int)sqlite3_value_int(pVal); + }else{ + const char zTemplate[11] = "-rwxrwxrwx"; + int i; + if( strlen(z)!=10 ) goto parse_error; + switch( z[0] ){ + case '-': mode |= S_IFREG; break; + case 'd': mode |= S_IFDIR; break; + case 'l': mode |= S_IFLNK; break; + default: goto parse_error; + } + for(i=1; i<10; i++){ + if( z[i]==zTemplate[i] ) mode |= 1 << (9-i); + else if( z[i]!='-' ) goto parse_error; + } + } + if( ((mode & S_IFDIR)==0)==bIsDir ){ + /* The "mode" attribute is a directory, but data has been specified. ** Or vice-versa - no data but "mode" is a file or symlink. */ - *pzErr = sqlite3_mprintf("zipfile: mode does not match data"); - return SQLITE_CONSTRAINT; - } - *pMode = mode; - return SQLITE_OK; + *pzErr = sqlite3_mprintf("zipfile: mode does not match data"); + return SQLITE_CONSTRAINT; + } + *pMode = mode; + return SQLITE_OK; -parse_error: - *pzErr = sqlite3_mprintf("zipfile: parse error in mode: %s", z); - return SQLITE_ERROR; + parse_error: + *pzErr = sqlite3_mprintf("zipfile: parse error in mode: %s", z); + return SQLITE_ERROR; } /* @@ -8182,44 +8182,44 @@ parse_error: ** nB is the value of strlen(zB). This function returns 0 if the strings are ** identical, ignoring any trailing '/' character in either path. */ static int zipfileComparePath(const char *zA, const char *zB, int nB){ - int nA = (int)strlen(zA); - if( nA>0 && zA[nA-1]=='/' ) nA--; - if( nB>0 && zB[nB-1]=='/' ) nB--; - if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0; - return 1; + int nA = (int)strlen(zA); + if( nA>0 && zA[nA-1]=='/' ) nA--; + if( nB>0 && zB[nB-1]=='/' ) nB--; + if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0; + return 1; } static int zipfileBegin(sqlite3_vtab *pVtab){ - ZipfileTab *pTab = (ZipfileTab*)pVtab; - int rc = SQLITE_OK; + ZipfileTab *pTab = (ZipfileTab*)pVtab; + int rc = SQLITE_OK; - assert( pTab->pWriteFd==0 ); - if( pTab->zFile==0 || pTab->zFile[0]==0 ){ - pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename"); - return SQLITE_ERROR; - } + assert( pTab->pWriteFd==0 ); + if( pTab->zFile==0 || pTab->zFile[0]==0 ){ + pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename"); + return SQLITE_ERROR; + } - /* Open a write fd on the file. Also load the entire central directory - ** structure into memory. During the transaction any new file data is + /* Open a write fd on the file. Also load the entire central directory + ** structure into memory. During the transaction any new file data is ** appended to the archive file, but the central directory is accumulated ** in main-memory until the transaction is committed. */ - pTab->pWriteFd = fopen(pTab->zFile, "ab+"); - if( pTab->pWriteFd==0 ){ - pTab->base.zErrMsg = sqlite3_mprintf( - "zipfile: failed to open file %s for writing", pTab->zFile + pTab->pWriteFd = fopen(pTab->zFile, "ab+"); + if( pTab->pWriteFd==0 ){ + pTab->base.zErrMsg = sqlite3_mprintf( + "zipfile: failed to open file %s for writing", pTab->zFile ); - rc = SQLITE_ERROR; - }else{ - fseek(pTab->pWriteFd, 0, SEEK_END); - pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd); - rc = zipfileLoadDirectory(pTab, 0, 0); - } + rc = SQLITE_ERROR; + }else{ + fseek(pTab->pWriteFd, 0, SEEK_END); + pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd); + rc = zipfileLoadDirectory(pTab, 0, 0); + } - if( rc!=SQLITE_OK ){ - zipfileCleanupTransaction(pTab); - } + if( rc!=SQLITE_OK ){ + zipfileCleanupTransaction(pTab); + } - return rc; + return rc; } /* @@ -8227,19 +8227,19 @@ static int zipfileBegin(sqlite3_vtab *pVtab){ ** time(2)). */ static u32 zipfileTime(void){ - sqlite3_vfs *pVfs = sqlite3_vfs_find(0); - u32 ret; - if( pVfs==0 ) return 0; - if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ - i64 ms; - pVfs->xCurrentTimeInt64(pVfs, &ms); - ret = (u32)((ms/1000) - ((i64)24405875 * 8640)); - }else{ - double day; - pVfs->xCurrentTime(pVfs, &day); - ret = (u32)((day - 2440587.5) * 86400); - } - return ret; + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); + u32 ret; + if( pVfs==0 ) return 0; + if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){ + i64 ms; + pVfs->xCurrentTimeInt64(pVfs, &ms); + ret = (u32)((ms/1000) - ((i64)24405875 * 8640)); + }else{ + double day; + pVfs->xCurrentTime(pVfs, &day); + ret = (u32)((day - 2440587.5) * 86400); + } + return ret; } /* @@ -8250,10 +8250,10 @@ static u32 zipfileTime(void){ ** cast to a 32-bit unsigned integer. */ static u32 zipfileGetTime(sqlite3_value *pVal){ - if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){ - return zipfileTime(); - } - return (u32)sqlite3_value_int64(pVal); + if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){ + return zipfileTime(); + } + return (u32)sqlite3_value_int64(pVal); } /* @@ -8261,226 +8261,226 @@ static u32 zipfileGetTime(sqlite3_value *pVal){ ** linked list. Remove it from the list and free the object. */ static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){ - if( pOld ){ - ZipfileEntry **pp; - for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext)); - *pp = (*pp)->pNext; - zipfileEntryFree(pOld); - } + if( pOld ){ + ZipfileEntry **pp; + for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext)); + *pp = (*pp)->pNext; + zipfileEntryFree(pOld); + } } /* ** xUpdate method. */ static int zipfileUpdate( - sqlite3_vtab *pVtab, - int nVal, - sqlite3_value **apVal, - sqlite_int64 *pRowid + sqlite3_vtab *pVtab, + int nVal, + sqlite3_value **apVal, + sqlite_int64 *pRowid ){ - ZipfileTab *pTab = (ZipfileTab*)pVtab; - int rc = SQLITE_OK; /* Return Code */ - ZipfileEntry *pNew = 0; /* New in-memory CDS entry */ - - u32 mode = 0; /* Mode for new entry */ - u32 mTime = 0; /* Modification time for new entry */ - i64 sz = 0; /* Uncompressed size */ - const char *zPath = 0; /* Path for new entry */ - int nPath = 0; /* strlen(zPath) */ - const u8 *pData = 0; /* Pointer to buffer containing content */ - int nData = 0; /* Size of pData buffer in bytes */ - int iMethod = 0; /* Compression method for new entry */ - u8 *pFree = 0; /* Free this */ - char *zFree = 0; /* Also free this */ - ZipfileEntry *pOld = 0; - ZipfileEntry *pOld2 = 0; - int bUpdate = 0; /* True for an update that modifies "name" */ - int bIsDir = 0; - u32 iCrc32 = 0; - - if( pTab->pWriteFd==0 ){ - rc = zipfileBegin(pVtab); - if( rc!=SQLITE_OK ) return rc; - } + ZipfileTab *pTab = (ZipfileTab*)pVtab; + int rc = SQLITE_OK; /* Return Code */ + ZipfileEntry *pNew = 0; /* New in-memory CDS entry */ + + u32 mode = 0; /* Mode for new entry */ + u32 mTime = 0; /* Modification time for new entry */ + i64 sz = 0; /* Uncompressed size */ + const char *zPath = 0; /* Path for new entry */ + int nPath = 0; /* strlen(zPath) */ + const u8 *pData = 0; /* Pointer to buffer containing content */ + int nData = 0; /* Size of pData buffer in bytes */ + int iMethod = 0; /* Compression method for new entry */ + u8 *pFree = 0; /* Free this */ + char *zFree = 0; /* Also free this */ + ZipfileEntry *pOld = 0; + ZipfileEntry *pOld2 = 0; + int bUpdate = 0; /* True for an update that modifies "name" */ + int bIsDir = 0; + u32 iCrc32 = 0; + + if( pTab->pWriteFd==0 ){ + rc = zipfileBegin(pVtab); + if( rc!=SQLITE_OK ) return rc; + } - /* If this is a DELETE or UPDATE, find the archive entry to delete. */ - if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ - const char *zDelete = (const char*)sqlite3_value_text(apVal[0]); - int nDelete = (int)strlen(zDelete); - if( nVal>1 ){ - const char *zUpdate = (const char*)sqlite3_value_text(apVal[1]); - if( zUpdate && zipfileComparePath(zUpdate, zDelete, nDelete)!=0 ){ - bUpdate = 1; - } - } - for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){ - if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){ - break; - } - assert( pOld->pNext ); - } + /* If this is a DELETE or UPDATE, find the archive entry to delete. */ + if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ + const char *zDelete = (const char*)sqlite3_value_text(apVal[0]); + int nDelete = (int)strlen(zDelete); + if( nVal>1 ){ + const char *zUpdate = (const char*)sqlite3_value_text(apVal[1]); + if( zUpdate && zipfileComparePath(zUpdate, zDelete, nDelete)!=0 ){ + bUpdate = 1; + } + } + for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){ + if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){ + break; + } + assert( pOld->pNext ); } + } - if( nVal>1 ){ - /* Check that "sz" and "rawdata" are both NULL: */ - if( sqlite3_value_type(apVal[5])!=SQLITE_NULL ){ - zipfileTableErr(pTab, "sz must be NULL"); - rc = SQLITE_CONSTRAINT; - } - if( sqlite3_value_type(apVal[6])!=SQLITE_NULL ){ - zipfileTableErr(pTab, "rawdata must be NULL"); - rc = SQLITE_CONSTRAINT; - } + if( nVal>1 ){ + /* Check that "sz" and "rawdata" are both NULL: */ + if( sqlite3_value_type(apVal[5])!=SQLITE_NULL ){ + zipfileTableErr(pTab, "sz must be NULL"); + rc = SQLITE_CONSTRAINT; + } + if( sqlite3_value_type(apVal[6])!=SQLITE_NULL ){ + zipfileTableErr(pTab, "rawdata must be NULL"); + rc = SQLITE_CONSTRAINT; + } - if( rc==SQLITE_OK ){ - if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){ - /* data=NULL. A directory */ - bIsDir = 1; - }else{ - /* Value specified for "data", and possibly "method". This must be + if( rc==SQLITE_OK ){ + if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){ + /* data=NULL. A directory */ + bIsDir = 1; + }else{ + /* Value specified for "data", and possibly "method". This must be ** a regular file or a symlink. */ - const u8 *aIn = sqlite3_value_blob(apVal[7]); - int nIn = sqlite3_value_bytes(apVal[7]); - int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL; - - iMethod = sqlite3_value_int(apVal[8]); - sz = nIn; - pData = aIn; - nData = nIn; - if( iMethod!=0 && iMethod!=8 ){ - zipfileTableErr(pTab, "unknown compression method: %d", iMethod); - rc = SQLITE_CONSTRAINT; - }else{ - if( bAuto || iMethod ){ - int nCmp; - rc = zipfileDeflate(aIn, nIn, &pFree, &nCmp, &pTab->base.zErrMsg); - if( rc==SQLITE_OK ){ - if( iMethod || nCmpbase.zErrMsg); + if( rc==SQLITE_OK ){ + if( iMethod || nCmpbase.zErrMsg); - } + if( rc==SQLITE_OK ){ + rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg); + } - if( rc==SQLITE_OK ){ - zPath = (const char*)sqlite3_value_text(apVal[2]); - if( zPath==0 ) zPath = ""; - nPath = (int)strlen(zPath); - mTime = zipfileGetTime(apVal[4]); - } + if( rc==SQLITE_OK ){ + zPath = (const char*)sqlite3_value_text(apVal[2]); + if( zPath==0 ) zPath = ""; + nPath = (int)strlen(zPath); + mTime = zipfileGetTime(apVal[4]); + } - if( rc==SQLITE_OK && bIsDir ){ - /* For a directory, check that the last character in the path is a + if( rc==SQLITE_OK && bIsDir ){ + /* For a directory, check that the last character in the path is a ** '/'. This appears to be required for compatibility with info-zip ** (the unzip command on unix). It does not create directories ** otherwise. */ - if( nPath<=0 || zPath[nPath-1]!='/' ){ - zFree = sqlite3_mprintf("%s/", zPath); - zPath = (const char*)zFree; - if( zFree==0 ){ - rc = SQLITE_NOMEM; - nPath = 0; - }else{ - nPath = (int)strlen(zPath); - } - } + if( nPath<=0 || zPath[nPath-1]!='/' ){ + zFree = sqlite3_mprintf("%s/", zPath); + zPath = (const char*)zFree; + if( zFree==0 ){ + rc = SQLITE_NOMEM; + nPath = 0; + }else{ + nPath = (int)strlen(zPath); } + } + } - /* Check that we're not inserting a duplicate entry -OR- updating an + /* Check that we're not inserting a duplicate entry -OR- updating an ** entry with a path, thereby making it into a duplicate. */ - if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){ - ZipfileEntry *p; - for(p=pTab->pFirstEntry; p; p=p->pNext){ - if( zipfileComparePath(p->cds.zFile, zPath, nPath)==0 ){ - switch( sqlite3_vtab_on_conflict(pTab->db) ){ - case SQLITE_IGNORE: { - goto zipfile_update_done; - } - case SQLITE_REPLACE: { - pOld2 = p; - break; - } - default: { - zipfileTableErr(pTab, "duplicate name: \"%s\"", zPath); - rc = SQLITE_CONSTRAINT; - break; - } - } - break; - } + if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){ + ZipfileEntry *p; + for(p=pTab->pFirstEntry; p; p=p->pNext){ + if( zipfileComparePath(p->cds.zFile, zPath, nPath)==0 ){ + switch( sqlite3_vtab_on_conflict(pTab->db) ){ + case SQLITE_IGNORE: { + goto zipfile_update_done; + } + case SQLITE_REPLACE: { + pOld2 = p; + break; } - } - - if( rc==SQLITE_OK ){ - /* Create the new CDS record. */ - pNew = zipfileNewEntry(zPath); - if( pNew==0 ){ - rc = SQLITE_NOMEM; - }else{ - pNew->cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; - pNew->cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED; - pNew->cds.flags = ZIPFILE_NEWENTRY_FLAGS; - pNew->cds.iCompression = (u16)iMethod; - zipfileMtimeToDos(&pNew->cds, mTime); - pNew->cds.crc32 = iCrc32; - pNew->cds.szCompressed = nData; - pNew->cds.szUncompressed = (u32)sz; - pNew->cds.iExternalAttr = (mode<<16); - pNew->cds.iOffset = (u32)pTab->szCurrent; - pNew->cds.nFile = (u16)nPath; - pNew->mUnixTime = (u32)mTime; - rc = zipfileAppendEntry(pTab, pNew, pData, nData); - zipfileAddEntry(pTab, pOld, pNew); + default: { + zipfileTableErr(pTab, "duplicate name: \"%s\"", zPath); + rc = SQLITE_CONSTRAINT; + break; } + } + break; } + } } - if( rc==SQLITE_OK && (pOld || pOld2) ){ - ZipfileCsr *pCsr; - for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){ - if( pCsr->pCurrent && (pCsr->pCurrent==pOld || pCsr->pCurrent==pOld2) ){ - pCsr->pCurrent = pCsr->pCurrent->pNext; - pCsr->bNoop = 1; - } - } - - zipfileRemoveEntryFromList(pTab, pOld); - zipfileRemoveEntryFromList(pTab, pOld2); + if( rc==SQLITE_OK ){ + /* Create the new CDS record. */ + pNew = zipfileNewEntry(zPath); + if( pNew==0 ){ + rc = SQLITE_NOMEM; + }else{ + pNew->cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; + pNew->cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED; + pNew->cds.flags = ZIPFILE_NEWENTRY_FLAGS; + pNew->cds.iCompression = (u16)iMethod; + zipfileMtimeToDos(&pNew->cds, mTime); + pNew->cds.crc32 = iCrc32; + pNew->cds.szCompressed = nData; + pNew->cds.szUncompressed = (u32)sz; + pNew->cds.iExternalAttr = (mode<<16); + pNew->cds.iOffset = (u32)pTab->szCurrent; + pNew->cds.nFile = (u16)nPath; + pNew->mUnixTime = (u32)mTime; + rc = zipfileAppendEntry(pTab, pNew, pData, nData); + zipfileAddEntry(pTab, pOld, pNew); + } + } + } + + if( rc==SQLITE_OK && (pOld || pOld2) ){ + ZipfileCsr *pCsr; + for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){ + if( pCsr->pCurrent && (pCsr->pCurrent==pOld || pCsr->pCurrent==pOld2) ){ + pCsr->pCurrent = pCsr->pCurrent->pNext; + pCsr->bNoop = 1; + } } + zipfileRemoveEntryFromList(pTab, pOld); + zipfileRemoveEntryFromList(pTab, pOld2); + } + zipfile_update_done: - sqlite3_free(pFree); - sqlite3_free(zFree); - return rc; + sqlite3_free(pFree); + sqlite3_free(zFree); + return rc; } static int zipfileSerializeEOCD(ZipfileEOCD *p, u8 *aBuf){ - u8 *a = aBuf; - zipfileWrite32(a, ZIPFILE_SIGNATURE_EOCD); - zipfileWrite16(a, p->iDisk); - zipfileWrite16(a, p->iFirstDisk); - zipfileWrite16(a, p->nEntry); - zipfileWrite16(a, p->nEntryTotal); - zipfileWrite32(a, p->nSize); - zipfileWrite32(a, p->iOffset); - zipfileWrite16(a, 0); /* Size of trailing comment in bytes*/ + u8 *a = aBuf; + zipfileWrite32(a, ZIPFILE_SIGNATURE_EOCD); + zipfileWrite16(a, p->iDisk); + zipfileWrite16(a, p->iFirstDisk); + zipfileWrite16(a, p->nEntry); + zipfileWrite16(a, p->nEntryTotal); + zipfileWrite32(a, p->nSize); + zipfileWrite32(a, p->iOffset); + zipfileWrite16(a, 0); /* Size of trailing comment in bytes*/ - return a-aBuf; + return a-aBuf; } static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){ - int nBuf = zipfileSerializeEOCD(p, pTab->aBuffer); - assert( nBuf==ZIPFILE_EOCD_FIXED_SZ ); - return zipfileAppendData(pTab, pTab->aBuffer, nBuf); + int nBuf = zipfileSerializeEOCD(p, pTab->aBuffer); + assert( nBuf==ZIPFILE_EOCD_FIXED_SZ ); + return zipfileAppendData(pTab, pTab->aBuffer, nBuf); } /* @@ -8488,185 +8488,185 @@ static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){ ** of bytes written. */ static int zipfileSerializeCDS(ZipfileEntry *pEntry, u8 *aBuf){ - u8 *a = aBuf; - ZipfileCDS *pCDS = &pEntry->cds; - - if( pEntry->aExtra==0 ){ - pCDS->nExtra = 9; - } - - zipfileWrite32(a, ZIPFILE_SIGNATURE_CDS); - zipfileWrite16(a, pCDS->iVersionMadeBy); - zipfileWrite16(a, pCDS->iVersionExtract); - zipfileWrite16(a, pCDS->flags); - zipfileWrite16(a, pCDS->iCompression); - zipfileWrite16(a, pCDS->mTime); - zipfileWrite16(a, pCDS->mDate); - zipfileWrite32(a, pCDS->crc32); - zipfileWrite32(a, pCDS->szCompressed); - zipfileWrite32(a, pCDS->szUncompressed); - assert( a==&aBuf[ZIPFILE_CDS_NFILE_OFF] ); - zipfileWrite16(a, pCDS->nFile); - zipfileWrite16(a, pCDS->nExtra); - zipfileWrite16(a, pCDS->nComment); - zipfileWrite16(a, pCDS->iDiskStart); - zipfileWrite16(a, pCDS->iInternalAttr); - zipfileWrite32(a, pCDS->iExternalAttr); - zipfileWrite32(a, pCDS->iOffset); - - memcpy(a, pCDS->zFile, pCDS->nFile); - a += pCDS->nFile; - - if( pEntry->aExtra ){ - int n = (int)pCDS->nExtra + (int)pCDS->nComment; - memcpy(a, pEntry->aExtra, n); - a += n; - }else{ - assert( pCDS->nExtra==9 ); - zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP); - zipfileWrite16(a, 5); - *a++ = 0x01; - zipfileWrite32(a, pEntry->mUnixTime); - } + u8 *a = aBuf; + ZipfileCDS *pCDS = &pEntry->cds; + + if( pEntry->aExtra==0 ){ + pCDS->nExtra = 9; + } + + zipfileWrite32(a, ZIPFILE_SIGNATURE_CDS); + zipfileWrite16(a, pCDS->iVersionMadeBy); + zipfileWrite16(a, pCDS->iVersionExtract); + zipfileWrite16(a, pCDS->flags); + zipfileWrite16(a, pCDS->iCompression); + zipfileWrite16(a, pCDS->mTime); + zipfileWrite16(a, pCDS->mDate); + zipfileWrite32(a, pCDS->crc32); + zipfileWrite32(a, pCDS->szCompressed); + zipfileWrite32(a, pCDS->szUncompressed); + assert( a==&aBuf[ZIPFILE_CDS_NFILE_OFF] ); + zipfileWrite16(a, pCDS->nFile); + zipfileWrite16(a, pCDS->nExtra); + zipfileWrite16(a, pCDS->nComment); + zipfileWrite16(a, pCDS->iDiskStart); + zipfileWrite16(a, pCDS->iInternalAttr); + zipfileWrite32(a, pCDS->iExternalAttr); + zipfileWrite32(a, pCDS->iOffset); + + memcpy(a, pCDS->zFile, pCDS->nFile); + a += pCDS->nFile; + + if( pEntry->aExtra ){ + int n = (int)pCDS->nExtra + (int)pCDS->nComment; + memcpy(a, pEntry->aExtra, n); + a += n; + }else{ + assert( pCDS->nExtra==9 ); + zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP); + zipfileWrite16(a, 5); + *a++ = 0x01; + zipfileWrite32(a, pEntry->mUnixTime); + } - return a-aBuf; + return a-aBuf; } static int zipfileCommit(sqlite3_vtab *pVtab){ - ZipfileTab *pTab = (ZipfileTab*)pVtab; - int rc = SQLITE_OK; - if( pTab->pWriteFd ){ - i64 iOffset = pTab->szCurrent; - ZipfileEntry *p; - ZipfileEOCD eocd; - int nEntry = 0; - - /* Write out all entries */ - for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){ - int n = zipfileSerializeCDS(p, pTab->aBuffer); - rc = zipfileAppendData(pTab, pTab->aBuffer, n); - nEntry++; - } - - /* Write out the EOCD record */ - eocd.iDisk = 0; - eocd.iFirstDisk = 0; - eocd.nEntry = (u16)nEntry; - eocd.nEntryTotal = (u16)nEntry; - eocd.nSize = (u32)(pTab->szCurrent - iOffset); - eocd.iOffset = (u32)iOffset; - rc = zipfileAppendEOCD(pTab, &eocd); + ZipfileTab *pTab = (ZipfileTab*)pVtab; + int rc = SQLITE_OK; + if( pTab->pWriteFd ){ + i64 iOffset = pTab->szCurrent; + ZipfileEntry *p; + ZipfileEOCD eocd; + int nEntry = 0; - zipfileCleanupTransaction(pTab); + /* Write out all entries */ + for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){ + int n = zipfileSerializeCDS(p, pTab->aBuffer); + rc = zipfileAppendData(pTab, pTab->aBuffer, n); + nEntry++; } - return rc; + + /* Write out the EOCD record */ + eocd.iDisk = 0; + eocd.iFirstDisk = 0; + eocd.nEntry = (u16)nEntry; + eocd.nEntryTotal = (u16)nEntry; + eocd.nSize = (u32)(pTab->szCurrent - iOffset); + eocd.iOffset = (u32)iOffset; + rc = zipfileAppendEOCD(pTab, &eocd); + + zipfileCleanupTransaction(pTab); + } + return rc; } static int zipfileRollback(sqlite3_vtab *pVtab){ - return zipfileCommit(pVtab); + return zipfileCommit(pVtab); } static ZipfileCsr *zipfileFindCursor(ZipfileTab *pTab, i64 iId){ - ZipfileCsr *pCsr; - for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){ - if( iId==pCsr->iId ) break; - } - return pCsr; + ZipfileCsr *pCsr; + for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){ + if( iId==pCsr->iId ) break; + } + return pCsr; } static void zipfileFunctionCds( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - ZipfileCsr *pCsr; - ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context); - assert( argc>0 ); - - pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0])); - if( pCsr ){ - ZipfileCDS *p = &pCsr->pCurrent->cds; - char *zRes = sqlite3_mprintf("{" - "\"version-made-by\" : %u, " - "\"version-to-extract\" : %u, " - "\"flags\" : %u, " - "\"compression\" : %u, " - "\"time\" : %u, " - "\"date\" : %u, " - "\"crc32\" : %u, " - "\"compressed-size\" : %u, " - "\"uncompressed-size\" : %u, " - "\"file-name-length\" : %u, " - "\"extra-field-length\" : %u, " - "\"file-comment-length\" : %u, " - "\"disk-number-start\" : %u, " - "\"internal-attr\" : %u, " - "\"external-attr\" : %u, " - "\"offset\" : %u }", - (u32)p->iVersionMadeBy, (u32)p->iVersionExtract, - (u32)p->flags, (u32)p->iCompression, - (u32)p->mTime, (u32)p->mDate, - (u32)p->crc32, (u32)p->szCompressed, - (u32)p->szUncompressed, (u32)p->nFile, - (u32)p->nExtra, (u32)p->nComment, - (u32)p->iDiskStart, (u32)p->iInternalAttr, - (u32)p->iExternalAttr, (u32)p->iOffset - ); + ZipfileCsr *pCsr; + ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context); + assert( argc>0 ); + + pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0])); + if( pCsr ){ + ZipfileCDS *p = &pCsr->pCurrent->cds; + char *zRes = sqlite3_mprintf("{" + "\"version-made-by\" : %u, " + "\"version-to-extract\" : %u, " + "\"flags\" : %u, " + "\"compression\" : %u, " + "\"time\" : %u, " + "\"date\" : %u, " + "\"crc32\" : %u, " + "\"compressed-size\" : %u, " + "\"uncompressed-size\" : %u, " + "\"file-name-length\" : %u, " + "\"extra-field-length\" : %u, " + "\"file-comment-length\" : %u, " + "\"disk-number-start\" : %u, " + "\"internal-attr\" : %u, " + "\"external-attr\" : %u, " + "\"offset\" : %u }", + (u32)p->iVersionMadeBy, (u32)p->iVersionExtract, + (u32)p->flags, (u32)p->iCompression, + (u32)p->mTime, (u32)p->mDate, + (u32)p->crc32, (u32)p->szCompressed, + (u32)p->szUncompressed, (u32)p->nFile, + (u32)p->nExtra, (u32)p->nComment, + (u32)p->iDiskStart, (u32)p->iInternalAttr, + (u32)p->iExternalAttr, (u32)p->iOffset + ); - if( zRes==0 ){ - sqlite3_result_error_nomem(context); - }else{ - sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); - sqlite3_free(zRes); - } + if( zRes==0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT); + sqlite3_free(zRes); } + } } /* ** xFindFunction method. */ static int zipfileFindFunction( - sqlite3_vtab *pVtab, /* Virtual table handle */ - int nArg, /* Number of SQL function arguments */ - const char *zName, /* Name of SQL function */ - void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ - void **ppArg /* OUT: User data for *pxFunc */ + sqlite3_vtab *pVtab, /* Virtual table handle */ + int nArg, /* Number of SQL function arguments */ + const char *zName, /* Name of SQL function */ + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ + void **ppArg /* OUT: User data for *pxFunc */ ){ - if( sqlite3_stricmp("zipfile_cds", zName)==0 ){ - *pxFunc = zipfileFunctionCds; - *ppArg = (void*)pVtab; - return 1; - } - return 0; + if( sqlite3_stricmp("zipfile_cds", zName)==0 ){ + *pxFunc = zipfileFunctionCds; + *ppArg = (void*)pVtab; + return 1; + } + return 0; } typedef struct ZipfileBuffer ZipfileBuffer; struct ZipfileBuffer { - u8 *a; /* Pointer to buffer */ - int n; /* Size of buffer in bytes */ - int nAlloc; /* Byte allocated at a[] */ + u8 *a; /* Pointer to buffer */ + int n; /* Size of buffer in bytes */ + int nAlloc; /* Byte allocated at a[] */ }; typedef struct ZipfileCtx ZipfileCtx; struct ZipfileCtx { - int nEntry; - ZipfileBuffer body; - ZipfileBuffer cds; + int nEntry; + ZipfileBuffer body; + ZipfileBuffer cds; }; static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){ - if( pBuf->n+nByte>pBuf->nAlloc ){ - u8 *aNew; - sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512; - int nReq = pBuf->n + nByte; + if( pBuf->n+nByte>pBuf->nAlloc ){ + u8 *aNew; + sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512; + int nReq = pBuf->n + nByte; - while( nNewa, nNew); - if( aNew==0 ) return SQLITE_NOMEM; - pBuf->a = aNew; - pBuf->nAlloc = (int)nNew; - } - return SQLITE_OK; + while( nNewa, nNew); + if( aNew==0 ) return SQLITE_NOMEM; + pBuf->a = aNew; + pBuf->nAlloc = (int)nNew; + } + return SQLITE_OK; } /* @@ -8678,209 +8678,209 @@ static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){ ** SELECT zipfile(name,mode,mtime,data,method) ... */ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){ - ZipfileCtx *p; /* Aggregate function context */ - ZipfileEntry e; /* New entry to add to zip archive */ - - sqlite3_value *pName = 0; - sqlite3_value *pMode = 0; - sqlite3_value *pMtime = 0; - sqlite3_value *pData = 0; - sqlite3_value *pMethod = 0; - - int bIsDir = 0; - u32 mode; - int rc = SQLITE_OK; - char *zErr = 0; - - int iMethod = -1; /* Compression method to use (0 or 8) */ - - const u8 *aData = 0; /* Possibly compressed data for new entry */ - int nData = 0; /* Size of aData[] in bytes */ - int szUncompressed = 0; /* Size of data before compression */ - u8 *aFree = 0; /* Free this before returning */ - u32 iCrc32 = 0; /* crc32 of uncompressed data */ - - char *zName = 0; /* Path (name) of new entry */ - int nName = 0; /* Size of zName in bytes */ - char *zFree = 0; /* Free this before returning */ - int nByte; - - memset(&e, 0, sizeof(e)); - p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx)); - if( p==0 ) return; - - /* Martial the arguments into stack variables */ - if( nVal!=2 && nVal!=4 && nVal!=5 ){ - zErr = sqlite3_mprintf("wrong number of arguments to function zipfile()"); - rc = SQLITE_ERROR; - goto zipfile_step_out; - } - pName = apVal[0]; - if( nVal==2 ){ - pData = apVal[1]; - }else{ - pMode = apVal[1]; - pMtime = apVal[2]; - pData = apVal[3]; - if( nVal==5 ){ - pMethod = apVal[4]; - } - } - - /* Check that the 'name' parameter looks ok. */ - zName = (char*)sqlite3_value_text(pName); - nName = sqlite3_value_bytes(pName); - if( zName==0 ){ - zErr = sqlite3_mprintf("first argument to zipfile() must be non-NULL"); - rc = SQLITE_ERROR; - goto zipfile_step_out; - } - - /* Inspect the 'method' parameter. This must be either 0 (store), 8 (use + ZipfileCtx *p; /* Aggregate function context */ + ZipfileEntry e; /* New entry to add to zip archive */ + + sqlite3_value *pName = 0; + sqlite3_value *pMode = 0; + sqlite3_value *pMtime = 0; + sqlite3_value *pData = 0; + sqlite3_value *pMethod = 0; + + int bIsDir = 0; + u32 mode; + int rc = SQLITE_OK; + char *zErr = 0; + + int iMethod = -1; /* Compression method to use (0 or 8) */ + + const u8 *aData = 0; /* Possibly compressed data for new entry */ + int nData = 0; /* Size of aData[] in bytes */ + int szUncompressed = 0; /* Size of data before compression */ + u8 *aFree = 0; /* Free this before returning */ + u32 iCrc32 = 0; /* crc32 of uncompressed data */ + + char *zName = 0; /* Path (name) of new entry */ + int nName = 0; /* Size of zName in bytes */ + char *zFree = 0; /* Free this before returning */ + int nByte; + + memset(&e, 0, sizeof(e)); + p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx)); + if( p==0 ) return; + + /* Martial the arguments into stack variables */ + if( nVal!=2 && nVal!=4 && nVal!=5 ){ + zErr = sqlite3_mprintf("wrong number of arguments to function zipfile()"); + rc = SQLITE_ERROR; + goto zipfile_step_out; + } + pName = apVal[0]; + if( nVal==2 ){ + pData = apVal[1]; + }else{ + pMode = apVal[1]; + pMtime = apVal[2]; + pData = apVal[3]; + if( nVal==5 ){ + pMethod = apVal[4]; + } + } + + /* Check that the 'name' parameter looks ok. */ + zName = (char*)sqlite3_value_text(pName); + nName = sqlite3_value_bytes(pName); + if( zName==0 ){ + zErr = sqlite3_mprintf("first argument to zipfile() must be non-NULL"); + rc = SQLITE_ERROR; + goto zipfile_step_out; + } + + /* Inspect the 'method' parameter. This must be either 0 (store), 8 (use ** deflate compression) or NULL (choose automatically). */ - if( pMethod && SQLITE_NULL!=sqlite3_value_type(pMethod) ){ - iMethod = (int)sqlite3_value_int64(pMethod); - if( iMethod!=0 && iMethod!=8 ){ - zErr = sqlite3_mprintf("illegal method value: %d", iMethod); - rc = SQLITE_ERROR; - goto zipfile_step_out; - } + if( pMethod && SQLITE_NULL!=sqlite3_value_type(pMethod) ){ + iMethod = (int)sqlite3_value_int64(pMethod); + if( iMethod!=0 && iMethod!=8 ){ + zErr = sqlite3_mprintf("illegal method value: %d", iMethod); + rc = SQLITE_ERROR; + goto zipfile_step_out; } + } - /* Now inspect the data. If this is NULL, then the new entry must be a + /* Now inspect the data. If this is NULL, then the new entry must be a ** directory. Otherwise, figure out whether or not the data should ** be deflated or simply stored in the zip archive. */ - if( sqlite3_value_type(pData)==SQLITE_NULL ){ - bIsDir = 1; + if( sqlite3_value_type(pData)==SQLITE_NULL ){ + bIsDir = 1; + iMethod = 0; + }else{ + aData = sqlite3_value_blob(pData); + szUncompressed = nData = sqlite3_value_bytes(pData); + iCrc32 = crc32(0, aData, nData); + if( iMethod<0 || iMethod==8 ){ + int nOut = 0; + rc = zipfileDeflate(aData, nData, &aFree, &nOut, &zErr); + if( rc!=SQLITE_OK ){ + goto zipfile_step_out; + } + if( iMethod==8 || nOut0 && zName[nName-1]=='/' ){ - zErr = sqlite3_mprintf("non-directory name must not end with /"); - rc = SQLITE_ERROR; - goto zipfile_step_out; - } + if( bIsDir==0 ){ + if( nName>0 && zName[nName-1]=='/' ){ + zErr = sqlite3_mprintf("non-directory name must not end with /"); + rc = SQLITE_ERROR; + goto zipfile_step_out; + } + }else{ + if( nName==0 || zName[nName-1]!='/' ){ + zName = zFree = sqlite3_mprintf("%s/", zName); + if( zName==0 ){ + rc = SQLITE_NOMEM; + goto zipfile_step_out; + } + nName = (int)strlen(zName); }else{ - if( nName==0 || zName[nName-1]!='/' ){ - zName = zFree = sqlite3_mprintf("%s/", zName); - if( zName==0 ){ - rc = SQLITE_NOMEM; - goto zipfile_step_out; - } - nName = (int)strlen(zName); - }else{ - while( nName>1 && zName[nName-2]=='/' ) nName--; - } - } - - /* Assemble the ZipfileEntry object for the new zip archive entry */ - e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; - e.cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED; - e.cds.flags = ZIPFILE_NEWENTRY_FLAGS; - e.cds.iCompression = (u16)iMethod; - zipfileMtimeToDos(&e.cds, (u32)e.mUnixTime); - e.cds.crc32 = iCrc32; - e.cds.szCompressed = nData; - e.cds.szUncompressed = szUncompressed; - e.cds.iExternalAttr = (mode<<16); - e.cds.iOffset = p->body.n; - e.cds.nFile = (u16)nName; - e.cds.zFile = zName; - - /* Append the LFH to the body of the new archive */ - nByte = ZIPFILE_LFH_FIXED_SZ + e.cds.nFile + 9; - if( (rc = zipfileBufferGrow(&p->body, nByte)) ) goto zipfile_step_out; - p->body.n += zipfileSerializeLFH(&e, &p->body.a[p->body.n]); - - /* Append the data to the body of the new archive */ - if( nData>0 ){ - if( (rc = zipfileBufferGrow(&p->body, nData)) ) goto zipfile_step_out; - memcpy(&p->body.a[p->body.n], aData, nData); - p->body.n += nData; - } - - /* Append the CDS record to the directory of the new archive */ - nByte = ZIPFILE_CDS_FIXED_SZ + e.cds.nFile + 9; - if( (rc = zipfileBufferGrow(&p->cds, nByte)) ) goto zipfile_step_out; - p->cds.n += zipfileSerializeCDS(&e, &p->cds.a[p->cds.n]); - - /* Increment the count of entries in the archive */ - p->nEntry++; - -zipfile_step_out: - sqlite3_free(aFree); - sqlite3_free(zFree); - if( rc ){ - if( zErr ){ - sqlite3_result_error(pCtx, zErr, -1); - }else{ - sqlite3_result_error_code(pCtx, rc); - } + while( nName>1 && zName[nName-2]=='/' ) nName--; + } + } + + /* Assemble the ZipfileEntry object for the new zip archive entry */ + e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; + e.cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED; + e.cds.flags = ZIPFILE_NEWENTRY_FLAGS; + e.cds.iCompression = (u16)iMethod; + zipfileMtimeToDos(&e.cds, (u32)e.mUnixTime); + e.cds.crc32 = iCrc32; + e.cds.szCompressed = nData; + e.cds.szUncompressed = szUncompressed; + e.cds.iExternalAttr = (mode<<16); + e.cds.iOffset = p->body.n; + e.cds.nFile = (u16)nName; + e.cds.zFile = zName; + + /* Append the LFH to the body of the new archive */ + nByte = ZIPFILE_LFH_FIXED_SZ + e.cds.nFile + 9; + if( (rc = zipfileBufferGrow(&p->body, nByte)) ) goto zipfile_step_out; + p->body.n += zipfileSerializeLFH(&e, &p->body.a[p->body.n]); + + /* Append the data to the body of the new archive */ + if( nData>0 ){ + if( (rc = zipfileBufferGrow(&p->body, nData)) ) goto zipfile_step_out; + memcpy(&p->body.a[p->body.n], aData, nData); + p->body.n += nData; + } + + /* Append the CDS record to the directory of the new archive */ + nByte = ZIPFILE_CDS_FIXED_SZ + e.cds.nFile + 9; + if( (rc = zipfileBufferGrow(&p->cds, nByte)) ) goto zipfile_step_out; + p->cds.n += zipfileSerializeCDS(&e, &p->cds.a[p->cds.n]); + + /* Increment the count of entries in the archive */ + p->nEntry++; + + zipfile_step_out: + sqlite3_free(aFree); + sqlite3_free(zFree); + if( rc ){ + if( zErr ){ + sqlite3_result_error(pCtx, zErr, -1); + }else{ + sqlite3_result_error_code(pCtx, rc); } - sqlite3_free(zErr); + } + sqlite3_free(zErr); } /* ** xFinalize() callback for zipfile aggregate function. */ void zipfileFinal(sqlite3_context *pCtx){ - ZipfileCtx *p; - ZipfileEOCD eocd; - sqlite3_int64 nZip; - u8 *aZip; - - p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx)); - if( p==0 ) return; - if( p->nEntry>0 ){ - memset(&eocd, 0, sizeof(eocd)); - eocd.nEntry = (u16)p->nEntry; - eocd.nEntryTotal = (u16)p->nEntry; - eocd.nSize = p->cds.n; - eocd.iOffset = p->body.n; - - nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ; - aZip = (u8*)sqlite3_malloc64(nZip); - if( aZip==0 ){ - sqlite3_result_error_nomem(pCtx); - }else{ - memcpy(aZip, p->body.a, p->body.n); - memcpy(&aZip[p->body.n], p->cds.a, p->cds.n); - zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]); - sqlite3_result_blob(pCtx, aZip, (int)nZip, zipfileFree); - } + ZipfileCtx *p; + ZipfileEOCD eocd; + sqlite3_int64 nZip; + u8 *aZip; + + p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx)); + if( p==0 ) return; + if( p->nEntry>0 ){ + memset(&eocd, 0, sizeof(eocd)); + eocd.nEntry = (u16)p->nEntry; + eocd.nEntryTotal = (u16)p->nEntry; + eocd.nSize = p->cds.n; + eocd.iOffset = p->body.n; + + nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ; + aZip = (u8*)sqlite3_malloc64(nZip); + if( aZip==0 ){ + sqlite3_result_error_nomem(pCtx); + }else{ + memcpy(aZip, p->body.a, p->body.n); + memcpy(&aZip[p->body.n], p->cds.a, p->cds.n); + zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]); + sqlite3_result_blob(pCtx, aZip, (int)nZip, zipfileFree); } + } - sqlite3_free(p->body.a); - sqlite3_free(p->cds.a); + sqlite3_free(p->body.a); + sqlite3_free(p->cds.a); } @@ -8888,41 +8888,41 @@ void zipfileFinal(sqlite3_context *pCtx){ ** Register the "zipfile" virtual table. */ static int zipfileRegister(sqlite3 *db){ - static sqlite3_module zipfileModule = { - 1, /* iVersion */ - zipfileConnect, /* xCreate */ - zipfileConnect, /* xConnect */ - zipfileBestIndex, /* xBestIndex */ - zipfileDisconnect, /* xDisconnect */ - zipfileDisconnect, /* xDestroy */ - zipfileOpen, /* xOpen - open a cursor */ - zipfileClose, /* xClose - close a cursor */ - zipfileFilter, /* xFilter - configure scan constraints */ - zipfileNext, /* xNext - advance a cursor */ - zipfileEof, /* xEof - check for end of scan */ - zipfileColumn, /* xColumn - read data */ - 0, /* xRowid - read data */ - zipfileUpdate, /* xUpdate */ - zipfileBegin, /* xBegin */ - 0, /* xSync */ - zipfileCommit, /* xCommit */ - zipfileRollback, /* xRollback */ - zipfileFindFunction, /* xFindMethod */ - 0, /* xRename */ - }; + static sqlite3_module zipfileModule = { + 1, /* iVersion */ + zipfileConnect, /* xCreate */ + zipfileConnect, /* xConnect */ + zipfileBestIndex, /* xBestIndex */ + zipfileDisconnect, /* xDisconnect */ + zipfileDisconnect, /* xDestroy */ + zipfileOpen, /* xOpen - open a cursor */ + zipfileClose, /* xClose - close a cursor */ + zipfileFilter, /* xFilter - configure scan constraints */ + zipfileNext, /* xNext - advance a cursor */ + zipfileEof, /* xEof - check for end of scan */ + zipfileColumn, /* xColumn - read data */ + 0, /* xRowid - read data */ + zipfileUpdate, /* xUpdate */ + zipfileBegin, /* xBegin */ + 0, /* xSync */ + zipfileCommit, /* xCommit */ + zipfileRollback, /* xRollback */ + zipfileFindFunction, /* xFindMethod */ + 0, /* xRename */ + }; - int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0); - if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0, - zipfileStep, zipfileFinal - ); - } - assert( sizeof(i64)==8 ); - assert( sizeof(u32)==4 ); - assert( sizeof(u16)==2 ); - assert( sizeof(u8)==1 ); - return rc; + int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0); + if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0, + zipfileStep, zipfileFinal + ); + } + assert( sizeof(i64)==8 ); + assert( sizeof(u32)==4 ); + assert( sizeof(u16)==2 ); + assert( sizeof(u8)==1 ); + return rc; } #else /* SQLITE_OMIT_VIRTUALTABLE */ # define zipfileRegister(x) SQLITE_OK @@ -8932,13 +8932,13 @@ static int zipfileRegister(sqlite3 *db){ #endif int sqlite3_zipfile_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - SQLITE_EXTENSION_INIT2(pApi); - (void)pzErrMsg; /* Unused parameter */ - return zipfileRegister(db); + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* Unused parameter */ + return zipfileRegister(db); } /************************* End ../ext/misc/zipfile.c ********************/ @@ -8980,34 +8980,34 @@ SQLITE_EXTENSION_INIT1 ** compressed data. */ static void sqlarCompressFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - assert( argc==1 ); - if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ - const Bytef *pData = sqlite3_value_blob(argv[0]); - uLong nData = sqlite3_value_bytes(argv[0]); - uLongf nOut = compressBound(nData); - Bytef *pOut; - - pOut = (Bytef*)sqlite3_malloc(nOut); - if( pOut==0 ){ - sqlite3_result_error_nomem(context); - return; - }else{ - if( Z_OK!=compress(pOut, &nOut, pData, nData) ){ - sqlite3_result_error(context, "error in compress()", -1); - }else if( nOut DESC */ - IdxConstraint *pNext; /* Next constraint in pEq or pRange list */ - IdxConstraint *pLink; /* See above */ + char *zColl; /* Collation sequence */ + int bRange; /* True for range, false for eq */ + int iCol; /* Constrained table column */ + int bFlag; /* Used by idxFindCompatible() */ + int bDesc; /* True if ORDER BY DESC */ + IdxConstraint *pNext; /* Next constraint in pEq or pRange list */ + IdxConstraint *pLink; /* See above */ }; /* ** A single scan of a single table. */ struct IdxScan { - IdxTable *pTab; /* Associated table object */ - int iDb; /* Database containing table zTable */ - i64 covering; /* Mask of columns required for cov. index */ - IdxConstraint *pOrder; /* ORDER BY columns */ - IdxConstraint *pEq; /* List of == constraints */ - IdxConstraint *pRange; /* List of < constraints */ - IdxScan *pNextScan; /* Next IdxScan object for same analysis */ + IdxTable *pTab; /* Associated table object */ + int iDb; /* Database containing table zTable */ + i64 covering; /* Mask of columns required for cov. index */ + IdxConstraint *pOrder; /* ORDER BY columns */ + IdxConstraint *pEq; /* List of == constraints */ + IdxConstraint *pRange; /* List of < constraints */ + IdxScan *pNextScan; /* Next IdxScan object for same analysis */ }; /* -** Information regarding a single database table. Extracted from +** Information regarding a single database table. Extracted from ** "PRAGMA table_info" by function idxGetTableInfo(). */ struct IdxColumn { - char *zName; - char *zColl; - int iPk; + char *zName; + char *zColl; + int iPk; }; struct IdxTable { - int nCol; - char *zName; /* Table name */ - IdxColumn *aCol; - IdxTable *pNext; /* Next table in linked list of all tables */ + int nCol; + char *zName; /* Table name */ + IdxColumn *aCol; + IdxTable *pNext; /* Next table in linked list of all tables */ }; /* @@ -9350,9 +9350,9 @@ struct IdxTable { ** sqlite3expert.pWrite. */ struct IdxWrite { - IdxTable *pTab; - int eOp; /* SQLITE_UPDATE, DELETE or INSERT */ - IdxWrite *pNext; + IdxTable *pTab; + int eOp; /* SQLITE_UPDATE, DELETE or INSERT */ + IdxWrite *pNext; }; /* @@ -9360,11 +9360,11 @@ struct IdxWrite { ** structure. */ struct IdxStatement { - int iId; /* Statement number */ - char *zSql; /* SQL statement */ - char *zIdx; /* Indexes */ - char *zEQP; /* Plan */ - IdxStatement *pNext; + int iId; /* Statement number */ + char *zSql; /* SQL statement */ + char *zIdx; /* Indexes */ + char *zEQP; /* Plan */ + IdxStatement *pNext; }; @@ -9381,76 +9381,76 @@ struct IdxStatement { typedef struct IdxHashEntry IdxHashEntry; typedef struct IdxHash IdxHash; struct IdxHashEntry { - char *zKey; /* nul-terminated key */ - char *zVal; /* nul-terminated value string */ - char *zVal2; /* nul-terminated value string 2 */ - IdxHashEntry *pHashNext; /* Next entry in same hash bucket */ - IdxHashEntry *pNext; /* Next entry in hash */ + char *zKey; /* nul-terminated key */ + char *zVal; /* nul-terminated value string */ + char *zVal2; /* nul-terminated value string 2 */ + IdxHashEntry *pHashNext; /* Next entry in same hash bucket */ + IdxHashEntry *pNext; /* Next entry in hash */ }; struct IdxHash { - IdxHashEntry *pFirst; - IdxHashEntry *aHash[IDX_HASH_SIZE]; + IdxHashEntry *pFirst; + IdxHashEntry *aHash[IDX_HASH_SIZE]; }; /* ** sqlite3expert object. */ struct sqlite3expert { - int iSample; /* Percentage of tables to sample for stat1 */ - sqlite3 *db; /* User database */ - sqlite3 *dbm; /* In-memory db for this analysis */ - sqlite3 *dbv; /* Vtab schema for this analysis */ - IdxTable *pTable; /* List of all IdxTable objects */ - IdxScan *pScan; /* List of scan objects */ - IdxWrite *pWrite; /* List of write objects */ - IdxStatement *pStatement; /* List of IdxStatement objects */ - int bRun; /* True once analysis has run */ - char **pzErrmsg; - int rc; /* Error code from whereinfo hook */ - IdxHash hIdx; /* Hash containing all candidate indexes */ - char *zCandidates; /* For EXPERT_REPORT_CANDIDATES */ + int iSample; /* Percentage of tables to sample for stat1 */ + sqlite3 *db; /* User database */ + sqlite3 *dbm; /* In-memory db for this analysis */ + sqlite3 *dbv; /* Vtab schema for this analysis */ + IdxTable *pTable; /* List of all IdxTable objects */ + IdxScan *pScan; /* List of scan objects */ + IdxWrite *pWrite; /* List of write objects */ + IdxStatement *pStatement; /* List of IdxStatement objects */ + int bRun; /* True once analysis has run */ + char **pzErrmsg; + int rc; /* Error code from whereinfo hook */ + IdxHash hIdx; /* Hash containing all candidate indexes */ + char *zCandidates; /* For EXPERT_REPORT_CANDIDATES */ }; /* -** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc(). +** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc(). ** If the allocation fails, set *pRc to SQLITE_NOMEM and return NULL. */ static void *idxMalloc(int *pRc, int nByte){ - void *pRet; - assert( *pRc==SQLITE_OK ); - assert( nByte>0 ); - pRet = sqlite3_malloc(nByte); - if( pRet ){ - memset(pRet, 0, nByte); - }else{ - *pRc = SQLITE_NOMEM; - } - return pRet; + void *pRet; + assert( *pRc==SQLITE_OK ); + assert( nByte>0 ); + pRet = sqlite3_malloc(nByte); + if( pRet ){ + memset(pRet, 0, nByte); + }else{ + *pRc = SQLITE_NOMEM; + } + return pRet; } /* ** Initialize an IdxHash hash table. */ static void idxHashInit(IdxHash *pHash){ - memset(pHash, 0, sizeof(IdxHash)); + memset(pHash, 0, sizeof(IdxHash)); } /* ** Reset an IdxHash hash table. */ static void idxHashClear(IdxHash *pHash){ - int i; - for(i=0; iaHash[i]; pEntry; pEntry=pNext){ - pNext = pEntry->pHashNext; - sqlite3_free(pEntry->zVal2); - sqlite3_free(pEntry); - } + int i; + for(i=0; iaHash[i]; pEntry; pEntry=pNext){ + pNext = pEntry->pHashNext; + sqlite3_free(pEntry->zVal2); + sqlite3_free(pEntry); } - memset(pHash, 0, sizeof(IdxHash)); + } + memset(pHash, 0, sizeof(IdxHash)); } /* @@ -9458,68 +9458,68 @@ static void idxHashClear(IdxHash *pHash){ ** arguments to this function belongs. */ static int idxHashString(const char *z, int n){ - unsigned int ret = 0; - int i; - for(i=0; i=0 ); - for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){ - if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){ - return 1; - } - } - pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + nKey+1 + nVal+1); - if( pEntry ){ - pEntry->zKey = (char*)&pEntry[1]; - memcpy(pEntry->zKey, zKey, nKey); - if( zVal ){ - pEntry->zVal = &pEntry->zKey[nKey+1]; - memcpy(pEntry->zVal, zVal, nVal); - } - pEntry->pHashNext = pHash->aHash[iHash]; - pHash->aHash[iHash] = pEntry; - - pEntry->pNext = pHash->pFirst; - pHash->pFirst = pEntry; - } - return 0; -} - -/* -** If zKey/nKey is present in the hash table, return a pointer to the + int nKey = STRLEN(zKey); + int iHash = idxHashString(zKey, nKey); + int nVal = (zVal ? STRLEN(zVal) : 0); + IdxHashEntry *pEntry; + assert( iHash>=0 ); + for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){ + if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){ + return 1; + } + } + pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + nKey+1 + nVal+1); + if( pEntry ){ + pEntry->zKey = (char*)&pEntry[1]; + memcpy(pEntry->zKey, zKey, nKey); + if( zVal ){ + pEntry->zVal = &pEntry->zKey[nKey+1]; + memcpy(pEntry->zVal, zVal, nVal); + } + pEntry->pHashNext = pHash->aHash[iHash]; + pHash->aHash[iHash] = pEntry; + + pEntry->pNext = pHash->pFirst; + pHash->pFirst = pEntry; + } + return 0; +} + +/* +** If zKey/nKey is present in the hash table, return a pointer to the ** hash-entry object. */ static IdxHashEntry *idxHashFind(IdxHash *pHash, const char *zKey, int nKey){ - int iHash; - IdxHashEntry *pEntry; - if( nKey<0 ) nKey = STRLEN(zKey); - iHash = idxHashString(zKey, nKey); - assert( iHash>=0 ); - for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){ - if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){ - return pEntry; - } + int iHash; + IdxHashEntry *pEntry; + if( nKey<0 ) nKey = STRLEN(zKey); + iHash = idxHashString(zKey, nKey); + assert( iHash>=0 ); + for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){ + if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){ + return pEntry; } - return 0; + } + return 0; } /* @@ -9529,9 +9529,9 @@ static IdxHashEntry *idxHashFind(IdxHash *pHash, const char *zKey, int nKey){ ** hash table, return NULL. */ static const char *idxHashSearch(IdxHash *pHash, const char *zKey, int nKey){ - IdxHashEntry *pEntry = idxHashFind(pHash, zKey, nKey); - if( pEntry ) return pEntry->zVal; - return 0; + IdxHashEntry *pEntry = idxHashFind(pHash, zKey, nKey); + if( pEntry ) return pEntry->zVal; + return 0; } /* @@ -9539,16 +9539,16 @@ static const char *idxHashSearch(IdxHash *pHash, const char *zKey, int nKey){ ** variable to point to a copy of nul-terminated string zColl. */ static IdxConstraint *idxNewConstraint(int *pRc, const char *zColl){ - IdxConstraint *pNew; - int nColl = STRLEN(zColl); + IdxConstraint *pNew; + int nColl = STRLEN(zColl); - assert( *pRc==SQLITE_OK ); - pNew = (IdxConstraint*)idxMalloc(pRc, sizeof(IdxConstraint) * nColl + 1); - if( pNew ){ - pNew->zColl = (char*)&pNew[1]; - memcpy(pNew->zColl, zColl, nColl+1); - } - return pNew; + assert( *pRc==SQLITE_OK ); + pNew = (IdxConstraint*)idxMalloc(pRc, sizeof(IdxConstraint) * nColl + 1); + if( pNew ){ + pNew->zColl = (char*)&pNew[1]; + memcpy(pNew->zColl, zColl, nColl+1); + } + return pNew; } /* @@ -9556,52 +9556,52 @@ static IdxConstraint *idxNewConstraint(int *pRc, const char *zColl){ ** the error message to callback function xOut. */ static void idxDatabaseError( - sqlite3 *db, /* Database handle */ - char **pzErrmsg /* Write error here */ + sqlite3 *db, /* Database handle */ + char **pzErrmsg /* Write error here */ ){ - *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } /* ** Prepare an SQL statement. */ static int idxPrepareStmt( - sqlite3 *db, /* Database handle to compile against */ - sqlite3_stmt **ppStmt, /* OUT: Compiled SQL statement */ - char **pzErrmsg, /* OUT: sqlite3_malloc()ed error message */ - const char *zSql /* SQL statement to compile */ + sqlite3 *db, /* Database handle to compile against */ + sqlite3_stmt **ppStmt, /* OUT: Compiled SQL statement */ + char **pzErrmsg, /* OUT: sqlite3_malloc()ed error message */ + const char *zSql /* SQL statement to compile */ ){ - int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); - if( rc!=SQLITE_OK ){ - *ppStmt = 0; - idxDatabaseError(db, pzErrmsg); - } - return rc; + int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); + if( rc!=SQLITE_OK ){ + *ppStmt = 0; + idxDatabaseError(db, pzErrmsg); + } + return rc; } /* ** Prepare an SQL statement using the results of a printf() formatting. */ static int idxPrintfPrepareStmt( - sqlite3 *db, /* Database handle to compile against */ - sqlite3_stmt **ppStmt, /* OUT: Compiled SQL statement */ - char **pzErrmsg, /* OUT: sqlite3_malloc()ed error message */ - const char *zFmt, /* printf() format of SQL statement */ - ... /* Trailing printf() arguments */ + sqlite3 *db, /* Database handle to compile against */ + sqlite3_stmt **ppStmt, /* OUT: Compiled SQL statement */ + char **pzErrmsg, /* OUT: sqlite3_malloc()ed error message */ + const char *zFmt, /* printf() format of SQL statement */ + ... /* Trailing printf() arguments */ ){ - va_list ap; - int rc; - char *zSql; - va_start(ap, zFmt); - zSql = sqlite3_vmprintf(zFmt, ap); - if( zSql==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = idxPrepareStmt(db, ppStmt, pzErrmsg, zSql); - sqlite3_free(zSql); - } - va_end(ap); - return rc; + va_list ap; + int rc; + char *zSql; + va_start(ap, zFmt); + zSql = sqlite3_vmprintf(zFmt, ap); + if( zSql==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = idxPrepareStmt(db, ppStmt, pzErrmsg, zSql); + sqlite3_free(zSql); + } + va_end(ap); + return rc; } @@ -9610,41 +9610,41 @@ static int idxPrintfPrepareStmt( */ typedef struct ExpertVtab ExpertVtab; struct ExpertVtab { - sqlite3_vtab base; - IdxTable *pTab; - sqlite3expert *pExpert; + sqlite3_vtab base; + IdxTable *pTab; + sqlite3expert *pExpert; }; typedef struct ExpertCsr ExpertCsr; struct ExpertCsr { - sqlite3_vtab_cursor base; - sqlite3_stmt *pData; + sqlite3_vtab_cursor base; + sqlite3_stmt *pData; }; static char *expertDequote(const char *zIn){ - int n = STRLEN(zIn); - char *zRet = sqlite3_malloc(n); - - assert( zIn[0]=='\'' ); - assert( zIn[n-1]=='\'' ); - - if( zRet ){ - int iOut = 0; - int iIn = 0; - for(iIn=1; iIn<(n-1); iIn++){ - if( zIn[iIn]=='\'' ){ - assert( zIn[iIn+1]=='\'' ); - iIn++; - } - zRet[iOut++] = zIn[iIn]; - } - zRet[iOut] = '\0'; + int n = STRLEN(zIn); + char *zRet = sqlite3_malloc(n); + + assert( zIn[0]=='\'' ); + assert( zIn[n-1]=='\'' ); + + if( zRet ){ + int iOut = 0; + int iIn = 0; + for(iIn=1; iIn<(n-1); iIn++){ + if( zIn[iIn]=='\'' ){ + assert( zIn[iIn+1]=='\'' ); + iIn++; + } + zRet[iOut++] = zIn[iIn]; } + zRet[iOut] = '\0'; + } - return zRet; + return zRet; } -/* +/* ** This function is the implementation of both the xConnect and xCreate ** methods of the r-tree virtual table. ** @@ -9654,261 +9654,261 @@ static char *expertDequote(const char *zIn){ ** argv[...] -> column names... */ static int expertConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr ){ - sqlite3expert *pExpert = (sqlite3expert*)pAux; - ExpertVtab *p = 0; - int rc; - - if( argc!=4 ){ - *pzErr = sqlite3_mprintf("internal error!"); - rc = SQLITE_ERROR; + sqlite3expert *pExpert = (sqlite3expert*)pAux; + ExpertVtab *p = 0; + int rc; + + if( argc!=4 ){ + *pzErr = sqlite3_mprintf("internal error!"); + rc = SQLITE_ERROR; + }else{ + char *zCreateTable = expertDequote(argv[3]); + if( zCreateTable ){ + rc = sqlite3_declare_vtab(db, zCreateTable); + if( rc==SQLITE_OK ){ + p = idxMalloc(&rc, sizeof(ExpertVtab)); + } + if( rc==SQLITE_OK ){ + p->pExpert = pExpert; + p->pTab = pExpert->pTable; + assert( sqlite3_stricmp(p->pTab->zName, argv[2])==0 ); + } + sqlite3_free(zCreateTable); }else{ - char *zCreateTable = expertDequote(argv[3]); - if( zCreateTable ){ - rc = sqlite3_declare_vtab(db, zCreateTable); - if( rc==SQLITE_OK ){ - p = idxMalloc(&rc, sizeof(ExpertVtab)); - } - if( rc==SQLITE_OK ){ - p->pExpert = pExpert; - p->pTab = pExpert->pTable; - assert( sqlite3_stricmp(p->pTab->zName, argv[2])==0 ); - } - sqlite3_free(zCreateTable); - }else{ - rc = SQLITE_NOMEM; - } + rc = SQLITE_NOMEM; } + } - *ppVtab = (sqlite3_vtab*)p; - return rc; + *ppVtab = (sqlite3_vtab*)p; + return rc; } static int expertDisconnect(sqlite3_vtab *pVtab){ - ExpertVtab *p = (ExpertVtab*)pVtab; - sqlite3_free(p); - return SQLITE_OK; + ExpertVtab *p = (ExpertVtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; } static int expertBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){ - ExpertVtab *p = (ExpertVtab*)pVtab; - int rc = SQLITE_OK; - int n = 0; - IdxScan *pScan; - const int opmask = - SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_GT | - SQLITE_INDEX_CONSTRAINT_LT | SQLITE_INDEX_CONSTRAINT_GE | - SQLITE_INDEX_CONSTRAINT_LE; - - pScan = idxMalloc(&rc, sizeof(IdxScan)); - if( pScan ){ - int i; - - /* Link the new scan object into the list */ - pScan->pTab = p->pTab; - pScan->pNextScan = p->pExpert->pScan; - p->pExpert->pScan = pScan; - - /* Add the constraints to the IdxScan object */ - for(i=0; inConstraint; i++){ - struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; - if( pCons->usable - && pCons->iColumn>=0 - && p->pTab->aCol[pCons->iColumn].iPk==0 - && (pCons->op & opmask) - ){ - IdxConstraint *pNew; - const char *zColl = sqlite3_vtab_collation(pIdxInfo, i); - pNew = idxNewConstraint(&rc, zColl); - if( pNew ){ - pNew->iCol = pCons->iColumn; - if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ - pNew->pNext = pScan->pEq; - pScan->pEq = pNew; - }else{ - pNew->bRange = 1; - pNew->pNext = pScan->pRange; - pScan->pRange = pNew; - } - } - n++; - pIdxInfo->aConstraintUsage[i].argvIndex = n; - } - } + ExpertVtab *p = (ExpertVtab*)pVtab; + int rc = SQLITE_OK; + int n = 0; + IdxScan *pScan; + const int opmask = + SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_GT | + SQLITE_INDEX_CONSTRAINT_LT | SQLITE_INDEX_CONSTRAINT_GE | + SQLITE_INDEX_CONSTRAINT_LE; + + pScan = idxMalloc(&rc, sizeof(IdxScan)); + if( pScan ){ + int i; - /* Add the ORDER BY to the IdxScan object */ - for(i=pIdxInfo->nOrderBy-1; i>=0; i--){ - int iCol = pIdxInfo->aOrderBy[i].iColumn; - if( iCol>=0 ){ - IdxConstraint *pNew = idxNewConstraint(&rc, p->pTab->aCol[iCol].zColl); - if( pNew ){ - pNew->iCol = iCol; - pNew->bDesc = pIdxInfo->aOrderBy[i].desc; - pNew->pNext = pScan->pOrder; - pNew->pLink = pScan->pOrder; - pScan->pOrder = pNew; - n++; - } - } - } - } + /* Link the new scan object into the list */ + pScan->pTab = p->pTab; + pScan->pNextScan = p->pExpert->pScan; + p->pExpert->pScan = pScan; - pIdxInfo->estimatedCost = 1000000.0 / (n+1); - return rc; + /* Add the constraints to the IdxScan object */ + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; + if( pCons->usable + && pCons->iColumn>=0 + && p->pTab->aCol[pCons->iColumn].iPk==0 + && (pCons->op & opmask) + ){ + IdxConstraint *pNew; + const char *zColl = sqlite3_vtab_collation(pIdxInfo, i); + pNew = idxNewConstraint(&rc, zColl); + if( pNew ){ + pNew->iCol = pCons->iColumn; + if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + pNew->pNext = pScan->pEq; + pScan->pEq = pNew; + }else{ + pNew->bRange = 1; + pNew->pNext = pScan->pRange; + pScan->pRange = pNew; + } + } + n++; + pIdxInfo->aConstraintUsage[i].argvIndex = n; + } + } + + /* Add the ORDER BY to the IdxScan object */ + for(i=pIdxInfo->nOrderBy-1; i>=0; i--){ + int iCol = pIdxInfo->aOrderBy[i].iColumn; + if( iCol>=0 ){ + IdxConstraint *pNew = idxNewConstraint(&rc, p->pTab->aCol[iCol].zColl); + if( pNew ){ + pNew->iCol = iCol; + pNew->bDesc = pIdxInfo->aOrderBy[i].desc; + pNew->pNext = pScan->pOrder; + pNew->pLink = pScan->pOrder; + pScan->pOrder = pNew; + n++; + } + } + } + } + + pIdxInfo->estimatedCost = 1000000.0 / (n+1); + return rc; } static int expertUpdate( - sqlite3_vtab *pVtab, - int nData, - sqlite3_value **azData, - sqlite_int64 *pRowid + sqlite3_vtab *pVtab, + int nData, + sqlite3_value **azData, + sqlite_int64 *pRowid ){ - (void)pVtab; - (void)nData; - (void)azData; - (void)pRowid; - return SQLITE_OK; + (void)pVtab; + (void)nData; + (void)azData; + (void)pRowid; + return SQLITE_OK; } -/* +/* ** Virtual table module xOpen method. */ static int expertOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ - int rc = SQLITE_OK; - ExpertCsr *pCsr; - (void)pVTab; - pCsr = idxMalloc(&rc, sizeof(ExpertCsr)); - *ppCursor = (sqlite3_vtab_cursor*)pCsr; - return rc; + int rc = SQLITE_OK; + ExpertCsr *pCsr; + (void)pVTab; + pCsr = idxMalloc(&rc, sizeof(ExpertCsr)); + *ppCursor = (sqlite3_vtab_cursor*)pCsr; + return rc; } -/* +/* ** Virtual table module xClose method. */ static int expertClose(sqlite3_vtab_cursor *cur){ - ExpertCsr *pCsr = (ExpertCsr*)cur; - sqlite3_finalize(pCsr->pData); - sqlite3_free(pCsr); - return SQLITE_OK; + ExpertCsr *pCsr = (ExpertCsr*)cur; + sqlite3_finalize(pCsr->pData); + sqlite3_free(pCsr); + return SQLITE_OK; } /* ** Virtual table module xEof method. ** -** Return non-zero if the cursor does not currently point to a valid +** Return non-zero if the cursor does not currently point to a valid ** record (i.e if the scan has finished), or zero otherwise. */ static int expertEof(sqlite3_vtab_cursor *cur){ - ExpertCsr *pCsr = (ExpertCsr*)cur; - return pCsr->pData==0; + ExpertCsr *pCsr = (ExpertCsr*)cur; + return pCsr->pData==0; } -/* +/* ** Virtual table module xNext method. */ static int expertNext(sqlite3_vtab_cursor *cur){ - ExpertCsr *pCsr = (ExpertCsr*)cur; - int rc = SQLITE_OK; - - assert( pCsr->pData ); - rc = sqlite3_step(pCsr->pData); - if( rc!=SQLITE_ROW ){ - rc = sqlite3_finalize(pCsr->pData); - pCsr->pData = 0; - }else{ - rc = SQLITE_OK; - } + ExpertCsr *pCsr = (ExpertCsr*)cur; + int rc = SQLITE_OK; - return rc; + assert( pCsr->pData ); + rc = sqlite3_step(pCsr->pData); + if( rc!=SQLITE_ROW ){ + rc = sqlite3_finalize(pCsr->pData); + pCsr->pData = 0; + }else{ + rc = SQLITE_OK; + } + + return rc; } -/* +/* ** Virtual table module xRowid method. */ static int expertRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ - (void)cur; - *pRowid = 0; - return SQLITE_OK; + (void)cur; + *pRowid = 0; + return SQLITE_OK; } -/* +/* ** Virtual table module xColumn method. */ static int expertColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ - ExpertCsr *pCsr = (ExpertCsr*)cur; - sqlite3_value *pVal; - pVal = sqlite3_column_value(pCsr->pData, i); - if( pVal ){ - sqlite3_result_value(ctx, pVal); - } - return SQLITE_OK; + ExpertCsr *pCsr = (ExpertCsr*)cur; + sqlite3_value *pVal; + pVal = sqlite3_column_value(pCsr->pData, i); + if( pVal ){ + sqlite3_result_value(ctx, pVal); + } + return SQLITE_OK; } -/* +/* ** Virtual table module xFilter method. */ static int expertFilter( - sqlite3_vtab_cursor *cur, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv + sqlite3_vtab_cursor *cur, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv ){ - ExpertCsr *pCsr = (ExpertCsr*)cur; - ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab); - sqlite3expert *pExpert = pVtab->pExpert; - int rc; - - (void)idxNum; - (void)idxStr; - (void)argc; - (void)argv; - rc = sqlite3_finalize(pCsr->pData); - pCsr->pData = 0; - if( rc==SQLITE_OK ){ - rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg, - "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName - ); - } + ExpertCsr *pCsr = (ExpertCsr*)cur; + ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab); + sqlite3expert *pExpert = pVtab->pExpert; + int rc; + + (void)idxNum; + (void)idxStr; + (void)argc; + (void)argv; + rc = sqlite3_finalize(pCsr->pData); + pCsr->pData = 0; + if( rc==SQLITE_OK ){ + rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg, + "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName + ); + } - if( rc==SQLITE_OK ){ - rc = expertNext(cur); - } - return rc; + if( rc==SQLITE_OK ){ + rc = expertNext(cur); + } + return rc; } static int idxRegisterVtab(sqlite3expert *p){ - static sqlite3_module expertModule = { - 2, /* iVersion */ - expertConnect, /* xCreate - create a table */ - expertConnect, /* xConnect - connect to an existing table */ - expertBestIndex, /* xBestIndex - Determine search strategy */ - expertDisconnect, /* xDisconnect - Disconnect from a table */ - expertDisconnect, /* xDestroy - Drop a table */ - expertOpen, /* xOpen - open a cursor */ - expertClose, /* xClose - close a cursor */ - expertFilter, /* xFilter - configure scan constraints */ - expertNext, /* xNext - advance a cursor */ - expertEof, /* xEof */ - expertColumn, /* xColumn - read data */ - expertRowid, /* xRowid - read data */ - expertUpdate, /* xUpdate - write data */ - 0, /* xBegin - begin transaction */ - 0, /* xSync - sync transaction */ - 0, /* xCommit - commit transaction */ - 0, /* xRollback - rollback transaction */ - 0, /* xFindFunction - function overloading */ - 0, /* xRename - rename the table */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0, /* xShadowName */ - }; - - return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p); + static sqlite3_module expertModule = { + 2, /* iVersion */ + expertConnect, /* xCreate - create a table */ + expertConnect, /* xConnect - connect to an existing table */ + expertBestIndex, /* xBestIndex - Determine search strategy */ + expertDisconnect, /* xDisconnect - Disconnect from a table */ + expertDisconnect, /* xDestroy - Drop a table */ + expertOpen, /* xOpen - open a cursor */ + expertClose, /* xClose - close a cursor */ + expertFilter, /* xFilter - configure scan constraints */ + expertNext, /* xNext - advance a cursor */ + expertEof, /* xEof */ + expertColumn, /* xColumn - read data */ + expertRowid, /* xRowid - read data */ + expertUpdate, /* xUpdate - write data */ + 0, /* xBegin - begin transaction */ + 0, /* xSync - sync transaction */ + 0, /* xCommit - commit transaction */ + 0, /* xRollback - rollback transaction */ + 0, /* xFindFunction - function overloading */ + 0, /* xRename - rename the table */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0, /* xShadowName */ + }; + + return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p); } /* ** End of virtual table implementation. @@ -9919,8 +9919,8 @@ static int idxRegisterVtab(sqlite3expert *p){ ** returning. Otherwise, discard the sqlite3_finalize() return value. */ static void idxFinalize(int *pRc, sqlite3_stmt *pStmt){ - int rc = sqlite3_finalize(pStmt); - if( *pRc==SQLITE_OK ) *pRc = rc; + int rc = sqlite3_finalize(pStmt); + if( *pRc==SQLITE_OK ) *pRc = rc; } /* @@ -9934,85 +9934,85 @@ static void idxFinalize(int *pRc, sqlite3_stmt *pStmt){ ** IdxTable object or error message using sqlite3_free(). */ static int idxGetTableInfo( - sqlite3 *db, /* Database connection to read details from */ - const char *zTab, /* Table name */ - IdxTable **ppOut, /* OUT: New object (if successful) */ - char **pzErrmsg /* OUT: Error message (if not) */ + sqlite3 *db, /* Database connection to read details from */ + const char *zTab, /* Table name */ + IdxTable **ppOut, /* OUT: New object (if successful) */ + char **pzErrmsg /* OUT: Error message (if not) */ ){ - sqlite3_stmt *p1 = 0; - int nCol = 0; - int nTab = STRLEN(zTab); - int nByte = sizeof(IdxTable) + nTab + 1; - IdxTable *pNew = 0; - int rc, rc2; - char *pCsr = 0; - int nPk = 0; - - rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ - const char *zCol = (const char*)sqlite3_column_text(p1, 1); - const char *zColSeq = 0; - nByte += 1 + STRLEN(zCol); - rc = sqlite3_table_column_metadata( - db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 - ); - if( zColSeq==0 ) zColSeq = "binary"; - nByte += 1 + STRLEN(zColSeq); - nCol++; - nPk += (sqlite3_column_int(p1, 5)>0); - } - rc2 = sqlite3_reset(p1); - if( rc==SQLITE_OK ) rc = rc2; + sqlite3_stmt *p1 = 0; + int nCol = 0; + int nTab = STRLEN(zTab); + int nByte = sizeof(IdxTable) + nTab + 1; + IdxTable *pNew = 0; + int rc, rc2; + char *pCsr = 0; + int nPk = 0; + + rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ + const char *zCol = (const char*)sqlite3_column_text(p1, 1); + const char *zColSeq = 0; + nByte += 1 + STRLEN(zCol); + rc = sqlite3_table_column_metadata( + db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 + ); + if( zColSeq==0 ) zColSeq = "binary"; + nByte += 1 + STRLEN(zColSeq); + nCol++; + nPk += (sqlite3_column_int(p1, 5)>0); + } + rc2 = sqlite3_reset(p1); + if( rc==SQLITE_OK ) rc = rc2; + + nByte += sizeof(IdxColumn) * nCol; + if( rc==SQLITE_OK ){ + pNew = idxMalloc(&rc, nByte); + } + if( rc==SQLITE_OK ){ + pNew->aCol = (IdxColumn*)&pNew[1]; + pNew->nCol = nCol; + pCsr = (char*)&pNew->aCol[nCol]; + } + + nCol = 0; + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ + const char *zCol = (const char*)sqlite3_column_text(p1, 1); + const char *zColSeq = 0; + int nCopy = STRLEN(zCol) + 1; + pNew->aCol[nCol].zName = pCsr; + pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1); + memcpy(pCsr, zCol, nCopy); + pCsr += nCopy; - nByte += sizeof(IdxColumn) * nCol; + rc = sqlite3_table_column_metadata( + db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 + ); if( rc==SQLITE_OK ){ - pNew = idxMalloc(&rc, nByte); + if( zColSeq==0 ) zColSeq = "binary"; + nCopy = STRLEN(zColSeq) + 1; + pNew->aCol[nCol].zColl = pCsr; + memcpy(pCsr, zColSeq, nCopy); + pCsr += nCopy; } - if( rc==SQLITE_OK ){ - pNew->aCol = (IdxColumn*)&pNew[1]; - pNew->nCol = nCol; - pCsr = (char*)&pNew->aCol[nCol]; - } - - nCol = 0; - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ - const char *zCol = (const char*)sqlite3_column_text(p1, 1); - const char *zColSeq = 0; - int nCopy = STRLEN(zCol) + 1; - pNew->aCol[nCol].zName = pCsr; - pNew->aCol[nCol].iPk = (sqlite3_column_int(p1, 5)==1 && nPk==1); - memcpy(pCsr, zCol, nCopy); - pCsr += nCopy; - - rc = sqlite3_table_column_metadata( - db, "main", zTab, zCol, 0, &zColSeq, 0, 0, 0 - ); - if( rc==SQLITE_OK ){ - if( zColSeq==0 ) zColSeq = "binary"; - nCopy = STRLEN(zColSeq) + 1; - pNew->aCol[nCol].zColl = pCsr; - memcpy(pCsr, zColSeq, nCopy); - pCsr += nCopy; - } - nCol++; - } - idxFinalize(&rc, p1); + nCol++; + } + idxFinalize(&rc, p1); - if( rc!=SQLITE_OK ){ - sqlite3_free(pNew); - pNew = 0; - }else if( ALWAYS(pNew!=0) ){ - pNew->zName = pCsr; - if( ALWAYS(pNew->zName!=0) ) memcpy(pNew->zName, zTab, nTab+1); - } + if( rc!=SQLITE_OK ){ + sqlite3_free(pNew); + pNew = 0; + }else if( ALWAYS(pNew!=0) ){ + pNew->zName = pCsr; + if( ALWAYS(pNew->zName!=0) ) memcpy(pNew->zName, zTab, nTab+1); + } - *ppOut = pNew; - return rc; + *ppOut = pNew; + return rc; } /* -** This function is a no-op if *pRc is set to anything other than +** This function is a no-op if *pRc is set to anything other than ** SQLITE_OK when it is called. ** ** If *pRc is initially set to SQLITE_OK, then the text specified by @@ -10021,31 +10021,31 @@ static int idxGetTableInfo( ** zIn before returning. */ static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){ - va_list ap; - char *zAppend = 0; - char *zRet = 0; - int nIn = zIn ? STRLEN(zIn) : 0; - int nAppend = 0; - va_start(ap, zFmt); - if( *pRc==SQLITE_OK ){ - zAppend = sqlite3_vmprintf(zFmt, ap); - if( zAppend ){ - nAppend = STRLEN(zAppend); - zRet = (char*)sqlite3_malloc(nIn + nAppend + 1); - } - if( zAppend && zRet ){ - if( nIn ) memcpy(zRet, zIn, nIn); - memcpy(&zRet[nIn], zAppend, nAppend+1); - }else{ - sqlite3_free(zRet); - zRet = 0; - *pRc = SQLITE_NOMEM; - } - sqlite3_free(zAppend); - sqlite3_free(zIn); + va_list ap; + char *zAppend = 0; + char *zRet = 0; + int nIn = zIn ? STRLEN(zIn) : 0; + int nAppend = 0; + va_start(ap, zFmt); + if( *pRc==SQLITE_OK ){ + zAppend = sqlite3_vmprintf(zFmt, ap); + if( zAppend ){ + nAppend = STRLEN(zAppend); + zRet = (char*)sqlite3_malloc(nIn + nAppend + 1); + } + if( zAppend && zRet ){ + if( nIn ) memcpy(zRet, zIn, nIn); + memcpy(&zRet[nIn], zAppend, nAppend+1); + }else{ + sqlite3_free(zRet); + zRet = 0; + *pRc = SQLITE_NOMEM; } - va_end(ap); - return zRet; + sqlite3_free(zAppend); + sqlite3_free(zIn); + } + va_end(ap); + return zRet; } /* @@ -10053,17 +10053,17 @@ static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){ ** identifier, or false otherwise. */ static int idxIdentifierRequiresQuotes(const char *zId){ - int i; - for(i=0; zId[i]; i++){ - if( !(zId[i]=='_') - && !(zId[i]>='0' && zId[i]<='9') - && !(zId[i]>='a' && zId[i]<='z') - && !(zId[i]>='A' && zId[i]<='Z') - ){ - return 1; - } + int i; + for(i=0; zId[i]; i++){ + if( !(zId[i]=='_') + && !(zId[i]>='0' && zId[i]<='9') + && !(zId[i]>='a' && zId[i]<='z') + && !(zId[i]>='A' && zId[i]<='Z') + ){ + return 1; } - return 0; + } + return 0; } /* @@ -10071,108 +10071,108 @@ static int idxIdentifierRequiresQuotes(const char *zId){ ** pCons to the string passed as zIn and returns the result. */ static char *idxAppendColDefn( - int *pRc, /* IN/OUT: Error code */ - char *zIn, /* Column defn accumulated so far */ - IdxTable *pTab, /* Table index will be created on */ - IdxConstraint *pCons + int *pRc, /* IN/OUT: Error code */ + char *zIn, /* Column defn accumulated so far */ + IdxTable *pTab, /* Table index will be created on */ + IdxConstraint *pCons ){ - char *zRet = zIn; - IdxColumn *p = &pTab->aCol[pCons->iCol]; - if( zRet ) zRet = idxAppendText(pRc, zRet, ", "); - - if( idxIdentifierRequiresQuotes(p->zName) ){ - zRet = idxAppendText(pRc, zRet, "%Q", p->zName); + char *zRet = zIn; + IdxColumn *p = &pTab->aCol[pCons->iCol]; + if( zRet ) zRet = idxAppendText(pRc, zRet, ", "); + + if( idxIdentifierRequiresQuotes(p->zName) ){ + zRet = idxAppendText(pRc, zRet, "%Q", p->zName); + }else{ + zRet = idxAppendText(pRc, zRet, "%s", p->zName); + } + + if( sqlite3_stricmp(p->zColl, pCons->zColl) ){ + if( idxIdentifierRequiresQuotes(pCons->zColl) ){ + zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl); }else{ - zRet = idxAppendText(pRc, zRet, "%s", p->zName); - } - - if( sqlite3_stricmp(p->zColl, pCons->zColl) ){ - if( idxIdentifierRequiresQuotes(pCons->zColl) ){ - zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl); - }else{ - zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl); - } + zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl); } + } - if( pCons->bDesc ){ - zRet = idxAppendText(pRc, zRet, " DESC"); - } - return zRet; + if( pCons->bDesc ){ + zRet = idxAppendText(pRc, zRet, " DESC"); + } + return zRet; } /* ** Search database dbm for an index compatible with the one idxCreateFromCons() -** would create from arguments pScan, pEq and pTail. If no error occurs and +** would create from arguments pScan, pEq and pTail. If no error occurs and ** such an index is found, return non-zero. Or, if no such index is found, ** return zero. ** ** If an error occurs, set *pRc to an SQLite error code and return zero. */ static int idxFindCompatible( - int *pRc, /* OUT: Error code */ - sqlite3* dbm, /* Database to search */ - IdxScan *pScan, /* Scan for table to search for index on */ - IdxConstraint *pEq, /* List of == constraints */ - IdxConstraint *pTail /* List of range constraints */ + int *pRc, /* OUT: Error code */ + sqlite3* dbm, /* Database to search */ + IdxScan *pScan, /* Scan for table to search for index on */ + IdxConstraint *pEq, /* List of == constraints */ + IdxConstraint *pTail /* List of range constraints */ ){ - const char *zTbl = pScan->pTab->zName; - sqlite3_stmt *pIdxList = 0; - IdxConstraint *pIter; - int nEq = 0; /* Number of elements in pEq */ - int rc; - - /* Count the elements in list pEq */ - for(pIter=pEq; pIter; pIter=pIter->pLink) nEq++; - - rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl); - while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){ - int bMatch = 1; - IdxConstraint *pT = pTail; - sqlite3_stmt *pInfo = 0; - const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1); - - /* Zero the IdxConstraint.bFlag values in the pEq list */ - for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0; - - rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx); - while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){ - int iIdx = sqlite3_column_int(pInfo, 0); - int iCol = sqlite3_column_int(pInfo, 1); - const char *zColl = (const char*)sqlite3_column_text(pInfo, 4); - - if( iIdxpLink){ - if( pIter->bFlag ) continue; - if( pIter->iCol!=iCol ) continue; - if( sqlite3_stricmp(pIter->zColl, zColl) ) continue; - pIter->bFlag = 1; - break; - } - if( pIter==0 ){ - bMatch = 0; - break; - } - }else{ - if( pT ){ - if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){ - bMatch = 0; - break; - } - pT = pT->pLink; - } - } + const char *zTbl = pScan->pTab->zName; + sqlite3_stmt *pIdxList = 0; + IdxConstraint *pIter; + int nEq = 0; /* Number of elements in pEq */ + int rc; + + /* Count the elements in list pEq */ + for(pIter=pEq; pIter; pIter=pIter->pLink) nEq++; + + rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl); + while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){ + int bMatch = 1; + IdxConstraint *pT = pTail; + sqlite3_stmt *pInfo = 0; + const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1); + + /* Zero the IdxConstraint.bFlag values in the pEq list */ + for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0; + + rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx); + while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){ + int iIdx = sqlite3_column_int(pInfo, 0); + int iCol = sqlite3_column_int(pInfo, 1); + const char *zColl = (const char*)sqlite3_column_text(pInfo, 4); + + if( iIdxpLink){ + if( pIter->bFlag ) continue; + if( pIter->iCol!=iCol ) continue; + if( sqlite3_stricmp(pIter->zColl, zColl) ) continue; + pIter->bFlag = 1; + break; + } + if( pIter==0 ){ + bMatch = 0; + break; + } + }else{ + if( pT ){ + if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){ + bMatch = 0; + break; + } + pT = pT->pLink; } - idxFinalize(&rc, pInfo); + } + } + idxFinalize(&rc, pInfo); - if( rc==SQLITE_OK && bMatch ){ - sqlite3_finalize(pIdxList); - return 1; - } + if( rc==SQLITE_OK && bMatch ){ + sqlite3_finalize(pIdxList); + return 1; } - idxFinalize(&rc, pIdxList); + } + idxFinalize(&rc, pIdxList); - *pRc = rc; - return 0; + *pRc = rc; + return 0; } /* Callback for sqlite3_exec() with query with leading count(*) column. @@ -10180,96 +10180,96 @@ static int idxFindCompatible( * if that leading column is not exactly '0'. */ static int countNonzeros(void* pCount, int nc, - char* azResults[], char* azColumns[]){ - (void)azColumns; /* Suppress unused parameter warning */ - if( nc>0 && (azResults[0][0]!='0' || azResults[0][1]!=0) ){ - *((int *)pCount) += 1; - } - return 0; + char* azResults[], char* azColumns[]){ + (void)azColumns; /* Suppress unused parameter warning */ + if( nc>0 && (azResults[0][0]!='0' || azResults[0][1]!=0) ){ + *((int *)pCount) += 1; + } + return 0; } static int idxCreateFromCons( - sqlite3expert *p, - IdxScan *pScan, - IdxConstraint *pEq, - IdxConstraint *pTail + sqlite3expert *p, + IdxScan *pScan, + IdxConstraint *pEq, + IdxConstraint *pTail ){ - sqlite3 *dbm = p->dbm; - int rc = SQLITE_OK; - if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){ - IdxTable *pTab = pScan->pTab; - char *zCols = 0; - char *zIdx = 0; - IdxConstraint *pCons; - unsigned int h = 0; - const char *zFmt; - - for(pCons=pEq; pCons; pCons=pCons->pLink){ - zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); - } - for(pCons=pTail; pCons; pCons=pCons->pLink){ - zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); - } + sqlite3 *dbm = p->dbm; + int rc = SQLITE_OK; + if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){ + IdxTable *pTab = pScan->pTab; + char *zCols = 0; + char *zIdx = 0; + IdxConstraint *pCons; + unsigned int h = 0; + const char *zFmt; - if( rc==SQLITE_OK ){ - /* Hash the list of columns to come up with a name for the index */ - const char *zTable = pScan->pTab->zName; - int quoteTable = idxIdentifierRequiresQuotes(zTable); - char *zName = 0; /* Index name */ - int collisions = 0; - do{ - int i; - char *zFind; - for(i=0; zCols[i]; i++){ - h += ((h<<3) + zCols[i]); - } - sqlite3_free(zName); - zName = sqlite3_mprintf("%s_idx_%08x", zTable, h); - if( zName==0 ) break; - /* Is is unique among table, view and index names? */ - zFmt = "SELECT count(*) FROM sqlite_schema WHERE name=%Q" - " AND type in ('index','table','view')"; - zFind = sqlite3_mprintf(zFmt, zName); - i = 0; - rc = sqlite3_exec(dbm, zFind, countNonzeros, &i, 0); - assert(rc==SQLITE_OK); - sqlite3_free(zFind); - if( i==0 ){ - collisions = 0; - break; - } - ++collisions; - }while( collisions<50 && zName!=0 ); - if( collisions ){ - /* This return means "Gave up trying to find a unique index name." */ - rc = SQLITE_BUSY_TIMEOUT; - }else if( zName==0 ){ - rc = SQLITE_NOMEM; - }else{ - if( quoteTable ){ - zFmt = "CREATE INDEX \"%w\" ON \"%w\"(%s)"; - }else{ - zFmt = "CREATE INDEX %s ON %s(%s)"; - } - zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols); - if( !zIdx ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg); - if( rc!=SQLITE_OK ){ - rc = SQLITE_BUSY_TIMEOUT; - }else{ - idxHashAdd(&rc, &p->hIdx, zName, zIdx); - } - } - sqlite3_free(zName); - sqlite3_free(zIdx); - } - } + for(pCons=pEq; pCons; pCons=pCons->pLink){ + zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); + } + for(pCons=pTail; pCons; pCons=pCons->pLink){ + zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); + } - sqlite3_free(zCols); + if( rc==SQLITE_OK ){ + /* Hash the list of columns to come up with a name for the index */ + const char *zTable = pScan->pTab->zName; + int quoteTable = idxIdentifierRequiresQuotes(zTable); + char *zName = 0; /* Index name */ + int collisions = 0; + do{ + int i; + char *zFind; + for(i=0; zCols[i]; i++){ + h += ((h<<3) + zCols[i]); + } + sqlite3_free(zName); + zName = sqlite3_mprintf("%s_idx_%08x", zTable, h); + if( zName==0 ) break; + /* Is is unique among table, view and index names? */ + zFmt = "SELECT count(*) FROM sqlite_schema WHERE name=%Q" + " AND type in ('index','table','view')"; + zFind = sqlite3_mprintf(zFmt, zName); + i = 0; + rc = sqlite3_exec(dbm, zFind, countNonzeros, &i, 0); + assert(rc==SQLITE_OK); + sqlite3_free(zFind); + if( i==0 ){ + collisions = 0; + break; + } + ++collisions; + }while( collisions<50 && zName!=0 ); + if( collisions ){ + /* This return means "Gave up trying to find a unique index name." */ + rc = SQLITE_BUSY_TIMEOUT; + }else if( zName==0 ){ + rc = SQLITE_NOMEM; + }else{ + if( quoteTable ){ + zFmt = "CREATE INDEX \"%w\" ON \"%w\"(%s)"; + }else{ + zFmt = "CREATE INDEX %s ON %s(%s)"; + } + zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols); + if( !zIdx ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg); + if( rc!=SQLITE_OK ){ + rc = SQLITE_BUSY_TIMEOUT; + }else{ + idxHashAdd(&rc, &p->hIdx, zName, zIdx); + } + } + sqlite3_free(zName); + sqlite3_free(zIdx); + } } - return rc; + + sqlite3_free(zCols); + } + return rc; } /* @@ -10277,77 +10277,77 @@ static int idxCreateFromCons( ** a constraint compatible with *p. Otherwise return false. */ static int idxFindConstraint(IdxConstraint *pList, IdxConstraint *p){ - IdxConstraint *pCmp; - for(pCmp=pList; pCmp; pCmp=pCmp->pLink){ - if( p->iCol==pCmp->iCol ) return 1; - } - return 0; + IdxConstraint *pCmp; + for(pCmp=pList; pCmp; pCmp=pCmp->pLink){ + if( p->iCol==pCmp->iCol ) return 1; + } + return 0; } static int idxCreateFromWhere( - sqlite3expert *p, - IdxScan *pScan, /* Create indexes for this scan */ - IdxConstraint *pTail /* range/ORDER BY constraints for inclusion */ + sqlite3expert *p, + IdxScan *pScan, /* Create indexes for this scan */ + IdxConstraint *pTail /* range/ORDER BY constraints for inclusion */ ){ - IdxConstraint *p1 = 0; - IdxConstraint *pCon; - int rc; + IdxConstraint *p1 = 0; + IdxConstraint *pCon; + int rc; - /* Gather up all the == constraints. */ - for(pCon=pScan->pEq; pCon; pCon=pCon->pNext){ - if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){ - pCon->pLink = p1; - p1 = pCon; - } + /* Gather up all the == constraints. */ + for(pCon=pScan->pEq; pCon; pCon=pCon->pNext){ + if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){ + pCon->pLink = p1; + p1 = pCon; } + } - /* Create an index using the == constraints collected above. And the + /* Create an index using the == constraints collected above. And the ** range constraint/ORDER BY terms passed in by the caller, if any. */ - rc = idxCreateFromCons(p, pScan, p1, pTail); + rc = idxCreateFromCons(p, pScan, p1, pTail); - /* If no range/ORDER BY passed by the caller, create a version of the + /* If no range/ORDER BY passed by the caller, create a version of the ** index for each range constraint. */ - if( pTail==0 ){ - for(pCon=pScan->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){ - assert( pCon->pLink==0 ); - if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){ - rc = idxCreateFromCons(p, pScan, p1, pCon); - } - } + if( pTail==0 ){ + for(pCon=pScan->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){ + assert( pCon->pLink==0 ); + if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){ + rc = idxCreateFromCons(p, pScan, p1, pCon); + } } + } - return rc; + return rc; } /* -** Create candidate indexes in database [dbm] based on the data in +** Create candidate indexes in database [dbm] based on the data in ** linked-list pScan. */ static int idxCreateCandidates(sqlite3expert *p){ - int rc = SQLITE_OK; - IdxScan *pIter; + int rc = SQLITE_OK; + IdxScan *pIter; - for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){ - rc = idxCreateFromWhere(p, pIter, 0); - if( rc==SQLITE_OK && pIter->pOrder ){ - rc = idxCreateFromWhere(p, pIter, pIter->pOrder); - } + for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){ + rc = idxCreateFromWhere(p, pIter, 0); + if( rc==SQLITE_OK && pIter->pOrder ){ + rc = idxCreateFromWhere(p, pIter, pIter->pOrder); } + } - return rc; + return rc; } /* ** Free all elements of the linked list starting at pConstraint. */ static void idxConstraintFree(IdxConstraint *pConstraint){ - IdxConstraint *pNext; - IdxConstraint *p; + IdxConstraint *pNext; + IdxConstraint *p; - for(p=pConstraint; p; p=pNext){ - pNext = p->pNext; - sqlite3_free(p); - } + for(p=pConstraint; p; p=pNext){ + pNext = p->pNext; + sqlite3_free(p); + } } /* @@ -10355,54 +10355,54 @@ static void idxConstraintFree(IdxConstraint *pConstraint){ ** (pLast is not freed). */ static void idxScanFree(IdxScan *pScan, IdxScan *pLast){ - IdxScan *p; - IdxScan *pNext; - for(p=pScan; p!=pLast; p=pNext){ - pNext = p->pNextScan; - idxConstraintFree(p->pOrder); - idxConstraintFree(p->pEq); - idxConstraintFree(p->pRange); - sqlite3_free(p); - } + IdxScan *p; + IdxScan *pNext; + for(p=pScan; p!=pLast; p=pNext){ + pNext = p->pNextScan; + idxConstraintFree(p->pOrder); + idxConstraintFree(p->pEq); + idxConstraintFree(p->pRange); + sqlite3_free(p); + } } /* -** Free all elements of the linked list starting from pStatement up +** Free all elements of the linked list starting from pStatement up ** until pLast (pLast is not freed). */ static void idxStatementFree(IdxStatement *pStatement, IdxStatement *pLast){ - IdxStatement *p; - IdxStatement *pNext; - for(p=pStatement; p!=pLast; p=pNext){ - pNext = p->pNext; - sqlite3_free(p->zEQP); - sqlite3_free(p->zIdx); - sqlite3_free(p); - } + IdxStatement *p; + IdxStatement *pNext; + for(p=pStatement; p!=pLast; p=pNext){ + pNext = p->pNext; + sqlite3_free(p->zEQP); + sqlite3_free(p->zIdx); + sqlite3_free(p); + } } /* ** Free the linked list of IdxTable objects starting at pTab. */ static void idxTableFree(IdxTable *pTab){ - IdxTable *pIter; - IdxTable *pNext; - for(pIter=pTab; pIter; pIter=pNext){ - pNext = pIter->pNext; - sqlite3_free(pIter); - } + IdxTable *pIter; + IdxTable *pNext; + for(pIter=pTab; pIter; pIter=pNext){ + pNext = pIter->pNext; + sqlite3_free(pIter); + } } /* ** Free the linked list of IdxWrite objects starting at pTab. */ static void idxWriteFree(IdxWrite *pTab){ - IdxWrite *pIter; - IdxWrite *pNext; - for(pIter=pTab; pIter; pIter=pNext){ - pNext = pIter->pNext; - sqlite3_free(pIter); - } + IdxWrite *pIter; + IdxWrite *pNext; + for(pIter=pTab; pIter; pIter=pNext){ + pNext = pIter->pNext; + sqlite3_free(pIter); + } } @@ -10413,529 +10413,529 @@ static void idxWriteFree(IdxWrite *pTab){ ** IdxStatement.zIdx and IdxStatement.zEQP with the results. */ int idxFindIndexes( - sqlite3expert *p, - char **pzErr /* OUT: Error message (sqlite3_malloc) */ + sqlite3expert *p, + char **pzErr /* OUT: Error message (sqlite3_malloc) */ ){ - IdxStatement *pStmt; - sqlite3 *dbm = p->dbm; - int rc = SQLITE_OK; - - IdxHash hIdx; - idxHashInit(&hIdx); - - for(pStmt=p->pStatement; rc==SQLITE_OK && pStmt; pStmt=pStmt->pNext){ - IdxHashEntry *pEntry; - sqlite3_stmt *pExplain = 0; - idxHashClear(&hIdx); - rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr, - "EXPLAIN QUERY PLAN %s", pStmt->zSql - ); - while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){ - /* int iId = sqlite3_column_int(pExplain, 0); */ - /* int iParent = sqlite3_column_int(pExplain, 1); */ - /* int iNotUsed = sqlite3_column_int(pExplain, 2); */ - const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3); - int nDetail; - int i; - - if( !zDetail ) continue; - nDetail = STRLEN(zDetail); - - for(i=0; ihIdx, zIdx, nIdx); - if( zSql ){ - idxHashAdd(&rc, &hIdx, zSql, 0); - if( rc ) goto find_indexes_out; - } - break; - } - } + IdxStatement *pStmt; + sqlite3 *dbm = p->dbm; + int rc = SQLITE_OK; - if( zDetail[0]!='-' ){ - pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%s\n", zDetail); - } - } + IdxHash hIdx; + idxHashInit(&hIdx); - for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){ - pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey); + for(pStmt=p->pStatement; rc==SQLITE_OK && pStmt; pStmt=pStmt->pNext){ + IdxHashEntry *pEntry; + sqlite3_stmt *pExplain = 0; + idxHashClear(&hIdx); + rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr, + "EXPLAIN QUERY PLAN %s", pStmt->zSql + ); + while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){ + /* int iId = sqlite3_column_int(pExplain, 0); */ + /* int iParent = sqlite3_column_int(pExplain, 1); */ + /* int iNotUsed = sqlite3_column_int(pExplain, 2); */ + const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3); + int nDetail; + int i; + + if( !zDetail ) continue; + nDetail = STRLEN(zDetail); + + for(i=0; ihIdx, zIdx, nIdx); + if( zSql ){ + idxHashAdd(&rc, &hIdx, zSql, 0); + if( rc ) goto find_indexes_out; + } + break; } + } - idxFinalize(&rc, pExplain); + if( zDetail[0]!='-' ){ + pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%s\n", zDetail); + } } -find_indexes_out: - idxHashClear(&hIdx); - return rc; + for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){ + pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey); + } + + idxFinalize(&rc, pExplain); + } + + find_indexes_out: + idxHashClear(&hIdx); + return rc; } static int idxAuthCallback( - void *pCtx, - int eOp, - const char *z3, - const char *z4, - const char *zDb, - const char *zTrigger + void *pCtx, + int eOp, + const char *z3, + const char *z4, + const char *zDb, + const char *zTrigger ){ - int rc = SQLITE_OK; - (void)z4; - (void)zTrigger; - if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){ - if( sqlite3_stricmp(zDb, "main")==0 ){ - sqlite3expert *p = (sqlite3expert*)pCtx; - IdxTable *pTab; - for(pTab=p->pTable; pTab; pTab=pTab->pNext){ - if( 0==sqlite3_stricmp(z3, pTab->zName) ) break; - } - if( pTab ){ - IdxWrite *pWrite; - for(pWrite=p->pWrite; pWrite; pWrite=pWrite->pNext){ - if( pWrite->pTab==pTab && pWrite->eOp==eOp ) break; - } - if( pWrite==0 ){ - pWrite = idxMalloc(&rc, sizeof(IdxWrite)); - if( rc==SQLITE_OK ){ - pWrite->pTab = pTab; - pWrite->eOp = eOp; - pWrite->pNext = p->pWrite; - p->pWrite = pWrite; - } - } - } - } - } - return rc; + int rc = SQLITE_OK; + (void)z4; + (void)zTrigger; + if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){ + if( sqlite3_stricmp(zDb, "main")==0 ){ + sqlite3expert *p = (sqlite3expert*)pCtx; + IdxTable *pTab; + for(pTab=p->pTable; pTab; pTab=pTab->pNext){ + if( 0==sqlite3_stricmp(z3, pTab->zName) ) break; + } + if( pTab ){ + IdxWrite *pWrite; + for(pWrite=p->pWrite; pWrite; pWrite=pWrite->pNext){ + if( pWrite->pTab==pTab && pWrite->eOp==eOp ) break; + } + if( pWrite==0 ){ + pWrite = idxMalloc(&rc, sizeof(IdxWrite)); + if( rc==SQLITE_OK ){ + pWrite->pTab = pTab; + pWrite->eOp = eOp; + pWrite->pNext = p->pWrite; + p->pWrite = pWrite; + } + } + } + } + } + return rc; } static int idxProcessOneTrigger( - sqlite3expert *p, - IdxWrite *pWrite, - char **pzErr + sqlite3expert *p, + IdxWrite *pWrite, + char **pzErr ){ - static const char *zInt = UNIQUE_TABLE_NAME; - static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME; - IdxTable *pTab = pWrite->pTab; - const char *zTab = pTab->zName; - const char *zSql = - "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema " - "WHERE tbl_name = %Q AND type IN ('table', 'trigger') " - "ORDER BY type;"; - sqlite3_stmt *pSelect = 0; - int rc = SQLITE_OK; - char *zWrite = 0; - - /* Create the table and its triggers in the temp schema */ - rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){ - const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0); - rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr); - } - idxFinalize(&rc, pSelect); - - /* Rename the table in the temp schema to zInt */ - if( rc==SQLITE_OK ){ - char *z = sqlite3_mprintf("ALTER TABLE temp.%Q RENAME TO %Q", zTab, zInt); - if( z==0 ){ - rc = SQLITE_NOMEM; - }else{ - rc = sqlite3_exec(p->dbv, z, 0, 0, pzErr); - sqlite3_free(z); - } - } - - switch( pWrite->eOp ){ - case SQLITE_INSERT: { - int i; - zWrite = idxAppendText(&rc, zWrite, "INSERT INTO %Q VALUES(", zInt); - for(i=0; inCol; i++){ - zWrite = idxAppendText(&rc, zWrite, "%s?", i==0 ? "" : ", "); - } - zWrite = idxAppendText(&rc, zWrite, ")"); - break; - } - case SQLITE_UPDATE: { - int i; - zWrite = idxAppendText(&rc, zWrite, "UPDATE %Q SET ", zInt); - for(i=0; inCol; i++){ - zWrite = idxAppendText(&rc, zWrite, "%s%Q=?", i==0 ? "" : ", ", - pTab->aCol[i].zName - ); - } - break; - } - default: { - assert( pWrite->eOp==SQLITE_DELETE ); - if( rc==SQLITE_OK ){ - zWrite = sqlite3_mprintf("DELETE FROM %Q", zInt); - if( zWrite==0 ) rc = SQLITE_NOMEM; - } - } - } - - if( rc==SQLITE_OK ){ - sqlite3_stmt *pX = 0; - rc = sqlite3_prepare_v2(p->dbv, zWrite, -1, &pX, 0); - idxFinalize(&rc, pX); - if( rc!=SQLITE_OK ){ - idxDatabaseError(p->dbv, pzErr); - } + static const char *zInt = UNIQUE_TABLE_NAME; + static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME; + IdxTable *pTab = pWrite->pTab; + const char *zTab = pTab->zName; + const char *zSql = + "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema " + "WHERE tbl_name = %Q AND type IN ('table', 'trigger') " + "ORDER BY type;"; + sqlite3_stmt *pSelect = 0; + int rc = SQLITE_OK; + char *zWrite = 0; + + /* Create the table and its triggers in the temp schema */ + rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){ + const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0); + rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr); + } + idxFinalize(&rc, pSelect); + + /* Rename the table in the temp schema to zInt */ + if( rc==SQLITE_OK ){ + char *z = sqlite3_mprintf("ALTER TABLE temp.%Q RENAME TO %Q", zTab, zInt); + if( z==0 ){ + rc = SQLITE_NOMEM; + }else{ + rc = sqlite3_exec(p->dbv, z, 0, 0, pzErr); + sqlite3_free(z); + } + } + + switch( pWrite->eOp ){ + case SQLITE_INSERT: { + int i; + zWrite = idxAppendText(&rc, zWrite, "INSERT INTO %Q VALUES(", zInt); + for(i=0; inCol; i++){ + zWrite = idxAppendText(&rc, zWrite, "%s?", i==0 ? "" : ", "); + } + zWrite = idxAppendText(&rc, zWrite, ")"); + break; + } + case SQLITE_UPDATE: { + int i; + zWrite = idxAppendText(&rc, zWrite, "UPDATE %Q SET ", zInt); + for(i=0; inCol; i++){ + zWrite = idxAppendText(&rc, zWrite, "%s%Q=?", i==0 ? "" : ", ", + pTab->aCol[i].zName + ); + } + break; + } + default: { + assert( pWrite->eOp==SQLITE_DELETE ); + if( rc==SQLITE_OK ){ + zWrite = sqlite3_mprintf("DELETE FROM %Q", zInt); + if( zWrite==0 ) rc = SQLITE_NOMEM; + } + } + } + + if( rc==SQLITE_OK ){ + sqlite3_stmt *pX = 0; + rc = sqlite3_prepare_v2(p->dbv, zWrite, -1, &pX, 0); + idxFinalize(&rc, pX); + if( rc!=SQLITE_OK ){ + idxDatabaseError(p->dbv, pzErr); } - sqlite3_free(zWrite); + } + sqlite3_free(zWrite); - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(p->dbv, zDrop, 0, 0, pzErr); - } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(p->dbv, zDrop, 0, 0, pzErr); + } - return rc; + return rc; } static int idxProcessTriggers(sqlite3expert *p, char **pzErr){ - int rc = SQLITE_OK; - IdxWrite *pEnd = 0; - IdxWrite *pFirst = p->pWrite; - - while( rc==SQLITE_OK && pFirst!=pEnd ){ - IdxWrite *pIter; - for(pIter=pFirst; rc==SQLITE_OK && pIter!=pEnd; pIter=pIter->pNext){ - rc = idxProcessOneTrigger(p, pIter, pzErr); - } - pEnd = pFirst; - pFirst = p->pWrite; + int rc = SQLITE_OK; + IdxWrite *pEnd = 0; + IdxWrite *pFirst = p->pWrite; + + while( rc==SQLITE_OK && pFirst!=pEnd ){ + IdxWrite *pIter; + for(pIter=pFirst; rc==SQLITE_OK && pIter!=pEnd; pIter=pIter->pNext){ + rc = idxProcessOneTrigger(p, pIter, pzErr); } + pEnd = pFirst; + pFirst = p->pWrite; + } - return rc; + return rc; } static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){ - int rc = idxRegisterVtab(p); - sqlite3_stmt *pSchema = 0; + int rc = idxRegisterVtab(p); + sqlite3_stmt *pSchema = 0; - /* For each table in the main db schema: + /* For each table in the main db schema: ** ** 1) Add an entry to the p->pTable list, and ** 2) Create the equivalent virtual table in dbv. */ - rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg, - "SELECT type, name, sql, 1 FROM sqlite_schema " - "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' " - " UNION ALL " - "SELECT type, name, sql, 2 FROM sqlite_schema " - "WHERE type = 'trigger'" - " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') " - "ORDER BY 4, 1" - ); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){ - const char *zType = (const char*)sqlite3_column_text(pSchema, 0); - const char *zName = (const char*)sqlite3_column_text(pSchema, 1); - const char *zSql = (const char*)sqlite3_column_text(pSchema, 2); - - if( zType[0]=='v' || zType[1]=='r' ){ - rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg); - }else{ - IdxTable *pTab; - rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg); - if( rc==SQLITE_OK ){ - int i; - char *zInner = 0; - char *zOuter = 0; - pTab->pNext = p->pTable; - p->pTable = pTab; - - /* The statement the vtab will pass to sqlite3_declare_vtab() */ - zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); - for(i=0; inCol; i++){ - zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", - (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl - ); - } - zInner = idxAppendText(&rc, zInner, ")"); - - /* The CVT statement to create the vtab */ - zOuter = idxAppendText(&rc, 0, - "CREATE VIRTUAL TABLE %Q USING expert(%Q)", zName, zInner - ); - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(p->dbv, zOuter, 0, 0, pzErrmsg); - } - sqlite3_free(zInner); - sqlite3_free(zOuter); - } + rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg, + "SELECT type, name, sql, 1 FROM sqlite_schema " + "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' " + " UNION ALL " + "SELECT type, name, sql, 2 FROM sqlite_schema " + "WHERE type = 'trigger'" + " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') " + "ORDER BY 4, 1" + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){ + const char *zType = (const char*)sqlite3_column_text(pSchema, 0); + const char *zName = (const char*)sqlite3_column_text(pSchema, 1); + const char *zSql = (const char*)sqlite3_column_text(pSchema, 2); + + if( zType[0]=='v' || zType[1]=='r' ){ + rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg); + }else{ + IdxTable *pTab; + rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg); + if( rc==SQLITE_OK ){ + int i; + char *zInner = 0; + char *zOuter = 0; + pTab->pNext = p->pTable; + p->pTable = pTab; + + /* The statement the vtab will pass to sqlite3_declare_vtab() */ + zInner = idxAppendText(&rc, 0, "CREATE TABLE x("); + for(i=0; inCol; i++){ + zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s", + (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl + ); + } + zInner = idxAppendText(&rc, zInner, ")"); + + /* The CVT statement to create the vtab */ + zOuter = idxAppendText(&rc, 0, + "CREATE VIRTUAL TABLE %Q USING expert(%Q)", zName, zInner + ); + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(p->dbv, zOuter, 0, 0, pzErrmsg); } + sqlite3_free(zInner); + sqlite3_free(zOuter); + } } - idxFinalize(&rc, pSchema); - return rc; + } + idxFinalize(&rc, pSchema); + return rc; } struct IdxSampleCtx { - int iTarget; - double target; /* Target nRet/nRow value */ - double nRow; /* Number of rows seen */ - double nRet; /* Number of rows returned */ + int iTarget; + double target; /* Target nRet/nRow value */ + double nRow; /* Number of rows seen */ + double nRet; /* Number of rows returned */ }; static void idxSampleFunc( - sqlite3_context *pCtx, - int argc, - sqlite3_value **argv + sqlite3_context *pCtx, + int argc, + sqlite3_value **argv ){ - struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx); - int bRet; + struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx); + int bRet; - (void)argv; - assert( argc==0 ); - if( p->nRow==0.0 ){ - bRet = 1; - }else{ - bRet = (p->nRet / p->nRow) <= p->target; - if( bRet==0 ){ - unsigned short rnd; - sqlite3_randomness(2, (void*)&rnd); - bRet = ((int)rnd % 100) <= p->iTarget; - } + (void)argv; + assert( argc==0 ); + if( p->nRow==0.0 ){ + bRet = 1; + }else{ + bRet = (p->nRet / p->nRow) <= p->target; + if( bRet==0 ){ + unsigned short rnd; + sqlite3_randomness(2, (void*)&rnd); + bRet = ((int)rnd % 100) <= p->iTarget; } + } - sqlite3_result_int(pCtx, bRet); - p->nRow += 1.0; - p->nRet += (double)bRet; + sqlite3_result_int(pCtx, bRet); + p->nRow += 1.0; + p->nRet += (double)bRet; } struct IdxRemCtx { - int nSlot; - struct IdxRemSlot { - int eType; /* SQLITE_NULL, INTEGER, REAL, TEXT, BLOB */ - i64 iVal; /* SQLITE_INTEGER value */ - double rVal; /* SQLITE_FLOAT value */ - int nByte; /* Bytes of space allocated at z */ - int n; /* Size of buffer z */ - char *z; /* SQLITE_TEXT/BLOB value */ - } aSlot[1]; + int nSlot; + struct IdxRemSlot { + int eType; /* SQLITE_NULL, INTEGER, REAL, TEXT, BLOB */ + i64 iVal; /* SQLITE_INTEGER value */ + double rVal; /* SQLITE_FLOAT value */ + int nByte; /* Bytes of space allocated at z */ + int n; /* Size of buffer z */ + char *z; /* SQLITE_TEXT/BLOB value */ + } aSlot[1]; }; /* ** Implementation of scalar function rem(). */ static void idxRemFunc( - sqlite3_context *pCtx, - int argc, - sqlite3_value **argv + sqlite3_context *pCtx, + int argc, + sqlite3_value **argv ){ - struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx); - struct IdxRemSlot *pSlot; - int iSlot; - assert( argc==2 ); - - iSlot = sqlite3_value_int(argv[0]); - assert( iSlot<=p->nSlot ); - pSlot = &p->aSlot[iSlot]; - - switch( pSlot->eType ){ - case SQLITE_NULL: - /* no-op */ - break; + struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx); + struct IdxRemSlot *pSlot; + int iSlot; + assert( argc==2 ); + + iSlot = sqlite3_value_int(argv[0]); + assert( iSlot<=p->nSlot ); + pSlot = &p->aSlot[iSlot]; + + switch( pSlot->eType ){ + case SQLITE_NULL: + /* no-op */ + break; + + case SQLITE_INTEGER: + sqlite3_result_int64(pCtx, pSlot->iVal); + break; + + case SQLITE_FLOAT: + sqlite3_result_double(pCtx, pSlot->rVal); + break; + + case SQLITE_BLOB: + sqlite3_result_blob(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT); + break; + + case SQLITE_TEXT: + sqlite3_result_text(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT); + break; + } + + pSlot->eType = sqlite3_value_type(argv[1]); + switch( pSlot->eType ){ + case SQLITE_NULL: + /* no-op */ + break; + + case SQLITE_INTEGER: + pSlot->iVal = sqlite3_value_int64(argv[1]); + break; + + case SQLITE_FLOAT: + pSlot->rVal = sqlite3_value_double(argv[1]); + break; + + case SQLITE_BLOB: + case SQLITE_TEXT: { + int nByte = sqlite3_value_bytes(argv[1]); + if( nByte>pSlot->nByte ){ + char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2); + if( zNew==0 ){ + sqlite3_result_error_nomem(pCtx); + return; + } + pSlot->nByte = nByte*2; + pSlot->z = zNew; + } + pSlot->n = nByte; + if( pSlot->eType==SQLITE_BLOB ){ + memcpy(pSlot->z, sqlite3_value_blob(argv[1]), nByte); + }else{ + memcpy(pSlot->z, sqlite3_value_text(argv[1]), nByte); + } + break; + } + } +} - case SQLITE_INTEGER: - sqlite3_result_int64(pCtx, pSlot->iVal); - break; +static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){ + int rc = SQLITE_OK; + const char *zMax = + "SELECT max(i.seqno) FROM " + " sqlite_schema AS s, " + " pragma_index_list(s.name) AS l, " + " pragma_index_info(l.name) AS i " + "WHERE s.type = 'table'"; + sqlite3_stmt *pMax = 0; - case SQLITE_FLOAT: - sqlite3_result_double(pCtx, pSlot->rVal); - break; + *pnMax = 0; + rc = idxPrepareStmt(db, &pMax, pzErr, zMax); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ + *pnMax = sqlite3_column_int(pMax, 0) + 1; + } + idxFinalize(&rc, pMax); - case SQLITE_BLOB: - sqlite3_result_blob(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT); - break; + return rc; +} - case SQLITE_TEXT: - sqlite3_result_text(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT); - break; +static int idxPopulateOneStat1( + sqlite3expert *p, + sqlite3_stmt *pIndexXInfo, + sqlite3_stmt *pWriteStat, + const char *zTab, + const char *zIdx, + char **pzErr +){ + char *zCols = 0; + char *zOrder = 0; + char *zQuery = 0; + int nCol = 0; + int i; + sqlite3_stmt *pQuery = 0; + int *aStat = 0; + int rc = SQLITE_OK; + + assert( p->iSample>0 ); + + /* Formulate the query text */ + sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC); + while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){ + const char *zComma = zCols==0 ? "" : ", "; + const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0); + const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1); + zCols = idxAppendText(&rc, zCols, + "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl + ); + zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); + } + sqlite3_reset(pIndexXInfo); + if( rc==SQLITE_OK ){ + if( p->iSample==100 ){ + zQuery = sqlite3_mprintf( + "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder + ); + }else{ + zQuery = sqlite3_mprintf( + "SELECT %s FROM temp."UNIQUE_TABLE_NAME" x ORDER BY %s", zCols, zOrder + ); + } + } + sqlite3_free(zCols); + sqlite3_free(zOrder); + + /* Formulate the query text */ + if( rc==SQLITE_OK ){ + sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv); + rc = idxPrepareStmt(dbrem, &pQuery, pzErr, zQuery); + } + sqlite3_free(zQuery); + + if( rc==SQLITE_OK ){ + aStat = (int*)idxMalloc(&rc, sizeof(int)*(nCol+1)); + } + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){ + IdxHashEntry *pEntry; + char *zStat = 0; + for(i=0; i<=nCol; i++) aStat[i] = 1; + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){ + aStat[0]++; + for(i=0; ieType = sqlite3_value_type(argv[1]); - switch( pSlot->eType ){ - case SQLITE_NULL: - /* no-op */ - break; - - case SQLITE_INTEGER: - pSlot->iVal = sqlite3_value_int64(argv[1]); - break; + if( rc==SQLITE_OK ){ + int s0 = aStat[0]; + zStat = sqlite3_mprintf("%d", s0); + if( zStat==0 ) rc = SQLITE_NOMEM; + for(i=1; rc==SQLITE_OK && i<=nCol; i++){ + zStat = idxAppendText(&rc, zStat, " %d", (s0+aStat[i]/2) / aStat[i]); + } + } - case SQLITE_FLOAT: - pSlot->rVal = sqlite3_value_double(argv[1]); - break; + if( rc==SQLITE_OK ){ + sqlite3_bind_text(pWriteStat, 1, zTab, -1, SQLITE_STATIC); + sqlite3_bind_text(pWriteStat, 2, zIdx, -1, SQLITE_STATIC); + sqlite3_bind_text(pWriteStat, 3, zStat, -1, SQLITE_STATIC); + sqlite3_step(pWriteStat); + rc = sqlite3_reset(pWriteStat); + } - case SQLITE_BLOB: - case SQLITE_TEXT: { - int nByte = sqlite3_value_bytes(argv[1]); - if( nByte>pSlot->nByte ){ - char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2); - if( zNew==0 ){ - sqlite3_result_error_nomem(pCtx); - return; - } - pSlot->nByte = nByte*2; - pSlot->z = zNew; - } - pSlot->n = nByte; - if( pSlot->eType==SQLITE_BLOB ){ - memcpy(pSlot->z, sqlite3_value_blob(argv[1]), nByte); - }else{ - memcpy(pSlot->z, sqlite3_value_text(argv[1]), nByte); - } - break; - } + pEntry = idxHashFind(&p->hIdx, zIdx, STRLEN(zIdx)); + if( pEntry ){ + assert( pEntry->zVal2==0 ); + pEntry->zVal2 = zStat; + }else{ + sqlite3_free(zStat); } + } + sqlite3_free(aStat); + idxFinalize(&rc, pQuery); + + return rc; } -static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){ - int rc = SQLITE_OK; - const char *zMax = - "SELECT max(i.seqno) FROM " - " sqlite_schema AS s, " - " pragma_index_list(s.name) AS l, " - " pragma_index_info(l.name) AS i " - "WHERE s.type = 'table'"; - sqlite3_stmt *pMax = 0; - - *pnMax = 0; - rc = idxPrepareStmt(db, &pMax, pzErr, zMax); - if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){ - *pnMax = sqlite3_column_int(pMax, 0) + 1; - } - idxFinalize(&rc, pMax); +static int idxBuildSampleTable(sqlite3expert *p, const char *zTab){ + int rc; + char *zSql; - return rc; -} - -static int idxPopulateOneStat1( - sqlite3expert *p, - sqlite3_stmt *pIndexXInfo, - sqlite3_stmt *pWriteStat, - const char *zTab, - const char *zIdx, - char **pzErr -){ - char *zCols = 0; - char *zOrder = 0; - char *zQuery = 0; - int nCol = 0; - int i; - sqlite3_stmt *pQuery = 0; - int *aStat = 0; - int rc = SQLITE_OK; - - assert( p->iSample>0 ); - - /* Formulate the query text */ - sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC); - while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){ - const char *zComma = zCols==0 ? "" : ", "; - const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0); - const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1); - zCols = idxAppendText(&rc, zCols, - "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl - ); - zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); - } - sqlite3_reset(pIndexXInfo); - if( rc==SQLITE_OK ){ - if( p->iSample==100 ){ - zQuery = sqlite3_mprintf( - "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder - ); - }else{ - zQuery = sqlite3_mprintf( - "SELECT %s FROM temp."UNIQUE_TABLE_NAME" x ORDER BY %s", zCols, zOrder - ); - } - } - sqlite3_free(zCols); - sqlite3_free(zOrder); - - /* Formulate the query text */ - if( rc==SQLITE_OK ){ - sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv); - rc = idxPrepareStmt(dbrem, &pQuery, pzErr, zQuery); - } - sqlite3_free(zQuery); - - if( rc==SQLITE_OK ){ - aStat = (int*)idxMalloc(&rc, sizeof(int)*(nCol+1)); - } - if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){ - IdxHashEntry *pEntry; - char *zStat = 0; - for(i=0; i<=nCol; i++) aStat[i] = 1; - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){ - aStat[0]++; - for(i=0; idbv,"DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0); + if( rc!=SQLITE_OK ) return rc; - pEntry = idxHashFind(&p->hIdx, zIdx, STRLEN(zIdx)); - if( pEntry ){ - assert( pEntry->zVal2==0 ); - pEntry->zVal2 = zStat; - }else{ - sqlite3_free(zStat); - } - } - sqlite3_free(aStat); - idxFinalize(&rc, pQuery); - - return rc; -} - -static int idxBuildSampleTable(sqlite3expert *p, const char *zTab){ - int rc; - char *zSql; - - rc = sqlite3_exec(p->dbv,"DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0); - if( rc!=SQLITE_OK ) return rc; - - zSql = sqlite3_mprintf( - "CREATE TABLE temp." UNIQUE_TABLE_NAME " AS SELECT * FROM %Q", zTab - ); - if( zSql==0 ) return SQLITE_NOMEM; - rc = sqlite3_exec(p->dbv, zSql, 0, 0, 0); - sqlite3_free(zSql); + zSql = sqlite3_mprintf( + "CREATE TABLE temp." UNIQUE_TABLE_NAME " AS SELECT * FROM %Q", zTab + ); + if( zSql==0 ) return SQLITE_NOMEM; + rc = sqlite3_exec(p->dbv, zSql, 0, 0, 0); + sqlite3_free(zSql); - return rc; + return rc; } /* @@ -10943,276 +10943,276 @@ static int idxBuildSampleTable(sqlite3expert *p, const char *zTab){ ** indexes have already been created in database sqlite3expert.dbm, this ** function populates sqlite_stat1 table in the same database. ** -** The stat1 data is generated by querying the +** The stat1 data is generated by querying the */ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){ - int rc = SQLITE_OK; - int nMax =0; - struct IdxRemCtx *pCtx = 0; - struct IdxSampleCtx samplectx; - int i; - i64 iPrev = -100000; - sqlite3_stmt *pAllIndex = 0; - sqlite3_stmt *pIndexXInfo = 0; - sqlite3_stmt *pWrite = 0; - - const char *zAllIndex = - "SELECT s.rowid, s.name, l.name FROM " - " sqlite_schema AS s, " - " pragma_index_list(s.name) AS l " - "WHERE s.type = 'table'"; - const char *zIndexXInfo = - "SELECT name, coll FROM pragma_index_xinfo(?) WHERE key"; - const char *zWrite = "INSERT INTO sqlite_stat1 VALUES(?, ?, ?)"; - - /* If iSample==0, no sqlite_stat1 data is required. */ - if( p->iSample==0 ) return SQLITE_OK; - - rc = idxLargestIndex(p->dbm, &nMax, pzErr); - if( nMax<=0 || rc!=SQLITE_OK ) return rc; - - rc = sqlite3_exec(p->dbm, "ANALYZE; PRAGMA writable_schema=1", 0, 0, 0); - - if( rc==SQLITE_OK ){ - int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax); - pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte); - } - - if( rc==SQLITE_OK ){ - sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv); - rc = sqlite3_create_function( - dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0 - ); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_create_function( - p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0 - ); - } - - if( rc==SQLITE_OK ){ - pCtx->nSlot = nMax+1; - rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex); - } - if( rc==SQLITE_OK ){ - rc = idxPrepareStmt(p->dbm, &pIndexXInfo, pzErr, zIndexXInfo); - } - if( rc==SQLITE_OK ){ - rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite); - } - - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){ - i64 iRowid = sqlite3_column_int64(pAllIndex, 0); - const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1); - const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2); - if( p->iSample<100 && iPrev!=iRowid ){ - samplectx.target = (double)p->iSample / 100.0; - samplectx.iTarget = p->iSample; - samplectx.nRow = 0.0; - samplectx.nRet = 0.0; - rc = idxBuildSampleTable(p, zTab); - if( rc!=SQLITE_OK ) break; - } - rc = idxPopulateOneStat1(p, pIndexXInfo, pWrite, zTab, zIdx, pzErr); - iPrev = iRowid; - } - if( rc==SQLITE_OK && p->iSample<100 ){ - rc = sqlite3_exec(p->dbv, - "DROP TABLE IF EXISTS temp." UNIQUE_TABLE_NAME, 0,0,0 - ); - } + int rc = SQLITE_OK; + int nMax =0; + struct IdxRemCtx *pCtx = 0; + struct IdxSampleCtx samplectx; + int i; + i64 iPrev = -100000; + sqlite3_stmt *pAllIndex = 0; + sqlite3_stmt *pIndexXInfo = 0; + sqlite3_stmt *pWrite = 0; + + const char *zAllIndex = + "SELECT s.rowid, s.name, l.name FROM " + " sqlite_schema AS s, " + " pragma_index_list(s.name) AS l " + "WHERE s.type = 'table'"; + const char *zIndexXInfo = + "SELECT name, coll FROM pragma_index_xinfo(?) WHERE key"; + const char *zWrite = "INSERT INTO sqlite_stat1 VALUES(?, ?, ?)"; + + /* If iSample==0, no sqlite_stat1 data is required. */ + if( p->iSample==0 ) return SQLITE_OK; + + rc = idxLargestIndex(p->dbm, &nMax, pzErr); + if( nMax<=0 || rc!=SQLITE_OK ) return rc; + + rc = sqlite3_exec(p->dbm, "ANALYZE; PRAGMA writable_schema=1", 0, 0, 0); + + if( rc==SQLITE_OK ){ + int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax); + pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte); + } + + if( rc==SQLITE_OK ){ + sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv); + rc = sqlite3_create_function( + dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0 + ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function( + p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0 + ); + } + + if( rc==SQLITE_OK ){ + pCtx->nSlot = nMax+1; + rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex); + } + if( rc==SQLITE_OK ){ + rc = idxPrepareStmt(p->dbm, &pIndexXInfo, pzErr, zIndexXInfo); + } + if( rc==SQLITE_OK ){ + rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite); + } + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){ + i64 iRowid = sqlite3_column_int64(pAllIndex, 0); + const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1); + const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2); + if( p->iSample<100 && iPrev!=iRowid ){ + samplectx.target = (double)p->iSample / 100.0; + samplectx.iTarget = p->iSample; + samplectx.nRow = 0.0; + samplectx.nRet = 0.0; + rc = idxBuildSampleTable(p, zTab); + if( rc!=SQLITE_OK ) break; + } + rc = idxPopulateOneStat1(p, pIndexXInfo, pWrite, zTab, zIdx, pzErr); + iPrev = iRowid; + } + if( rc==SQLITE_OK && p->iSample<100 ){ + rc = sqlite3_exec(p->dbv, + "DROP TABLE IF EXISTS temp." UNIQUE_TABLE_NAME, 0,0,0 + ); + } - idxFinalize(&rc, pAllIndex); - idxFinalize(&rc, pIndexXInfo); - idxFinalize(&rc, pWrite); + idxFinalize(&rc, pAllIndex); + idxFinalize(&rc, pIndexXInfo); + idxFinalize(&rc, pWrite); - if( pCtx ){ - for(i=0; inSlot; i++){ - sqlite3_free(pCtx->aSlot[i].z); - } - sqlite3_free(pCtx); + if( pCtx ){ + for(i=0; inSlot; i++){ + sqlite3_free(pCtx->aSlot[i].z); } + sqlite3_free(pCtx); + } - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0); - } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0); + } - sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0); - return rc; + sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0); + return rc; } /* ** Allocate a new sqlite3expert object. */ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){ - int rc = SQLITE_OK; - sqlite3expert *pNew; + int rc = SQLITE_OK; + sqlite3expert *pNew; - pNew = (sqlite3expert*)idxMalloc(&rc, sizeof(sqlite3expert)); + pNew = (sqlite3expert*)idxMalloc(&rc, sizeof(sqlite3expert)); - /* Open two in-memory databases to work with. The "vtab database" (dbv) + /* Open two in-memory databases to work with. The "vtab database" (dbv) ** will contain a virtual table corresponding to each real table in ** the user database schema, and a copy of each view. It is used to ** collect information regarding the WHERE, ORDER BY and other clauses ** of the user's query. */ + if( rc==SQLITE_OK ){ + pNew->db = db; + pNew->iSample = 100; + rc = sqlite3_open(":memory:", &pNew->dbv); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_open(":memory:", &pNew->dbm); if( rc==SQLITE_OK ){ - pNew->db = db; - pNew->iSample = 100; - rc = sqlite3_open(":memory:", &pNew->dbv); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_open(":memory:", &pNew->dbm); - if( rc==SQLITE_OK ){ - sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0); - } + sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0); } + } + - - /* Copy the entire schema of database [db] into [dbm]. */ - if( rc==SQLITE_OK ){ - sqlite3_stmt *pSql; - rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, - "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'" - " AND sql NOT LIKE 'CREATE VIRTUAL %%'" - ); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ - const char *zSql = (const char*)sqlite3_column_text(pSql, 0); - rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg); - } - idxFinalize(&rc, pSql); + /* Copy the entire schema of database [db] into [dbm]. */ + if( rc==SQLITE_OK ){ + sqlite3_stmt *pSql; + rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg, + "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'" + " AND sql NOT LIKE 'CREATE VIRTUAL %%'" + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ + const char *zSql = (const char*)sqlite3_column_text(pSql, 0); + rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg); } + idxFinalize(&rc, pSql); + } - /* Create the vtab schema */ - if( rc==SQLITE_OK ){ - rc = idxCreateVtabSchema(pNew, pzErrmsg); - } + /* Create the vtab schema */ + if( rc==SQLITE_OK ){ + rc = idxCreateVtabSchema(pNew, pzErrmsg); + } - /* Register the auth callback with dbv */ - if( rc==SQLITE_OK ){ - sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew); - } + /* Register the auth callback with dbv */ + if( rc==SQLITE_OK ){ + sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew); + } - /* If an error has occurred, free the new object and reutrn NULL. Otherwise, + /* If an error has occurred, free the new object and reutrn NULL. Otherwise, ** return the new sqlite3expert handle. */ - if( rc!=SQLITE_OK ){ - sqlite3_expert_destroy(pNew); - pNew = 0; - } - return pNew; + if( rc!=SQLITE_OK ){ + sqlite3_expert_destroy(pNew); + pNew = 0; + } + return pNew; } /* ** Configure an sqlite3expert object. */ int sqlite3_expert_config(sqlite3expert *p, int op, ...){ - int rc = SQLITE_OK; - va_list ap; - va_start(ap, op); - switch( op ){ - case EXPERT_CONFIG_SAMPLE: { - int iVal = va_arg(ap, int); - if( iVal<0 ) iVal = 0; - if( iVal>100 ) iVal = 100; - p->iSample = iVal; - break; - } - default: - rc = SQLITE_NOTFOUND; - break; + int rc = SQLITE_OK; + va_list ap; + va_start(ap, op); + switch( op ){ + case EXPERT_CONFIG_SAMPLE: { + int iVal = va_arg(ap, int); + if( iVal<0 ) iVal = 0; + if( iVal>100 ) iVal = 100; + p->iSample = iVal; + break; } + default: + rc = SQLITE_NOTFOUND; + break; + } - va_end(ap); - return rc; + va_end(ap); + return rc; } /* ** Add an SQL statement to the analysis. */ int sqlite3_expert_sql( - sqlite3expert *p, /* From sqlite3_expert_new() */ - const char *zSql, /* SQL statement to add */ - char **pzErr /* OUT: Error message (if any) */ + sqlite3expert *p, /* From sqlite3_expert_new() */ + const char *zSql, /* SQL statement to add */ + char **pzErr /* OUT: Error message (if any) */ ){ - IdxScan *pScanOrig = p->pScan; - IdxStatement *pStmtOrig = p->pStatement; - int rc = SQLITE_OK; - const char *zStmt = zSql; + IdxScan *pScanOrig = p->pScan; + IdxStatement *pStmtOrig = p->pStatement; + int rc = SQLITE_OK; + const char *zStmt = zSql; - if( p->bRun ) return SQLITE_MISUSE; + if( p->bRun ) return SQLITE_MISUSE; - while( rc==SQLITE_OK && zStmt && zStmt[0] ){ - sqlite3_stmt *pStmt = 0; - rc = sqlite3_prepare_v2(p->dbv, zStmt, -1, &pStmt, &zStmt); + while( rc==SQLITE_OK && zStmt && zStmt[0] ){ + sqlite3_stmt *pStmt = 0; + rc = sqlite3_prepare_v2(p->dbv, zStmt, -1, &pStmt, &zStmt); + if( rc==SQLITE_OK ){ + if( pStmt ){ + IdxStatement *pNew; + const char *z = sqlite3_sql(pStmt); + int n = STRLEN(z); + pNew = (IdxStatement*)idxMalloc(&rc, sizeof(IdxStatement) + n+1); if( rc==SQLITE_OK ){ - if( pStmt ){ - IdxStatement *pNew; - const char *z = sqlite3_sql(pStmt); - int n = STRLEN(z); - pNew = (IdxStatement*)idxMalloc(&rc, sizeof(IdxStatement) + n+1); - if( rc==SQLITE_OK ){ - pNew->zSql = (char*)&pNew[1]; - memcpy(pNew->zSql, z, n+1); - pNew->pNext = p->pStatement; - if( p->pStatement ) pNew->iId = p->pStatement->iId+1; - p->pStatement = pNew; - } - sqlite3_finalize(pStmt); - } - }else{ - idxDatabaseError(p->dbv, pzErr); + pNew->zSql = (char*)&pNew[1]; + memcpy(pNew->zSql, z, n+1); + pNew->pNext = p->pStatement; + if( p->pStatement ) pNew->iId = p->pStatement->iId+1; + p->pStatement = pNew; } + sqlite3_finalize(pStmt); + } + }else{ + idxDatabaseError(p->dbv, pzErr); } + } - if( rc!=SQLITE_OK ){ - idxScanFree(p->pScan, pScanOrig); - idxStatementFree(p->pStatement, pStmtOrig); - p->pScan = pScanOrig; - p->pStatement = pStmtOrig; - } + if( rc!=SQLITE_OK ){ + idxScanFree(p->pScan, pScanOrig); + idxStatementFree(p->pStatement, pStmtOrig); + p->pScan = pScanOrig; + p->pStatement = pStmtOrig; + } - return rc; + return rc; } int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr){ - int rc; - IdxHashEntry *pEntry; - - /* Do trigger processing to collect any extra IdxScan structures */ - rc = idxProcessTriggers(p, pzErr); - - /* Create candidate indexes within the in-memory database file */ - if( rc==SQLITE_OK ){ - rc = idxCreateCandidates(p); - }else if ( rc==SQLITE_BUSY_TIMEOUT ){ - if( pzErr ) - *pzErr = sqlite3_mprintf("Cannot find a unique index name to propose."); - return rc; - } - - /* Generate the stat1 data */ - if( rc==SQLITE_OK ){ - rc = idxPopulateStat1(p, pzErr); - } - - /* Formulate the EXPERT_REPORT_CANDIDATES text */ - for(pEntry=p->hIdx.pFirst; pEntry; pEntry=pEntry->pNext){ - p->zCandidates = idxAppendText(&rc, p->zCandidates, - "%s;%s%s\n", pEntry->zVal, - pEntry->zVal2 ? " -- stat1: " : "", pEntry->zVal2 - ); - } + int rc; + IdxHashEntry *pEntry; + + /* Do trigger processing to collect any extra IdxScan structures */ + rc = idxProcessTriggers(p, pzErr); + + /* Create candidate indexes within the in-memory database file */ + if( rc==SQLITE_OK ){ + rc = idxCreateCandidates(p); + }else if ( rc==SQLITE_BUSY_TIMEOUT ){ + if( pzErr ) + *pzErr = sqlite3_mprintf("Cannot find a unique index name to propose."); + return rc; + } + + /* Generate the stat1 data */ + if( rc==SQLITE_OK ){ + rc = idxPopulateStat1(p, pzErr); + } + + /* Formulate the EXPERT_REPORT_CANDIDATES text */ + for(pEntry=p->hIdx.pFirst; pEntry; pEntry=pEntry->pNext){ + p->zCandidates = idxAppendText(&rc, p->zCandidates, + "%s;%s%s\n", pEntry->zVal, + pEntry->zVal2 ? " -- stat1: " : "", pEntry->zVal2 + ); + } - /* Figure out which of the candidate indexes are preferred by the query + /* Figure out which of the candidate indexes are preferred by the query ** planner and report the results to the user. */ - if( rc==SQLITE_OK ){ - rc = idxFindIndexes(p, pzErr); - } + if( rc==SQLITE_OK ){ + rc = idxFindIndexes(p, pzErr); + } - if( rc==SQLITE_OK ){ - p->bRun = 1; - } - return rc; + if( rc==SQLITE_OK ){ + p->bRun = 1; + } + return rc; } /* @@ -11220,52 +11220,52 @@ int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr){ ** sqlite3expert using sqlite3_expert_sql(). */ int sqlite3_expert_count(sqlite3expert *p){ - int nRet = 0; - if( p->pStatement ) nRet = p->pStatement->iId+1; - return nRet; + int nRet = 0; + if( p->pStatement ) nRet = p->pStatement->iId+1; + return nRet; } /* ** Return a component of the report. */ const char *sqlite3_expert_report(sqlite3expert *p, int iStmt, int eReport){ - const char *zRet = 0; - IdxStatement *pStmt; - - if( p->bRun==0 ) return 0; - for(pStmt=p->pStatement; pStmt && pStmt->iId!=iStmt; pStmt=pStmt->pNext); - switch( eReport ){ - case EXPERT_REPORT_SQL: - if( pStmt ) zRet = pStmt->zSql; - break; - case EXPERT_REPORT_INDEXES: - if( pStmt ) zRet = pStmt->zIdx; - break; - case EXPERT_REPORT_PLAN: - if( pStmt ) zRet = pStmt->zEQP; - break; - case EXPERT_REPORT_CANDIDATES: - zRet = p->zCandidates; - break; - } - return zRet; + const char *zRet = 0; + IdxStatement *pStmt; + + if( p->bRun==0 ) return 0; + for(pStmt=p->pStatement; pStmt && pStmt->iId!=iStmt; pStmt=pStmt->pNext); + switch( eReport ){ + case EXPERT_REPORT_SQL: + if( pStmt ) zRet = pStmt->zSql; + break; + case EXPERT_REPORT_INDEXES: + if( pStmt ) zRet = pStmt->zIdx; + break; + case EXPERT_REPORT_PLAN: + if( pStmt ) zRet = pStmt->zEQP; + break; + case EXPERT_REPORT_CANDIDATES: + zRet = p->zCandidates; + break; + } + return zRet; } /* ** Free an sqlite3expert object. */ void sqlite3_expert_destroy(sqlite3expert *p){ - if( p ){ - sqlite3_close(p->dbm); - sqlite3_close(p->dbv); - idxScanFree(p->pScan, 0); - idxStatementFree(p->pStatement, 0); - idxTableFree(p->pTable); - idxWriteFree(p->pWrite); - idxHashClear(&p->hIdx); - sqlite3_free(p->zCandidates); - sqlite3_free(p); - } + if( p ){ + sqlite3_close(p->dbm); + sqlite3_close(p->dbv); + idxScanFree(p->pScan, 0); + idxStatementFree(p->pStatement, 0); + idxTableFree(p->pTable); + idxWriteFree(p->pWrite); + idxHashClear(&p->hIdx); + sqlite3_free(p->zCandidates); + sqlite3_free(p); + } } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ @@ -11320,7 +11320,7 @@ void sqlite3_expert_destroy(sqlite3expert *p){ ** INSERT INTO t1(rowid, a, b) VALUES(5, 'v', 'five'); ** INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten'); ** -** the sqlite_dbdata table contains, as well as from entries related to +** the sqlite_dbdata table contains, as well as from entries related to ** page 1, content equivalent to: ** ** INSERT INTO sqlite_dbdata(pgno, cell, field, value) VALUES @@ -11347,7 +11347,7 @@ void sqlite3_expert_destroy(sqlite3expert *p){ ** It contains one entry for each b-tree pointer between a parent and ** child page in the database. */ -#if !defined(SQLITEINT_H) +#if !defined(SQLITEINT_H) /* #include "sqlite3ext.h" */ /* typedef unsigned char u8; */ @@ -11357,42 +11357,42 @@ SQLITE_EXTENSION_INIT1 #include #include -#define DBDATA_PADDING_BYTES 100 +#define DBDATA_PADDING_BYTES 100 typedef struct DbdataTable DbdataTable; typedef struct DbdataCursor DbdataCursor; /* Cursor object */ struct DbdataCursor { - sqlite3_vtab_cursor base; /* Base class. Must be first */ - sqlite3_stmt *pStmt; /* For fetching database pages */ - - int iPgno; /* Current page number */ - u8 *aPage; /* Buffer containing page */ - int nPage; /* Size of aPage[] in bytes */ - int nCell; /* Number of cells on aPage[] */ - int iCell; /* Current cell number */ - int bOnePage; /* True to stop after one page */ - int szDb; - sqlite3_int64 iRowid; - - /* Only for the sqlite_dbdata table */ - u8 *pRec; /* Buffer containing current record */ - int nRec; /* Size of pRec[] in bytes */ - int nHdr; /* Size of header in bytes */ - int iField; /* Current field number */ - u8 *pHdrPtr; - u8 *pPtr; - - sqlite3_int64 iIntkey; /* Integer key value */ + sqlite3_vtab_cursor base; /* Base class. Must be first */ + sqlite3_stmt *pStmt; /* For fetching database pages */ + + int iPgno; /* Current page number */ + u8 *aPage; /* Buffer containing page */ + int nPage; /* Size of aPage[] in bytes */ + int nCell; /* Number of cells on aPage[] */ + int iCell; /* Current cell number */ + int bOnePage; /* True to stop after one page */ + int szDb; + sqlite3_int64 iRowid; + + /* Only for the sqlite_dbdata table */ + u8 *pRec; /* Buffer containing current record */ + int nRec; /* Size of pRec[] in bytes */ + int nHdr; /* Size of header in bytes */ + int iField; /* Current field number */ + u8 *pHdrPtr; + u8 *pPtr; + + sqlite3_int64 iIntkey; /* Integer key value */ }; /* Table object */ struct DbdataTable { - sqlite3_vtab base; /* Base class. Must be first */ - sqlite3 *db; /* The database connection */ - sqlite3_stmt *pStmt; /* For fetching database pages */ - int bPtr; /* True for sqlite3_dbptr table */ + sqlite3_vtab base; /* Base class. Must be first */ + sqlite3 *db; /* The database connection */ + sqlite3_stmt *pStmt; /* For fetching database pages */ + int bPtr; /* True for sqlite3_dbptr table */ }; /* Column and schema definitions for sqlite_dbdata */ @@ -11422,44 +11422,44 @@ struct DbdataTable { ")" /* -** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual +** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual ** table. */ static int dbdataConnect( - sqlite3 *db, - void *pAux, - int argc, const char *const*argv, - sqlite3_vtab **ppVtab, - char **pzErr + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr ){ - DbdataTable *pTab = 0; - int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA); + DbdataTable *pTab = 0; + int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA); - if( rc==SQLITE_OK ){ - pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable)); - if( pTab==0 ){ - rc = SQLITE_NOMEM; - }else{ - memset(pTab, 0, sizeof(DbdataTable)); - pTab->db = db; - pTab->bPtr = (pAux!=0); - } + if( rc==SQLITE_OK ){ + pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable)); + if( pTab==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pTab, 0, sizeof(DbdataTable)); + pTab->db = db; + pTab->bPtr = (pAux!=0); } + } - *ppVtab = (sqlite3_vtab*)pTab; - return rc; + *ppVtab = (sqlite3_vtab*)pTab; + return rc; } /* ** Disconnect from or destroy a sqlite_dbdata or sqlite_dbptr virtual table. */ static int dbdataDisconnect(sqlite3_vtab *pVtab){ - DbdataTable *pTab = (DbdataTable*)pVtab; - if( pTab ){ - sqlite3_finalize(pTab->pStmt); - sqlite3_free(pVtab); - } - return SQLITE_OK; + DbdataTable *pTab = (DbdataTable*)pVtab; + if( pTab ){ + sqlite3_finalize(pTab->pStmt); + sqlite3_free(pVtab); + } + return SQLITE_OK; } /* @@ -11476,113 +11476,113 @@ static int dbdataDisconnect(sqlite3_vtab *pVtab){ ** position 1. */ static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdx){ - DbdataTable *pTab = (DbdataTable*)tab; - int i; - int iSchema = -1; - int iPgno = -1; - int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA); - - for(i=0; inConstraint; i++){ - struct sqlite3_index_constraint *p = &pIdx->aConstraint[i]; - if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ - if( p->iColumn==colSchema ){ - if( p->usable==0 ) return SQLITE_CONSTRAINT; - iSchema = i; - } - if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){ - iPgno = i; - } - } - } - - if( iSchema>=0 ){ - pIdx->aConstraintUsage[iSchema].argvIndex = 1; - pIdx->aConstraintUsage[iSchema].omit = 1; - } - if( iPgno>=0 ){ - pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0); - pIdx->aConstraintUsage[iPgno].omit = 1; - pIdx->estimatedCost = 100; - pIdx->estimatedRows = 50; - - if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){ - int iCol = pIdx->aOrderBy[0].iColumn; - if( pIdx->nOrderBy==1 ){ - pIdx->orderByConsumed = (iCol==0 || iCol==1); - }else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){ - pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1); - } - } - - }else{ - pIdx->estimatedCost = 100000000; - pIdx->estimatedRows = 1000000000; - } - pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00); - return SQLITE_OK; + DbdataTable *pTab = (DbdataTable*)tab; + int i; + int iSchema = -1; + int iPgno = -1; + int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA); + + for(i=0; inConstraint; i++){ + struct sqlite3_index_constraint *p = &pIdx->aConstraint[i]; + if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + if( p->iColumn==colSchema ){ + if( p->usable==0 ) return SQLITE_CONSTRAINT; + iSchema = i; + } + if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){ + iPgno = i; + } + } + } + + if( iSchema>=0 ){ + pIdx->aConstraintUsage[iSchema].argvIndex = 1; + pIdx->aConstraintUsage[iSchema].omit = 1; + } + if( iPgno>=0 ){ + pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0); + pIdx->aConstraintUsage[iPgno].omit = 1; + pIdx->estimatedCost = 100; + pIdx->estimatedRows = 50; + + if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){ + int iCol = pIdx->aOrderBy[0].iColumn; + if( pIdx->nOrderBy==1 ){ + pIdx->orderByConsumed = (iCol==0 || iCol==1); + }else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){ + pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1); + } + } + + }else{ + pIdx->estimatedCost = 100000000; + pIdx->estimatedRows = 1000000000; + } + pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00); + return SQLITE_OK; } /* ** Open a new sqlite_dbdata or sqlite_dbptr cursor. */ static int dbdataOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ - DbdataCursor *pCsr; + DbdataCursor *pCsr; - pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor)); - if( pCsr==0 ){ - return SQLITE_NOMEM; - }else{ - memset(pCsr, 0, sizeof(DbdataCursor)); - pCsr->base.pVtab = pVTab; - } + pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor)); + if( pCsr==0 ){ + return SQLITE_NOMEM; + }else{ + memset(pCsr, 0, sizeof(DbdataCursor)); + pCsr->base.pVtab = pVTab; + } - *ppCursor = (sqlite3_vtab_cursor *)pCsr; - return SQLITE_OK; + *ppCursor = (sqlite3_vtab_cursor *)pCsr; + return SQLITE_OK; } /* -** Restore a cursor object to the state it was in when first allocated +** Restore a cursor object to the state it was in when first allocated ** by dbdataOpen(). */ static void dbdataResetCursor(DbdataCursor *pCsr){ - DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab); - if( pTab->pStmt==0 ){ - pTab->pStmt = pCsr->pStmt; - }else{ - sqlite3_finalize(pCsr->pStmt); - } - pCsr->pStmt = 0; - pCsr->iPgno = 1; - pCsr->iCell = 0; - pCsr->iField = 0; - pCsr->bOnePage = 0; - sqlite3_free(pCsr->aPage); - sqlite3_free(pCsr->pRec); - pCsr->pRec = 0; - pCsr->aPage = 0; + DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab); + if( pTab->pStmt==0 ){ + pTab->pStmt = pCsr->pStmt; + }else{ + sqlite3_finalize(pCsr->pStmt); + } + pCsr->pStmt = 0; + pCsr->iPgno = 1; + pCsr->iCell = 0; + pCsr->iField = 0; + pCsr->bOnePage = 0; + sqlite3_free(pCsr->aPage); + sqlite3_free(pCsr->pRec); + pCsr->pRec = 0; + pCsr->aPage = 0; } /* ** Close an sqlite_dbdata or sqlite_dbptr cursor. */ static int dbdataClose(sqlite3_vtab_cursor *pCursor){ - DbdataCursor *pCsr = (DbdataCursor*)pCursor; - dbdataResetCursor(pCsr); - sqlite3_free(pCsr); - return SQLITE_OK; + DbdataCursor *pCsr = (DbdataCursor*)pCursor; + dbdataResetCursor(pCsr); + sqlite3_free(pCsr); + return SQLITE_OK; } -/* -** Utility methods to decode 16 and 32-bit big-endian unsigned integers. +/* +** Utility methods to decode 16 and 32-bit big-endian unsigned integers. */ static unsigned int get_uint16(unsigned char *a){ - return (a[0]<<8)|a[1]; + return (a[0]<<8)|a[1]; } static unsigned int get_uint32(unsigned char *a){ - return ((unsigned int)a[0]<<24) - | ((unsigned int)a[1]<<16) - | ((unsigned int)a[2]<<8) - | ((unsigned int)a[3]); + return ((unsigned int)a[0]<<24) + | ((unsigned int)a[1]<<16) + | ((unsigned int)a[2]<<8) + | ((unsigned int)a[3]); } /* @@ -11596,53 +11596,53 @@ static unsigned int get_uint32(unsigned char *a){ ** return an SQLite error code. */ static int dbdataLoadPage( - DbdataCursor *pCsr, /* Cursor object */ - unsigned int pgno, /* Page number of page to load */ - u8 **ppPage, /* OUT: pointer to page buffer */ - int *pnPage /* OUT: Size of (*ppPage) in bytes */ + DbdataCursor *pCsr, /* Cursor object */ + unsigned int pgno, /* Page number of page to load */ + u8 **ppPage, /* OUT: pointer to page buffer */ + int *pnPage /* OUT: Size of (*ppPage) in bytes */ ){ - int rc2; - int rc = SQLITE_OK; - sqlite3_stmt *pStmt = pCsr->pStmt; - - *ppPage = 0; - *pnPage = 0; - sqlite3_bind_int64(pStmt, 2, pgno); - if( SQLITE_ROW==sqlite3_step(pStmt) ){ - int nCopy = sqlite3_column_bytes(pStmt, 0); - if( nCopy>0 ){ - u8 *pPage; - pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES); - if( pPage==0 ){ - rc = SQLITE_NOMEM; - }else{ - const u8 *pCopy = sqlite3_column_blob(pStmt, 0); - memcpy(pPage, pCopy, nCopy); - memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES); - } - *ppPage = pPage; - *pnPage = nCopy; - } + int rc2; + int rc = SQLITE_OK; + sqlite3_stmt *pStmt = pCsr->pStmt; + + *ppPage = 0; + *pnPage = 0; + sqlite3_bind_int64(pStmt, 2, pgno); + if( SQLITE_ROW==sqlite3_step(pStmt) ){ + int nCopy = sqlite3_column_bytes(pStmt, 0); + if( nCopy>0 ){ + u8 *pPage; + pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES); + if( pPage==0 ){ + rc = SQLITE_NOMEM; + }else{ + const u8 *pCopy = sqlite3_column_blob(pStmt, 0); + memcpy(pPage, pCopy, nCopy); + memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES); + } + *ppPage = pPage; + *pnPage = nCopy; } - rc2 = sqlite3_reset(pStmt); - if( rc==SQLITE_OK ) rc = rc2; + } + rc2 = sqlite3_reset(pStmt); + if( rc==SQLITE_OK ) rc = rc2; - return rc; + return rc; } /* ** Read a varint. Put the value in *pVal and return the number of bytes. */ static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){ - sqlite3_int64 v = 0; - int i; - for(i=0; i<8; i++){ - v = (v<<7) + (z[i]&0x7f); - if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } - } - v = (v<<8) + (z[i]&0xff); - *pVal = v; - return 9; + sqlite3_int64 v = 0; + int i; + for(i=0; i<8; i++){ + v = (v<<7) + (z[i]&0x7f); + if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } + } + v = (v<<8) + (z[i]&0xff); + *pVal = v; + return 9; } /* @@ -11650,29 +11650,29 @@ static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){ ** eType. */ static int dbdataValueBytes(int eType){ - switch( eType ){ - case 0: case 8: case 9: - case 10: case 11: - return 0; - case 1: - return 1; - case 2: - return 2; - case 3: - return 3; - case 4: - return 4; - case 5: - return 6; - case 6: - case 7: - return 8; - default: - if( eType>0 ){ - return ((eType-12) / 2); - } - return 0; - } + switch( eType ){ + case 0: case 8: case 9: + case 10: case 11: + return 0; + case 1: + return 1; + case 2: + return 2; + case 3: + return 3; + case 4: + return 4; + case 5: + return 6; + case 6: + case 7: + return 8; + default: + if( eType>0 ){ + return ((eType-12) / 2); + } + return 0; + } } /* @@ -11680,399 +11680,399 @@ static int dbdataValueBytes(int eType){ ** result of context object pCtx. */ static void dbdataValue( - sqlite3_context *pCtx, - int eType, - u8 *pData, - int nData + sqlite3_context *pCtx, + int eType, + u8 *pData, + int nData ){ - if( eType>=0 && dbdataValueBytes(eType)<=nData ){ + if( eType>=0 && dbdataValueBytes(eType)<=nData ){ + switch( eType ){ + case 0: + case 10: + case 11: + sqlite3_result_null(pCtx); + break; + + case 8: + sqlite3_result_int(pCtx, 0); + break; + case 9: + sqlite3_result_int(pCtx, 1); + break; + + case 1: case 2: case 3: case 4: case 5: case 6: case 7: { + sqlite3_uint64 v = (signed char)pData[0]; + pData++; switch( eType ){ - case 0: - case 10: - case 11: - sqlite3_result_null(pCtx); - break; - - case 8: - sqlite3_result_int(pCtx, 0); - break; - case 9: - sqlite3_result_int(pCtx, 1); - break; - - case 1: case 2: case 3: case 4: case 5: case 6: case 7: { - sqlite3_uint64 v = (signed char)pData[0]; - pData++; - switch( eType ){ - case 7: - case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; - case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; - case 4: v = (v<<8) + pData[0]; pData++; - case 3: v = (v<<8) + pData[0]; pData++; - case 2: v = (v<<8) + pData[0]; pData++; - } - - if( eType==7 ){ - double r; - memcpy(&r, &v, sizeof(r)); - sqlite3_result_double(pCtx, r); - }else{ - sqlite3_result_int64(pCtx, (sqlite3_int64)v); - } - break; - } - - default: { - int n = ((eType-12) / 2); - if( eType % 2 ){ - sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT); - }else{ - sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT); - } - } + case 7: + case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; + case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; + case 4: v = (v<<8) + pData[0]; pData++; + case 3: v = (v<<8) + pData[0]; pData++; + case 2: v = (v<<8) + pData[0]; pData++; + } + + if( eType==7 ){ + double r; + memcpy(&r, &v, sizeof(r)); + sqlite3_result_double(pCtx, r); + }else{ + sqlite3_result_int64(pCtx, (sqlite3_int64)v); + } + break; + } + + default: { + int n = ((eType-12) / 2); + if( eType % 2 ){ + sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT); + }else{ + sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT); } + } } + } } /* ** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry. */ static int dbdataNext(sqlite3_vtab_cursor *pCursor){ - DbdataCursor *pCsr = (DbdataCursor*)pCursor; - DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; + DbdataCursor *pCsr = (DbdataCursor*)pCursor; + DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; - pCsr->iRowid++; - while( 1 ){ - int rc; - int iOff = (pCsr->iPgno==1 ? 100 : 0); - int bNextPage = 0; - - if( pCsr->aPage==0 ){ - while( 1 ){ - if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK; - rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); - if( rc!=SQLITE_OK ) return rc; - if( pCsr->aPage ) break; - pCsr->iPgno++; - } - pCsr->iCell = pTab->bPtr ? -2 : 0; - pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); + pCsr->iRowid++; + while( 1 ){ + int rc; + int iOff = (pCsr->iPgno==1 ? 100 : 0); + int bNextPage = 0; + + if( pCsr->aPage==0 ){ + while( 1 ){ + if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK; + rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage); + if( rc!=SQLITE_OK ) return rc; + if( pCsr->aPage ) break; + pCsr->iPgno++; + } + pCsr->iCell = pTab->bPtr ? -2 : 0; + pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]); + } + + if( pTab->bPtr ){ + if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){ + pCsr->iCell = pCsr->nCell; + } + pCsr->iCell++; + if( pCsr->iCell>=pCsr->nCell ){ + sqlite3_free(pCsr->aPage); + pCsr->aPage = 0; + if( pCsr->bOnePage ) return SQLITE_OK; + pCsr->iPgno++; + }else{ + return SQLITE_OK; + } + }else{ + /* If there is no record loaded, load it now. */ + if( pCsr->pRec==0 ){ + int bHasRowid = 0; + int nPointer = 0; + sqlite3_int64 nPayload = 0; + sqlite3_int64 nHdr = 0; + int iHdr; + int U, X; + int nLocal; + + switch( pCsr->aPage[iOff] ){ + case 0x02: + nPointer = 4; + break; + case 0x0a: + break; + case 0x0d: + bHasRowid = 1; + break; + default: + /* This is not a b-tree page with records on it. Continue. */ + pCsr->iCell = pCsr->nCell; + break; } - if( pTab->bPtr ){ - if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){ - pCsr->iCell = pCsr->nCell; - } - pCsr->iCell++; - if( pCsr->iCell>=pCsr->nCell ){ - sqlite3_free(pCsr->aPage); - pCsr->aPage = 0; - if( pCsr->bOnePage ) return SQLITE_OK; - pCsr->iPgno++; - }else{ - return SQLITE_OK; - } + if( pCsr->iCell>=pCsr->nCell ){ + bNextPage = 1; }else{ - /* If there is no record loaded, load it now. */ - if( pCsr->pRec==0 ){ - int bHasRowid = 0; - int nPointer = 0; - sqlite3_int64 nPayload = 0; - sqlite3_int64 nHdr = 0; - int iHdr; - int U, X; - int nLocal; - - switch( pCsr->aPage[iOff] ){ - case 0x02: - nPointer = 4; - break; - case 0x0a: - break; - case 0x0d: - bHasRowid = 1; - break; - default: - /* This is not a b-tree page with records on it. Continue. */ - pCsr->iCell = pCsr->nCell; - break; - } - - if( pCsr->iCell>=pCsr->nCell ){ - bNextPage = 1; - }else{ - - iOff += 8 + nPointer + pCsr->iCell*2; - if( iOff>pCsr->nPage ){ - bNextPage = 1; - }else{ - iOff = get_uint16(&pCsr->aPage[iOff]); - } - - /* For an interior node cell, skip past the child-page number */ - iOff += nPointer; - - /* Load the "byte of payload including overflow" field */ - if( bNextPage || iOff>pCsr->nPage ){ - bNextPage = 1; - }else{ - iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload); - } - - /* If this is a leaf intkey cell, load the rowid */ - if( bHasRowid && !bNextPage && iOffnPage ){ - iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey); - } - - /* Figure out how much data to read from the local page */ - U = pCsr->nPage; - if( bHasRowid ){ - X = U-35; - }else{ - X = ((U-12)*64/255)-23; - } - if( nPayload<=X ){ - nLocal = nPayload; - }else{ - int M, K; - M = ((U-12)*32/255)-23; - K = M+((nPayload-M)%(U-4)); - if( K<=X ){ - nLocal = K; - }else{ - nLocal = M; - } - } - - if( bNextPage || nLocal+iOff>pCsr->nPage ){ - bNextPage = 1; - }else{ - - /* Allocate space for payload. And a bit more to catch small buffer - ** overruns caused by attempting to read a varint or similar from - ** near the end of a corrupt record. */ - pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES); - if( pCsr->pRec==0 ) return SQLITE_NOMEM; - memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES); - pCsr->nRec = nPayload; - - /* Load the nLocal bytes of payload */ - memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal); - iOff += nLocal; - - /* Load content from overflow pages */ - if( nPayload>nLocal ){ - sqlite3_int64 nRem = nPayload - nLocal; - unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]); - while( nRem>0 ){ - u8 *aOvfl = 0; - int nOvfl = 0; - int nCopy; - rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl); - assert( rc!=SQLITE_OK || aOvfl==0 || nOvfl==pCsr->nPage ); - if( rc!=SQLITE_OK ) return rc; - if( aOvfl==0 ) break; - - nCopy = U-4; - if( nCopy>nRem ) nCopy = nRem; - memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy); - nRem -= nCopy; - - pgnoOvfl = get_uint32(aOvfl); - sqlite3_free(aOvfl); - } - } - - iHdr = dbdataGetVarint(pCsr->pRec, &nHdr); - pCsr->nHdr = nHdr; - pCsr->pHdrPtr = &pCsr->pRec[iHdr]; - pCsr->pPtr = &pCsr->pRec[pCsr->nHdr]; - pCsr->iField = (bHasRowid ? -1 : 0); - } - } + + iOff += 8 + nPointer + pCsr->iCell*2; + if( iOff>pCsr->nPage ){ + bNextPage = 1; + }else{ + iOff = get_uint16(&pCsr->aPage[iOff]); + } + + /* For an interior node cell, skip past the child-page number */ + iOff += nPointer; + + /* Load the "byte of payload including overflow" field */ + if( bNextPage || iOff>pCsr->nPage ){ + bNextPage = 1; + }else{ + iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload); + } + + /* If this is a leaf intkey cell, load the rowid */ + if( bHasRowid && !bNextPage && iOffnPage ){ + iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey); + } + + /* Figure out how much data to read from the local page */ + U = pCsr->nPage; + if( bHasRowid ){ + X = U-35; + }else{ + X = ((U-12)*64/255)-23; + } + if( nPayload<=X ){ + nLocal = nPayload; + }else{ + int M, K; + M = ((U-12)*32/255)-23; + K = M+((nPayload-M)%(U-4)); + if( K<=X ){ + nLocal = K; }else{ - pCsr->iField++; - if( pCsr->iField>0 ){ - sqlite3_int64 iType; - if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){ - bNextPage = 1; - }else{ - pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType); - pCsr->pPtr += dbdataValueBytes(iType); - } - } + nLocal = M; } + } - if( bNextPage ){ - sqlite3_free(pCsr->aPage); - sqlite3_free(pCsr->pRec); - pCsr->aPage = 0; - pCsr->pRec = 0; - if( pCsr->bOnePage ) return SQLITE_OK; - pCsr->iPgno++; - }else{ - if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){ - return SQLITE_OK; - } + if( bNextPage || nLocal+iOff>pCsr->nPage ){ + bNextPage = 1; + }else{ - /* Advance to the next cell. The next iteration of the loop will load + /* Allocate space for payload. And a bit more to catch small buffer + ** overruns caused by attempting to read a varint or similar from + ** near the end of a corrupt record. */ + pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES); + if( pCsr->pRec==0 ) return SQLITE_NOMEM; + memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES); + pCsr->nRec = nPayload; + + /* Load the nLocal bytes of payload */ + memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal); + iOff += nLocal; + + /* Load content from overflow pages */ + if( nPayload>nLocal ){ + sqlite3_int64 nRem = nPayload - nLocal; + unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]); + while( nRem>0 ){ + u8 *aOvfl = 0; + int nOvfl = 0; + int nCopy; + rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl); + assert( rc!=SQLITE_OK || aOvfl==0 || nOvfl==pCsr->nPage ); + if( rc!=SQLITE_OK ) return rc; + if( aOvfl==0 ) break; + + nCopy = U-4; + if( nCopy>nRem ) nCopy = nRem; + memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy); + nRem -= nCopy; + + pgnoOvfl = get_uint32(aOvfl); + sqlite3_free(aOvfl); + } + } + + iHdr = dbdataGetVarint(pCsr->pRec, &nHdr); + pCsr->nHdr = nHdr; + pCsr->pHdrPtr = &pCsr->pRec[iHdr]; + pCsr->pPtr = &pCsr->pRec[pCsr->nHdr]; + pCsr->iField = (bHasRowid ? -1 : 0); + } + } + }else{ + pCsr->iField++; + if( pCsr->iField>0 ){ + sqlite3_int64 iType; + if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){ + bNextPage = 1; + }else{ + pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType); + pCsr->pPtr += dbdataValueBytes(iType); + } + } + } + + if( bNextPage ){ + sqlite3_free(pCsr->aPage); + sqlite3_free(pCsr->pRec); + pCsr->aPage = 0; + pCsr->pRec = 0; + if( pCsr->bOnePage ) return SQLITE_OK; + pCsr->iPgno++; + }else{ + if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){ + return SQLITE_OK; + } + + /* Advance to the next cell. The next iteration of the loop will load ** the record and so on. */ - sqlite3_free(pCsr->pRec); - pCsr->pRec = 0; - pCsr->iCell++; - } - } + sqlite3_free(pCsr->pRec); + pCsr->pRec = 0; + pCsr->iCell++; + } } + } - assert( !"can't get here" ); - return SQLITE_OK; + assert( !"can't get here" ); + return SQLITE_OK; } -/* +/* ** Return true if the cursor is at EOF. */ static int dbdataEof(sqlite3_vtab_cursor *pCursor){ - DbdataCursor *pCsr = (DbdataCursor*)pCursor; - return pCsr->aPage==0; + DbdataCursor *pCsr = (DbdataCursor*)pCursor; + return pCsr->aPage==0; } -/* +/* ** Determine the size in pages of database zSchema (where zSchema is -** "main", "temp" or the name of an attached database) and set +** "main", "temp" or the name of an attached database) and set ** pCsr->szDb accordingly. If successful, return SQLITE_OK. Otherwise, ** an SQLite error code. */ static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){ - DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab; - char *zSql = 0; - int rc, rc2; - sqlite3_stmt *pStmt = 0; - - zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema); - if( zSql==0 ) return SQLITE_NOMEM; - rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - pCsr->szDb = sqlite3_column_int(pStmt, 0); - } - rc2 = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ) rc = rc2; - return rc; -} - -/* + DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab; + char *zSql = 0; + int rc, rc2; + sqlite3_stmt *pStmt = 0; + + zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema); + if( zSql==0 ) return SQLITE_NOMEM; + rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ + pCsr->szDb = sqlite3_column_int(pStmt, 0); + } + rc2 = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) rc = rc2; + return rc; +} + +/* ** xFilter method for sqlite_dbdata and sqlite_dbptr. */ static int dbdataFilter( - sqlite3_vtab_cursor *pCursor, - int idxNum, const char *idxStr, - int argc, sqlite3_value **argv + sqlite3_vtab_cursor *pCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv ){ - DbdataCursor *pCsr = (DbdataCursor*)pCursor; - DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; - int rc = SQLITE_OK; - const char *zSchema = "main"; - - dbdataResetCursor(pCsr); - assert( pCsr->iPgno==1 ); - if( idxNum & 0x01 ){ - zSchema = (const char*)sqlite3_value_text(argv[0]); - } - if( idxNum & 0x02 ){ - pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); - pCsr->bOnePage = 1; + DbdataCursor *pCsr = (DbdataCursor*)pCursor; + DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; + int rc = SQLITE_OK; + const char *zSchema = "main"; + + dbdataResetCursor(pCsr); + assert( pCsr->iPgno==1 ); + if( idxNum & 0x01 ){ + zSchema = (const char*)sqlite3_value_text(argv[0]); + } + if( idxNum & 0x02 ){ + pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]); + pCsr->bOnePage = 1; + }else{ + pCsr->nPage = dbdataDbsize(pCsr, zSchema); + rc = dbdataDbsize(pCsr, zSchema); + } + + if( rc==SQLITE_OK ){ + if( pTab->pStmt ){ + pCsr->pStmt = pTab->pStmt; + pTab->pStmt = 0; }else{ - pCsr->nPage = dbdataDbsize(pCsr, zSchema); - rc = dbdataDbsize(pCsr, zSchema); - } - - if( rc==SQLITE_OK ){ - if( pTab->pStmt ){ - pCsr->pStmt = pTab->pStmt; - pTab->pStmt = 0; + rc = sqlite3_prepare_v2(pTab->db, + "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1, + &pCsr->pStmt, 0 + ); + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT); + }else{ + pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); + } + if( rc==SQLITE_OK ){ + rc = dbdataNext(pCursor); + } + return rc; +} + +/* +** Return a column for the sqlite_dbdata or sqlite_dbptr table. +*/ +static int dbdataColumn( + sqlite3_vtab_cursor *pCursor, + sqlite3_context *ctx, + int i +){ + DbdataCursor *pCsr = (DbdataCursor*)pCursor; + DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; + if( pTab->bPtr ){ + switch( i ){ + case DBPTR_COLUMN_PGNO: + sqlite3_result_int64(ctx, pCsr->iPgno); + break; + case DBPTR_COLUMN_CHILD: { + int iOff = pCsr->iPgno==1 ? 100 : 0; + if( pCsr->iCell<0 ){ + iOff += 8; }else{ - rc = sqlite3_prepare_v2(pTab->db, - "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1, - &pCsr->pStmt, 0 - ); + iOff += 12 + pCsr->iCell*2; + if( iOff>pCsr->nPage ) return SQLITE_OK; + iOff = get_uint16(&pCsr->aPage[iOff]); } + if( iOff<=pCsr->nPage ){ + sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff])); + } + break; + } } - if( rc==SQLITE_OK ){ - rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT); - }else{ - pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db)); - } - if( rc==SQLITE_OK ){ - rc = dbdataNext(pCursor); + }else{ + switch( i ){ + case DBDATA_COLUMN_PGNO: + sqlite3_result_int64(ctx, pCsr->iPgno); + break; + case DBDATA_COLUMN_CELL: + sqlite3_result_int(ctx, pCsr->iCell); + break; + case DBDATA_COLUMN_FIELD: + sqlite3_result_int(ctx, pCsr->iField); + break; + case DBDATA_COLUMN_VALUE: { + if( pCsr->iField<0 ){ + sqlite3_result_int64(ctx, pCsr->iIntkey); + }else{ + sqlite3_int64 iType; + dbdataGetVarint(pCsr->pHdrPtr, &iType); + dbdataValue( + ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr + ); + } + break; + } } - return rc; + } + return SQLITE_OK; } -/* -** Return a column for the sqlite_dbdata or sqlite_dbptr table. -*/ -static int dbdataColumn( - sqlite3_vtab_cursor *pCursor, - sqlite3_context *ctx, - int i -){ - DbdataCursor *pCsr = (DbdataCursor*)pCursor; - DbdataTable *pTab = (DbdataTable*)pCursor->pVtab; - if( pTab->bPtr ){ - switch( i ){ - case DBPTR_COLUMN_PGNO: - sqlite3_result_int64(ctx, pCsr->iPgno); - break; - case DBPTR_COLUMN_CHILD: { - int iOff = pCsr->iPgno==1 ? 100 : 0; - if( pCsr->iCell<0 ){ - iOff += 8; - }else{ - iOff += 12 + pCsr->iCell*2; - if( iOff>pCsr->nPage ) return SQLITE_OK; - iOff = get_uint16(&pCsr->aPage[iOff]); - } - if( iOff<=pCsr->nPage ){ - sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff])); - } - break; - } - } - }else{ - switch( i ){ - case DBDATA_COLUMN_PGNO: - sqlite3_result_int64(ctx, pCsr->iPgno); - break; - case DBDATA_COLUMN_CELL: - sqlite3_result_int(ctx, pCsr->iCell); - break; - case DBDATA_COLUMN_FIELD: - sqlite3_result_int(ctx, pCsr->iField); - break; - case DBDATA_COLUMN_VALUE: { - if( pCsr->iField<0 ){ - sqlite3_result_int64(ctx, pCsr->iIntkey); - }else{ - sqlite3_int64 iType; - dbdataGetVarint(pCsr->pHdrPtr, &iType); - dbdataValue( - ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr - ); - } - break; - } - } - } - return SQLITE_OK; -} - -/* -** Return the rowid for an sqlite_dbdata or sqlite_dptr table. +/* +** Return the rowid for an sqlite_dbdata or sqlite_dptr table. */ static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ - DbdataCursor *pCsr = (DbdataCursor*)pCursor; - *pRowid = pCsr->iRowid; - return SQLITE_OK; + DbdataCursor *pCsr = (DbdataCursor*)pCursor; + *pRowid = pCsr->iRowid; + return SQLITE_OK; } @@ -12080,50 +12080,50 @@ static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ ** Invoke this routine to register the "sqlite_dbdata" virtual table module */ static int sqlite3DbdataRegister(sqlite3 *db){ - static sqlite3_module dbdata_module = { - 0, /* iVersion */ - 0, /* xCreate */ - dbdataConnect, /* xConnect */ - dbdataBestIndex, /* xBestIndex */ - dbdataDisconnect, /* xDisconnect */ - 0, /* xDestroy */ - dbdataOpen, /* xOpen - open a cursor */ - dbdataClose, /* xClose - close a cursor */ - dbdataFilter, /* xFilter - configure scan constraints */ - dbdataNext, /* xNext - advance a cursor */ - dbdataEof, /* xEof - check for end of scan */ - dbdataColumn, /* xColumn - read data */ - dbdataRowid, /* xRowid - read data */ - 0, /* xUpdate */ - 0, /* xBegin */ - 0, /* xSync */ - 0, /* xCommit */ - 0, /* xRollback */ - 0, /* xFindMethod */ - 0, /* xRename */ - 0, /* xSavepoint */ - 0, /* xRelease */ - 0, /* xRollbackTo */ - 0 /* xShadowName */ - }; - - int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1); - } - return rc; + static sqlite3_module dbdata_module = { + 0, /* iVersion */ + 0, /* xCreate */ + dbdataConnect, /* xConnect */ + dbdataBestIndex, /* xBestIndex */ + dbdataDisconnect, /* xDisconnect */ + 0, /* xDestroy */ + dbdataOpen, /* xOpen - open a cursor */ + dbdataClose, /* xClose - close a cursor */ + dbdataFilter, /* xFilter - configure scan constraints */ + dbdataNext, /* xNext - advance a cursor */ + dbdataEof, /* xEof - check for end of scan */ + dbdataColumn, /* xColumn - read data */ + dbdataRowid, /* xRowid - read data */ + 0, /* xUpdate */ + 0, /* xBegin */ + 0, /* xSync */ + 0, /* xCommit */ + 0, /* xRollback */ + 0, /* xFindMethod */ + 0, /* xRename */ + 0, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ + 0 /* xShadowName */ + }; + + int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1); + } + return rc; } #ifdef _WIN32 #endif int sqlite3_dbdata_init( - sqlite3 *db, - char **pzErrMsg, - const sqlite3_api_routines *pApi + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi ){ - SQLITE_EXTENSION_INIT2(pApi); - return sqlite3DbdataRegister(db); + SQLITE_EXTENSION_INIT2(pApi); + return sqlite3DbdataRegister(db); } /************************* End ../ext/misc/dbdata.c ********************/ @@ -12135,34 +12135,34 @@ int sqlite3_dbdata_init( */ typedef struct OpenSession OpenSession; struct OpenSession { - char *zName; /* Symbolic name for this session */ - int nFilter; /* Number of xFilter rejection GLOB patterns */ - char **azFilter; /* Array of xFilter rejection GLOB patterns */ - sqlite3_session *p; /* The open session */ + char *zName; /* Symbolic name for this session */ + int nFilter; /* Number of xFilter rejection GLOB patterns */ + char **azFilter; /* Array of xFilter rejection GLOB patterns */ + sqlite3_session *p; /* The open session */ }; #endif typedef struct ExpertInfo ExpertInfo; struct ExpertInfo { - sqlite3expert *pExpert; - int bVerbose; + sqlite3expert *pExpert; + int bVerbose; }; /* A single line in the EQP output */ typedef struct EQPGraphRow EQPGraphRow; struct EQPGraphRow { - int iEqpId; /* ID for this row */ - int iParentId; /* ID of the parent row */ - EQPGraphRow *pNext; /* Next row in sequence */ - char zText[1]; /* Text to display for this row */ + int iEqpId; /* ID for this row */ + int iParentId; /* ID of the parent row */ + EQPGraphRow *pNext; /* Next row in sequence */ + char zText[1]; /* Text to display for this row */ }; /* All EQP output is collected into an instance of the following */ typedef struct EQPGraph EQPGraph; struct EQPGraph { - EQPGraphRow *pRow; /* Linked list of all rows of the EQP output */ - EQPGraphRow *pLast; /* Last element of the pRow list */ - char zPrefix[100]; /* Graph prefix */ + EQPGraphRow *pRow; /* Linked list of all rows of the EQP output */ + EQPGraphRow *pLast; /* Last element of the pRow list */ + char zPrefix[100]; /* Graph prefix */ }; /* @@ -12171,72 +12171,72 @@ struct EQPGraph { */ typedef struct ShellState ShellState; struct ShellState { - sqlite3 *db; /* The database */ - u8 autoExplain; /* Automatically turn on .explain mode */ - u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ - u8 autoEQPtest; /* autoEQP is in test mode */ - u8 autoEQPtrace; /* autoEQP is in trace mode */ - u8 scanstatsOn; /* True to display scan stats before each finalize */ - u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ - u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ - u8 nEqpLevel; /* Depth of the EQP output graph */ - u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ - u8 bSafeMode; /* True to prohibit unsafe operations */ - u8 bSafeModePersist; /* The long-term value of bSafeMode */ - unsigned statsOn; /* True to display memory stats before each finalize */ - unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */ - int outCount; /* Revert to stdout when reaching zero */ - int cnt; /* Number of records displayed so far */ - int lineno; /* Line number of last line read from in */ - int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */ - FILE *in; /* Read commands from this stream */ - FILE *out; /* Write results here */ - FILE *traceOut; /* Output for sqlite3_trace() */ - int nErr; /* Number of errors seen */ - int mode; /* An output mode setting */ - int modePrior; /* Saved mode */ - int cMode; /* temporary output mode for the current query */ - int normalMode; /* Output mode before ".explain on" */ - int writableSchema; /* True if PRAGMA writable_schema=ON */ - int showHeader; /* True to show column names in List or Column mode */ - int nCheck; /* Number of ".check" commands run */ - unsigned nProgress; /* Number of progress callbacks encountered */ - unsigned mxProgress; /* Maximum progress callbacks before failing */ - unsigned flgProgress; /* Flags for the progress callback */ - unsigned shellFlgs; /* Various flags */ - unsigned priorShFlgs; /* Saved copy of flags */ - sqlite3_int64 szMax; /* --maxsize argument to .open */ - char *zDestTable; /* Name of destination table when MODE_Insert */ - char *zTempFile; /* Temporary file that might need deleting */ - char zTestcase[30]; /* Name of current test case */ - char colSeparator[20]; /* Column separator character for several modes */ - char rowSeparator[20]; /* Row separator character for MODE_Ascii */ - char colSepPrior[20]; /* Saved column separator */ - char rowSepPrior[20]; /* Saved row separator */ - int *colWidth; /* Requested width of each column in columnar modes */ - int *actualWidth; /* Actual width of each column */ - int nWidth; /* Number of slots in colWidth[] and actualWidth[] */ - char nullValue[20]; /* The text to print when a NULL comes back from + sqlite3 *db; /* The database */ + u8 autoExplain; /* Automatically turn on .explain mode */ + u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ + u8 autoEQPtest; /* autoEQP is in test mode */ + u8 autoEQPtrace; /* autoEQP is in trace mode */ + u8 scanstatsOn; /* True to display scan stats before each finalize */ + u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ + u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ + u8 nEqpLevel; /* Depth of the EQP output graph */ + u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ + u8 bSafeMode; /* True to prohibit unsafe operations */ + u8 bSafeModePersist; /* The long-term value of bSafeMode */ + unsigned statsOn; /* True to display memory stats before each finalize */ + unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */ + int outCount; /* Revert to stdout when reaching zero */ + int cnt; /* Number of records displayed so far */ + int lineno; /* Line number of last line read from in */ + int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */ + FILE *in; /* Read commands from this stream */ + FILE *out; /* Write results here */ + FILE *traceOut; /* Output for sqlite3_trace() */ + int nErr; /* Number of errors seen */ + int mode; /* An output mode setting */ + int modePrior; /* Saved mode */ + int cMode; /* temporary output mode for the current query */ + int normalMode; /* Output mode before ".explain on" */ + int writableSchema; /* True if PRAGMA writable_schema=ON */ + int showHeader; /* True to show column names in List or Column mode */ + int nCheck; /* Number of ".check" commands run */ + unsigned nProgress; /* Number of progress callbacks encountered */ + unsigned mxProgress; /* Maximum progress callbacks before failing */ + unsigned flgProgress; /* Flags for the progress callback */ + unsigned shellFlgs; /* Various flags */ + unsigned priorShFlgs; /* Saved copy of flags */ + sqlite3_int64 szMax; /* --maxsize argument to .open */ + char *zDestTable; /* Name of destination table when MODE_Insert */ + char *zTempFile; /* Temporary file that might need deleting */ + char zTestcase[30]; /* Name of current test case */ + char colSeparator[20]; /* Column separator character for several modes */ + char rowSeparator[20]; /* Row separator character for MODE_Ascii */ + char colSepPrior[20]; /* Saved column separator */ + char rowSepPrior[20]; /* Saved row separator */ + int *colWidth; /* Requested width of each column in columnar modes */ + int *actualWidth; /* Actual width of each column */ + int nWidth; /* Number of slots in colWidth[] and actualWidth[] */ + char nullValue[20]; /* The text to print when a NULL comes back from ** the database */ - char outfile[FILENAME_MAX]; /* Filename for *out */ - sqlite3_stmt *pStmt; /* Current statement if any. */ - FILE *pLog; /* Write log output here */ - struct AuxDb { /* Storage space for auxiliary database connections */ - sqlite3 *db; /* Connection pointer */ - const char *zDbFilename; /* Filename used to open the connection */ - char *zFreeOnClose; /* Free this memory allocation on close */ + char outfile[FILENAME_MAX]; /* Filename for *out */ + sqlite3_stmt *pStmt; /* Current statement if any. */ + FILE *pLog; /* Write log output here */ + struct AuxDb { /* Storage space for auxiliary database connections */ + sqlite3 *db; /* Connection pointer */ + const char *zDbFilename; /* Filename used to open the connection */ + char *zFreeOnClose; /* Free this memory allocation on close */ #if defined(SQLITE_ENABLE_SESSION) - int nSession; /* Number of active sessions */ - OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */ + int nSession; /* Number of active sessions */ + OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */ #endif - } aAuxDb[5], /* Array of all database connections */ - *pAuxDb; /* Currently active database connection */ - int *aiIndent; /* Array of indents used in MODE_Explain */ - int nIndent; /* Size of array aiIndent[] */ - int iIndent; /* Index of current op in aiIndent[] */ - char *zNonce; /* Nonce for temporary safe-mode excapes */ - EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */ - ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ + } aAuxDb[5], /* Array of all database connections */ + *pAuxDb; /* Currently active database connection */ + int *aiIndent; /* Array of indents used in MODE_Explain */ + int nIndent; /* Size of array aiIndent[] */ + int iIndent; /* Index of current op in aiIndent[] */ + char *zNonce; /* Nonce for temporary safe-mode excapes */ + EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */ + ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ }; @@ -12313,23 +12313,23 @@ struct ShellState { #define MODE_Box 16 /* Unicode box-drawing characters */ static const char *modeDescr[] = { - "line", - "column", - "list", - "semi", - "html", - "insert", - "quote", - "tcl", - "csv", - "explain", - "ascii", - "prettyprint", - "eqp", - "json", - "markdown", - "table", - "box" + "line", + "column", + "list", + "semi", + "html", + "insert", + "quote", + "tcl", + "csv", + "explain", + "ascii", + "prettyprint", + "eqp", + "json", + "markdown", + "table", + "box" }; /* @@ -12349,10 +12349,10 @@ static const char *modeDescr[] = { ** A callback for the sqlite3_log() interface. */ static void shellLog(void *pArg, int iErrCode, const char *zMsg){ - ShellState *p = (ShellState*)pArg; - if( p->pLog==0 ) return; - utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg); - fflush(p->pLog); + ShellState *p = (ShellState*)pArg; + if( p->pLog==0 ) return; + utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg); + fflush(p->pLog); } /* @@ -12362,14 +12362,14 @@ static void shellLog(void *pArg, int iErrCode, const char *zMsg){ ** adding a newline at the end, and then return X. */ static void shellPutsFunc( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal ){ - ShellState *p = (ShellState*)sqlite3_user_data(pCtx); - (void)nVal; - utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0])); - sqlite3_result_value(pCtx, apVal[0]); + ShellState *p = (ShellState*)sqlite3_user_data(pCtx); + (void)nVal; + utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0])); + sqlite3_result_value(pCtx, apVal[0]); } /* @@ -12377,20 +12377,20 @@ static void shellPutsFunc( ** and exit immediately. */ static void failIfSafeMode( - ShellState *p, - const char *zErrMsg, - ... + ShellState *p, + const char *zErrMsg, + ... ){ - if( p->bSafeMode ){ - va_list ap; - char *zMsg; - va_start(ap, zErrMsg); - zMsg = sqlite3_vmprintf(zErrMsg, ap); - va_end(ap); - raw_printf(stderr, "line %d: ", p->lineno); - utf8_printf(stderr, "%s\n", zMsg); - exit(1); - } + if( p->bSafeMode ){ + va_list ap; + char *zMsg; + va_start(ap, zErrMsg); + zMsg = sqlite3_vmprintf(zErrMsg, ap); + va_end(ap); + raw_printf(stderr, "line %d: ", p->lineno); + utf8_printf(stderr, "%s\n", zMsg); + exit(1); + } } /* @@ -12411,128 +12411,128 @@ static void failIfSafeMode( */ #ifndef SQLITE_NOHAVE_SYSTEM static void editFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - const char *zEditor; - char *zTempFile = 0; - sqlite3 *db; - char *zCmd = 0; - int bBin; - int rc; - int hasCRNL = 0; - FILE *f = 0; - sqlite3_int64 sz; - sqlite3_int64 x; - unsigned char *p = 0; - - if( argc==2 ){ - zEditor = (const char*)sqlite3_value_text(argv[1]); - }else{ - zEditor = getenv("VISUAL"); - } - if( zEditor==0 ){ - sqlite3_result_error(context, "no editor for edit()", -1); - return; - } - if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ - sqlite3_result_error(context, "NULL input to edit()", -1); - return; - } - db = sqlite3_context_db_handle(context); - zTempFile = 0; - sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile); + const char *zEditor; + char *zTempFile = 0; + sqlite3 *db; + char *zCmd = 0; + int bBin; + int rc; + int hasCRNL = 0; + FILE *f = 0; + sqlite3_int64 sz; + sqlite3_int64 x; + unsigned char *p = 0; + + if( argc==2 ){ + zEditor = (const char*)sqlite3_value_text(argv[1]); + }else{ + zEditor = getenv("VISUAL"); + } + if( zEditor==0 ){ + sqlite3_result_error(context, "no editor for edit()", -1); + return; + } + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ + sqlite3_result_error(context, "NULL input to edit()", -1); + return; + } + db = sqlite3_context_db_handle(context); + zTempFile = 0; + sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile); + if( zTempFile==0 ){ + sqlite3_uint64 r = 0; + sqlite3_randomness(sizeof(r), &r); + zTempFile = sqlite3_mprintf("temp%llx", r); if( zTempFile==0 ){ - sqlite3_uint64 r = 0; - sqlite3_randomness(sizeof(r), &r); - zTempFile = sqlite3_mprintf("temp%llx", r); - if( zTempFile==0 ){ - sqlite3_result_error_nomem(context); - return; - } + sqlite3_result_error_nomem(context); + return; } - bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB; - /* When writing the file to be edited, do \n to \r\n conversions on systems + } + bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB; + /* When writing the file to be edited, do \n to \r\n conversions on systems ** that want \r\n line endings */ - f = fopen(zTempFile, bBin ? "wb" : "w"); - if( f==0 ){ - sqlite3_result_error(context, "edit() cannot open temp file", -1); - goto edit_func_end; - } - sz = sqlite3_value_bytes(argv[0]); - if( bBin ){ - x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f); - }else{ - const char *z = (const char*)sqlite3_value_text(argv[0]); - /* Remember whether or not the value originally contained \r\n */ - if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1; - x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f); - } - fclose(f); - f = 0; - if( x!=sz ){ - sqlite3_result_error(context, "edit() could not write the whole file", -1); - goto edit_func_end; - } - zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile); - if( zCmd==0 ){ - sqlite3_result_error_nomem(context); - goto edit_func_end; - } - rc = system(zCmd); - sqlite3_free(zCmd); - if( rc ){ - sqlite3_result_error(context, "EDITOR returned non-zero", -1); - goto edit_func_end; - } - f = fopen(zTempFile, "rb"); - if( f==0 ){ - sqlite3_result_error(context, - "edit() cannot reopen temp file after edit", -1); - goto edit_func_end; - } - fseek(f, 0, SEEK_END); - sz = ftell(f); - rewind(f); - p = sqlite3_malloc64( sz+1 ); - if( p==0 ){ - sqlite3_result_error_nomem(context); - goto edit_func_end; - } - x = fread(p, 1, (size_t)sz, f); - fclose(f); - f = 0; - if( x!=sz ){ - sqlite3_result_error(context, "could not read back the whole file", -1); - goto edit_func_end; - } - if( bBin ){ - sqlite3_result_blob64(context, p, sz, sqlite3_free); + f = fopen(zTempFile, bBin ? "wb" : "w"); + if( f==0 ){ + sqlite3_result_error(context, "edit() cannot open temp file", -1); + goto edit_func_end; + } + sz = sqlite3_value_bytes(argv[0]); + if( bBin ){ + x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f); + }else{ + const char *z = (const char*)sqlite3_value_text(argv[0]); + /* Remember whether or not the value originally contained \r\n */ + if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1; + x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f); + } + fclose(f); + f = 0; + if( x!=sz ){ + sqlite3_result_error(context, "edit() could not write the whole file", -1); + goto edit_func_end; + } + zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile); + if( zCmd==0 ){ + sqlite3_result_error_nomem(context); + goto edit_func_end; + } + rc = system(zCmd); + sqlite3_free(zCmd); + if( rc ){ + sqlite3_result_error(context, "EDITOR returned non-zero", -1); + goto edit_func_end; + } + f = fopen(zTempFile, "rb"); + if( f==0 ){ + sqlite3_result_error(context, + "edit() cannot reopen temp file after edit", -1); + goto edit_func_end; + } + fseek(f, 0, SEEK_END); + sz = ftell(f); + rewind(f); + p = sqlite3_malloc64( sz+1 ); + if( p==0 ){ + sqlite3_result_error_nomem(context); + goto edit_func_end; + } + x = fread(p, 1, (size_t)sz, f); + fclose(f); + f = 0; + if( x!=sz ){ + sqlite3_result_error(context, "could not read back the whole file", -1); + goto edit_func_end; + } + if( bBin ){ + sqlite3_result_blob64(context, p, sz, sqlite3_free); + }else{ + sqlite3_int64 i, j; + if( hasCRNL ){ + /* If the original contains \r\n then do no conversions back to \n */ }else{ - sqlite3_int64 i, j; - if( hasCRNL ){ - /* If the original contains \r\n then do no conversions back to \n */ - }else{ - /* If the file did not originally contain \r\n then convert any new + /* If the file did not originally contain \r\n then convert any new ** \r\n back into \n */ - for(i=j=0; imodePrior = p->mode; - p->priorShFlgs = p->shellFlgs; - memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator)); - memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator)); + p->modePrior = p->mode; + p->priorShFlgs = p->shellFlgs; + memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator)); + memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator)); } static void outputModePop(ShellState *p){ - p->mode = p->modePrior; - p->shellFlgs = p->priorShFlgs; - memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator)); - memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator)); + p->mode = p->modePrior; + p->shellFlgs = p->priorShFlgs; + memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator)); + memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator)); } /* ** Output the given string as a hex-encoded blob (eg. X'1234' ) */ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ - int i; - char *zBlob = (char *)pBlob; - raw_printf(out,"X'"); - for(i=0; i0 ){ - utf8_printf(out,"%.*s",i,z); - } - if( z[i]=='<' ){ - raw_printf(out,"<"); - }else if( z[i]=='&' ){ - raw_printf(out,"&"); - }else if( z[i]=='>' ){ - raw_printf(out,">"); - }else if( z[i]=='\"' ){ - raw_printf(out,"""); - }else if( z[i]=='\'' ){ - raw_printf(out,"'"); - }else{ - break; - } - z += i + 1; + int i; + if( z==0 ) z = ""; + while( *z ){ + for(i=0; z[i] + && z[i]!='<' + && z[i]!='&' + && z[i]!='>' + && z[i]!='\"' + && z[i]!='\''; + i++){} + if( i>0 ){ + utf8_printf(out,"%.*s",i,z); + } + if( z[i]=='<' ){ + raw_printf(out,"<"); + }else if( z[i]=='&' ){ + raw_printf(out,"&"); + }else if( z[i]=='>' ){ + raw_printf(out,">"); + }else if( z[i]=='\"' ){ + raw_printf(out,"""); + }else if( z[i]=='\'' ){ + raw_printf(out,"'"); + }else{ + break; } + z += i + 1; + } } /* @@ -12791,22 +12791,22 @@ static void output_html_string(FILE *out, const char *z){ ** array, then the string must be quoted for CSV. */ static const char needCsvQuote[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; /* @@ -12816,38 +12816,38 @@ static const char needCsvQuote[] = { ** is only issued if bSep is true. */ static void output_csv(ShellState *p, const char *z, int bSep){ - FILE *out = p->out; - if( z==0 ){ - utf8_printf(out,"%s",p->nullValue); + FILE *out = p->out; + if( z==0 ){ + utf8_printf(out,"%s",p->nullValue); + }else{ + unsigned i; + for(i=0; z[i]; i++){ + if( needCsvQuote[((unsigned char*)z)[i]] ){ + i = 0; + break; + } + } + if( i==0 || strstr(z, p->colSeparator)!=0 ){ + char *zQuoted = sqlite3_mprintf("\"%w\"", z); + utf8_printf(out, "%s", zQuoted); + sqlite3_free(zQuoted); }else{ - unsigned i; - for(i=0; z[i]; i++){ - if( needCsvQuote[((unsigned char*)z)[i]] ){ - i = 0; - break; - } - } - if( i==0 || strstr(z, p->colSeparator)!=0 ){ - char *zQuoted = sqlite3_mprintf("\"%w\"", z); - utf8_printf(out, "%s", zQuoted); - sqlite3_free(zQuoted); - }else{ - utf8_printf(out, "%s", z); - } - } - if( bSep ){ - utf8_printf(p->out, "%s", p->colSeparator); + utf8_printf(out, "%s", z); } + } + if( bSep ){ + utf8_printf(p->out, "%s", p->colSeparator); + } } /* ** This routine runs when the user presses Ctrl-C */ static void interrupt_handler(int NotUsed){ - UNUSED_PARAMETER(NotUsed); - seenInterrupt++; - if( seenInterrupt>2 ) exit(1); - if( globalDb ) sqlite3_interrupt(globalDb); + UNUSED_PARAMETER(NotUsed); + seenInterrupt++; + if( seenInterrupt>2 ) exit(1); + if( globalDb ) sqlite3_interrupt(globalDb); } #if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE) @@ -12855,13 +12855,13 @@ static void interrupt_handler(int NotUsed){ ** This routine runs for console events (e.g. Ctrl-C) on Win32 */ static BOOL WINAPI ConsoleCtrlHandler( - DWORD dwCtrlType /* One of the CTRL_*_EVENT constants */ + DWORD dwCtrlType /* One of the CTRL_*_EVENT constants */ ){ - if( dwCtrlType==CTRL_C_EVENT ){ - interrupt_handler(0); - return TRUE; - } - return FALSE; + if( dwCtrlType==CTRL_C_EVENT ){ + interrupt_handler(0); + return TRUE; + } + return FALSE; } #endif @@ -12870,43 +12870,43 @@ static BOOL WINAPI ConsoleCtrlHandler( ** This authorizer runs in safe mode. */ static int safeModeAuth( - void *pClientData, - int op, - const char *zA1, - const char *zA2, - const char *zA3, - const char *zA4 + void *pClientData, + int op, + const char *zA1, + const char *zA2, + const char *zA3, + const char *zA4 ){ - ShellState *p = (ShellState*)pClientData; - static const char *azProhibitedFunctions[] = { - "edit", - "fts3_tokenizer", - "load_extension", - "readfile", - "writefile", - "zipfile", - "zipfile_cds", - }; - UNUSED_PARAMETER(zA1); - UNUSED_PARAMETER(zA3); - UNUSED_PARAMETER(zA4); - switch( op ){ - case SQLITE_ATTACH: { - failIfSafeMode(p, "cannot run ATTACH in safe mode"); - break; - } - case SQLITE_FUNCTION: { - int i; - for(i=0; iout, "authorizer: %s", azAction[op]); - for(i=0; i<4; i++){ - raw_printf(p->out, " "); - if( az[i] ){ - output_c_string(p->out, az[i]); - }else{ - raw_printf(p->out, "NULL"); - } + ShellState *p = (ShellState*)pClientData; + static const char *azAction[] = { 0, + "CREATE_INDEX", "CREATE_TABLE", "CREATE_TEMP_INDEX", + "CREATE_TEMP_TABLE", "CREATE_TEMP_TRIGGER", "CREATE_TEMP_VIEW", + "CREATE_TRIGGER", "CREATE_VIEW", "DELETE", + "DROP_INDEX", "DROP_TABLE", "DROP_TEMP_INDEX", + "DROP_TEMP_TABLE", "DROP_TEMP_TRIGGER", "DROP_TEMP_VIEW", + "DROP_TRIGGER", "DROP_VIEW", "INSERT", + "PRAGMA", "READ", "SELECT", + "TRANSACTION", "UPDATE", "ATTACH", + "DETACH", "ALTER_TABLE", "REINDEX", + "ANALYZE", "CREATE_VTABLE", "DROP_VTABLE", + "FUNCTION", "SAVEPOINT", "RECURSIVE" + }; + int i; + const char *az[4]; + az[0] = zA1; + az[1] = zA2; + az[2] = zA3; + az[3] = zA4; + utf8_printf(p->out, "authorizer: %s", azAction[op]); + for(i=0; i<4; i++){ + raw_printf(p->out, " "); + if( az[i] ){ + output_c_string(p->out, az[i]); + }else{ + raw_printf(p->out, "NULL"); } - raw_printf(p->out, "\n"); - if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4); - return SQLITE_OK; + } + raw_printf(p->out, "\n"); + if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4); + return SQLITE_OK; } #endif @@ -12963,19 +12963,19 @@ static int shellAuth( ** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements. */ static void printSchemaLine(FILE *out, const char *z, const char *zTail){ - if( z==0 ) return; - if( zTail==0 ) return; - if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){ - utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail); - }else{ - utf8_printf(out, "%s%s", z, zTail); - } + if( z==0 ) return; + if( zTail==0 ) return; + if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){ + utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail); + }else{ + utf8_printf(out, "%s%s", z, zTail); + } } static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){ - char c = z[n]; - z[n] = 0; - printSchemaLine(out, z, zTail); - z[n] = c; + char c = z[n]; + z[n] = 0; + printSchemaLine(out, z, zTail); + z[n] = c; } /* @@ -12983,37 +12983,37 @@ static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){ ** end of the first line. */ static int wsToEol(const char *z){ - int i; - for(i=0; z[i]; i++){ - if( z[i]=='\n' ) return 1; - if( IsSpace(z[i]) ) continue; - if( z[i]=='-' && z[i+1]=='-' ) return 1; - return 0; - } - return 1; + int i; + for(i=0; z[i]; i++){ + if( z[i]=='\n' ) return 1; + if( IsSpace(z[i]) ) continue; + if( z[i]=='-' && z[i+1]=='-' ) return 1; + return 0; + } + return 1; } /* ** Add a new entry to the EXPLAIN QUERY PLAN data */ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){ - EQPGraphRow *pNew; - int nText = strlen30(zText); - if( p->autoEQPtest ){ - utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText); - } - pNew = sqlite3_malloc64( sizeof(*pNew) + nText ); - if( pNew==0 ) shell_out_of_memory(); - pNew->iEqpId = iEqpId; - pNew->iParentId = p2; - memcpy(pNew->zText, zText, nText+1); - pNew->pNext = 0; - if( p->sGraph.pLast ){ - p->sGraph.pLast->pNext = pNew; - }else{ - p->sGraph.pRow = pNew; - } - p->sGraph.pLast = pNew; + EQPGraphRow *pNew; + int nText = strlen30(zText); + if( p->autoEQPtest ){ + utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText); + } + pNew = sqlite3_malloc64( sizeof(*pNew) + nText ); + if( pNew==0 ) shell_out_of_memory(); + pNew->iEqpId = iEqpId; + pNew->iParentId = p2; + memcpy(pNew->zText, zText, nText+1); + pNew->pNext = 0; + if( p->sGraph.pLast ){ + p->sGraph.pLast->pNext = pNew; + }else{ + p->sGraph.pRow = pNew; + } + p->sGraph.pLast = pNew; } /* @@ -13021,64 +13021,64 @@ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){ ** in p->sGraph. */ static void eqp_reset(ShellState *p){ - EQPGraphRow *pRow, *pNext; - for(pRow = p->sGraph.pRow; pRow; pRow = pNext){ - pNext = pRow->pNext; - sqlite3_free(pRow); - } - memset(&p->sGraph, 0, sizeof(p->sGraph)); + EQPGraphRow *pRow, *pNext; + for(pRow = p->sGraph.pRow; pRow; pRow = pNext){ + pNext = pRow->pNext; + sqlite3_free(pRow); + } + memset(&p->sGraph, 0, sizeof(p->sGraph)); } /* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after ** pOld, or return the first such line if pOld is NULL */ static EQPGraphRow *eqp_next_row(ShellState *p, int iEqpId, EQPGraphRow *pOld){ - EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow; - while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext; - return pRow; + EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow; + while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext; + return pRow; } /* Render a single level of the graph that has iEqpId as its parent. Called ** recursively to render sublevels. */ static void eqp_render_level(ShellState *p, int iEqpId){ - EQPGraphRow *pRow, *pNext; - int n = strlen30(p->sGraph.zPrefix); - char *z; - for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){ - pNext = eqp_next_row(p, iEqpId, pRow); - z = pRow->zText; - utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix, - pNext ? "|--" : "`--", z); - if( n<(int)sizeof(p->sGraph.zPrefix)-7 ){ - memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4); - eqp_render_level(p, pRow->iEqpId); - p->sGraph.zPrefix[n] = 0; - } + EQPGraphRow *pRow, *pNext; + int n = strlen30(p->sGraph.zPrefix); + char *z; + for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){ + pNext = eqp_next_row(p, iEqpId, pRow); + z = pRow->zText; + utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix, + pNext ? "|--" : "`--", z); + if( n<(int)sizeof(p->sGraph.zPrefix)-7 ){ + memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4); + eqp_render_level(p, pRow->iEqpId); + p->sGraph.zPrefix[n] = 0; } + } } /* ** Display and reset the EXPLAIN QUERY PLAN data */ static void eqp_render(ShellState *p){ - EQPGraphRow *pRow = p->sGraph.pRow; - if( pRow ){ - if( pRow->zText[0]=='-' ){ - if( pRow->pNext==0 ){ - eqp_reset(p); - return; - } - utf8_printf(p->out, "%s\n", pRow->zText+3); - p->sGraph.pRow = pRow->pNext; - sqlite3_free(pRow); - }else{ - utf8_printf(p->out, "QUERY PLAN\n"); - } - p->sGraph.zPrefix[0] = 0; - eqp_render_level(p, 0); + EQPGraphRow *pRow = p->sGraph.pRow; + if( pRow ){ + if( pRow->zText[0]=='-' ){ + if( pRow->pNext==0 ){ eqp_reset(p); + return; + } + utf8_printf(p->out, "%s\n", pRow->zText+3); + p->sGraph.pRow = pRow->pNext; + sqlite3_free(pRow); + }else{ + utf8_printf(p->out, "QUERY PLAN\n"); } + p->sGraph.zPrefix[0] = 0; + eqp_render_level(p, 0); + eqp_reset(p); + } } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK @@ -13086,18 +13086,18 @@ static void eqp_render(ShellState *p){ ** Progress handler callback. */ static int progress_handler(void *pClientData) { - ShellState *p = (ShellState*)pClientData; - p->nProgress++; - if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){ - raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress); - if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0; - if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0; - return 1; - } - if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){ - raw_printf(p->out, "Progress %u\n", p->nProgress); - } - return 0; + ShellState *p = (ShellState*)pClientData; + p->nProgress++; + if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){ + raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress); + if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0; + if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0; + return 1; + } + if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){ + raw_printf(p->out, "Progress %u\n", p->nProgress); + } + return 0; } #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ @@ -13105,34 +13105,34 @@ static int progress_handler(void *pClientData) { ** Print N dashes */ static void print_dashes(FILE *out, int N){ - const char zDash[] = "--------------------------------------------------"; - const int nDash = sizeof(zDash) - 1; - while( N>nDash ){ - fputs(zDash, out); - N -= nDash; - } - raw_printf(out, "%.*s", N, zDash); + const char zDash[] = "--------------------------------------------------"; + const int nDash = sizeof(zDash) - 1; + while( N>nDash ){ + fputs(zDash, out); + N -= nDash; + } + raw_printf(out, "%.*s", N, zDash); } /* ** Print a markdown or table-style row separator using ascii-art */ static void print_row_separator( - ShellState *p, - int nArg, - const char *zSep + ShellState *p, + int nArg, + const char *zSep ){ - int i; - if( nArg>0 ){ - fputs(zSep, p->out); - print_dashes(p->out, p->actualWidth[0]+2); - for(i=1; iout); - print_dashes(p->out, p->actualWidth[i]+2); - } - fputs(zSep, p->out); + int i; + if( nArg>0 ){ + fputs(zSep, p->out); + print_dashes(p->out, p->actualWidth[0]+2); + for(i=1; iout); + print_dashes(p->out, p->actualWidth[i]+2); } - fputs("\n", p->out); + fputs(zSep, p->out); + } + fputs("\n", p->out); } /* @@ -13140,366 +13140,366 @@ static void print_row_separator( ** invokes for each row of a query result. */ static int shell_callback( - void *pArg, - int nArg, /* Number of result columns */ - char **azArg, /* Text of each result column */ - char **azCol, /* Column names */ - int *aiType /* Column types. Might be NULL */ + void *pArg, + int nArg, /* Number of result columns */ + char **azArg, /* Text of each result column */ + char **azCol, /* Column names */ + int *aiType /* Column types. Might be NULL */ ){ - int i; - ShellState *p = (ShellState*)pArg; - - if( azArg==0 ) return 0; - switch( p->cMode ){ - case MODE_Line: { - int w = 5; - if( azArg==0 ) break; - for(i=0; iw ) w = len; - } - if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator); - for(i=0; iout,"%*s = %s%s", w, azCol[i], - azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator); - } - break; - } - case MODE_Explain: { - static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13}; - if( nArg>ArraySize(aExplainWidth) ){ - nArg = ArraySize(aExplainWidth); - } - if( p->cnt++==0 ){ - for(i=0; iout, w, azCol[i]); - fputs(i==nArg-1 ? "\n" : " ", p->out); - } - for(i=0; iout, w); - fputs(i==nArg-1 ? "\n" : " ", p->out); - } - } - if( azArg==0 ) break; - for(i=0; iw ){ - w = strlenChar(azArg[i]); - } - if( i==1 && p->aiIndent && p->pStmt ){ - if( p->iIndentnIndent ){ - utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); - } - p->iIndent++; - } - utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue); - fputs(i==nArg-1 ? "\n" : " ", p->out); - } - break; - } - case MODE_Semi: { /* .schema and .fullschema output */ - printSchemaLine(p->out, azArg[0], ";\n"); - break; - } - case MODE_Pretty: { /* .schema and .fullschema with --indent */ - char *z; - int j; - int nParen = 0; - char cEnd = 0; - char c; - int nLine = 0; - assert( nArg==1 ); - if( azArg[0]==0 ) break; - if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0 - || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0 - ){ - utf8_printf(p->out, "%s;\n", azArg[0]); - break; - } - z = sqlite3_mprintf("%s", azArg[0]); + int i; + ShellState *p = (ShellState*)pArg; + + if( azArg==0 ) return 0; + switch( p->cMode ){ + case MODE_Line: { + int w = 5; + if( azArg==0 ) break; + for(i=0; iw ) w = len; + } + if( p->cnt++>0 ) utf8_printf(p->out, "%s", p->rowSeparator); + for(i=0; iout,"%*s = %s%s", w, azCol[i], + azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator); + } + break; + } + case MODE_Explain: { + static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13}; + if( nArg>ArraySize(aExplainWidth) ){ + nArg = ArraySize(aExplainWidth); + } + if( p->cnt++==0 ){ + for(i=0; iout, w, azCol[i]); + fputs(i==nArg-1 ? "\n" : " ", p->out); + } + for(i=0; iout, w); + fputs(i==nArg-1 ? "\n" : " ", p->out); + } + } + if( azArg==0 ) break; + for(i=0; iw ){ + w = strlenChar(azArg[i]); + } + if( i==1 && p->aiIndent && p->pStmt ){ + if( p->iIndentnIndent ){ + utf8_printf(p->out, "%*.s", p->aiIndent[p->iIndent], ""); + } + p->iIndent++; + } + utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue); + fputs(i==nArg-1 ? "\n" : " ", p->out); + } + break; + } + case MODE_Semi: { /* .schema and .fullschema output */ + printSchemaLine(p->out, azArg[0], ";\n"); + break; + } + case MODE_Pretty: { /* .schema and .fullschema with --indent */ + char *z; + int j; + int nParen = 0; + char cEnd = 0; + char c; + int nLine = 0; + assert( nArg==1 ); + if( azArg[0]==0 ) break; + if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0 + || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0 + ){ + utf8_printf(p->out, "%s;\n", azArg[0]); + break; + } + z = sqlite3_mprintf("%s", azArg[0]); + j = 0; + for(i=0; IsSpace(z[i]); i++){} + for(; (c = z[i])!=0; i++){ + if( IsSpace(c) ){ + if( z[j-1]=='\r' ) z[j-1] = '\n'; + if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue; + }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){ + j--; + } + z[j++] = c; + } + while( j>0 && IsSpace(z[j-1]) ){ j--; } + z[j] = 0; + if( strlen30(z)>=79 ){ + for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */ + if( c==cEnd ){ + cEnd = 0; + }else if( c=='"' || c=='\'' || c=='`' ){ + cEnd = c; + }else if( c=='[' ){ + cEnd = ']'; + }else if( c=='-' && z[i+1]=='-' ){ + cEnd = '\n'; + }else if( c=='(' ){ + nParen++; + }else if( c==')' ){ + nParen--; + if( nLine>0 && nParen==0 && j>0 ){ + printSchemaLineN(p->out, z, j, "\n"); + j = 0; + } + } + z[j++] = c; + if( nParen==1 && cEnd==0 + && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1))) + ){ + if( c=='\n' ) j--; + printSchemaLineN(p->out, z, j, "\n "); j = 0; - for(i=0; IsSpace(z[i]); i++){} - for(; (c = z[i])!=0; i++){ - if( IsSpace(c) ){ - if( z[j-1]=='\r' ) z[j-1] = '\n'; - if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue; - }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){ - j--; - } - z[j++] = c; - } - while( j>0 && IsSpace(z[j-1]) ){ j--; } - z[j] = 0; - if( strlen30(z)>=79 ){ - for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */ - if( c==cEnd ){ - cEnd = 0; - }else if( c=='"' || c=='\'' || c=='`' ){ - cEnd = c; - }else if( c=='[' ){ - cEnd = ']'; - }else if( c=='-' && z[i+1]=='-' ){ - cEnd = '\n'; - }else if( c=='(' ){ - nParen++; - }else if( c==')' ){ - nParen--; - if( nLine>0 && nParen==0 && j>0 ){ - printSchemaLineN(p->out, z, j, "\n"); - j = 0; - } - } - z[j++] = c; - if( nParen==1 && cEnd==0 - && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1))) - ){ - if( c=='\n' ) j--; - printSchemaLineN(p->out, z, j, "\n "); - j = 0; - nLine++; - while( IsSpace(z[i+1]) ){ i++; } - } - } - z[j] = 0; - } - printSchemaLine(p->out, z, ";\n"); + nLine++; + while( IsSpace(z[i+1]) ){ i++; } + } + } + z[j] = 0; + } + printSchemaLine(p->out, z, ";\n"); + sqlite3_free(z); + break; + } + case MODE_List: { + if( p->cnt++==0 && p->showHeader ){ + for(i=0; iout,"%s%s",azCol[i], + i==nArg-1 ? p->rowSeparator : p->colSeparator); + } + } + if( azArg==0 ) break; + for(i=0; inullValue; + utf8_printf(p->out, "%s", z); + if( iout, "%s", p->colSeparator); + }else{ + utf8_printf(p->out, "%s", p->rowSeparator); + } + } + break; + } + case MODE_Html: { + if( p->cnt++==0 && p->showHeader ){ + raw_printf(p->out,""); + for(i=0; iout,"\n"); + } + raw_printf(p->out,"\n"); + } + if( azArg==0 ) break; + raw_printf(p->out,""); + for(i=0; iout,"\n"); + } + raw_printf(p->out,"\n"); + break; + } + case MODE_Tcl: { + if( p->cnt++==0 && p->showHeader ){ + for(i=0; iout,azCol[i] ? azCol[i] : ""); + if(iout, "%s", p->colSeparator); + } + utf8_printf(p->out, "%s", p->rowSeparator); + } + if( azArg==0 ) break; + for(i=0; iout, azArg[i] ? azArg[i] : p->nullValue); + if(iout, "%s", p->colSeparator); + } + utf8_printf(p->out, "%s", p->rowSeparator); + break; + } + case MODE_Csv: { + setBinaryMode(p->out, 1); + if( p->cnt++==0 && p->showHeader ){ + for(i=0; iout, "%s", p->rowSeparator); + } + if( nArg>0 ){ + for(i=0; iout, "%s", p->rowSeparator); + } + setTextMode(p->out, 1); + break; + } + case MODE_Insert: { + if( azArg==0 ) break; + utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); + if( p->showHeader ){ + raw_printf(p->out,"("); + for(i=0; i0 ) raw_printf(p->out, ","); + if( quoteChar(azCol[i]) ){ + char *z = sqlite3_mprintf("\"%w\"", azCol[i]); + utf8_printf(p->out, "%s", z); sqlite3_free(z); - break; - } - case MODE_List: { - if( p->cnt++==0 && p->showHeader ){ - for(i=0; iout,"%s%s",azCol[i], - i==nArg-1 ? p->rowSeparator : p->colSeparator); - } - } - if( azArg==0 ) break; - for(i=0; inullValue; - utf8_printf(p->out, "%s", z); - if( iout, "%s", p->colSeparator); - }else{ - utf8_printf(p->out, "%s", p->rowSeparator); - } - } - break; - } - case MODE_Html: { - if( p->cnt++==0 && p->showHeader ){ - raw_printf(p->out,""); - for(i=0; iout,"\n"); - } - raw_printf(p->out,"\n"); - } - if( azArg==0 ) break; - raw_printf(p->out,""); - for(i=0; iout,"\n"); - } - raw_printf(p->out,"\n"); - break; - } - case MODE_Tcl: { - if( p->cnt++==0 && p->showHeader ){ - for(i=0; iout,azCol[i] ? azCol[i] : ""); - if(iout, "%s", p->colSeparator); - } - utf8_printf(p->out, "%s", p->rowSeparator); - } - if( azArg==0 ) break; - for(i=0; iout, azArg[i] ? azArg[i] : p->nullValue); - if(iout, "%s", p->colSeparator); - } - utf8_printf(p->out, "%s", p->rowSeparator); - break; - } - case MODE_Csv: { - setBinaryMode(p->out, 1); - if( p->cnt++==0 && p->showHeader ){ - for(i=0; iout, "%s", p->rowSeparator); - } - if( nArg>0 ){ - for(i=0; iout, "%s", p->rowSeparator); - } - setTextMode(p->out, 1); - break; - } - case MODE_Insert: { - if( azArg==0 ) break; - utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); - if( p->showHeader ){ - raw_printf(p->out,"("); - for(i=0; i0 ) raw_printf(p->out, ","); - if( quoteChar(azCol[i]) ){ - char *z = sqlite3_mprintf("\"%w\"", azCol[i]); - utf8_printf(p->out, "%s", z); - sqlite3_free(z); - }else{ - raw_printf(p->out, "%s", azCol[i]); - } - } - raw_printf(p->out,")"); - } - p->cnt++; - for(i=0; iout, i>0 ? "," : " VALUES("); - if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ - utf8_printf(p->out,"NULL"); - }else if( aiType && aiType[i]==SQLITE_TEXT ){ - if( ShellHasFlag(p, SHFLG_Newlines) ){ - output_quoted_string(p->out, azArg[i]); - }else{ - output_quoted_escaped_string(p->out, azArg[i]); - } - }else if( aiType && aiType[i]==SQLITE_INTEGER ){ - utf8_printf(p->out,"%s", azArg[i]); - }else if( aiType && aiType[i]==SQLITE_FLOAT ){ - char z[50]; - double r = sqlite3_column_double(p->pStmt, i); - sqlite3_uint64 ur; - memcpy(&ur,&r,sizeof(r)); - if( ur==0x7ff0000000000000LL ){ - raw_printf(p->out, "1e999"); - }else if( ur==0xfff0000000000000LL ){ - raw_printf(p->out, "-1e999"); - }else{ - sqlite3_snprintf(50,z,"%!.20g", r); - raw_printf(p->out, "%s", z); - } - }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ - const void *pBlob = sqlite3_column_blob(p->pStmt, i); - int nBlob = sqlite3_column_bytes(p->pStmt, i); - output_hex_blob(p->out, pBlob, nBlob); - }else if( isNumber(azArg[i], 0) ){ - utf8_printf(p->out,"%s", azArg[i]); - }else if( ShellHasFlag(p, SHFLG_Newlines) ){ - output_quoted_string(p->out, azArg[i]); - }else{ - output_quoted_escaped_string(p->out, azArg[i]); - } - } - raw_printf(p->out,");\n"); - break; - } - case MODE_Json: { - if( azArg==0 ) break; - if( p->cnt==0 ){ - fputs("[{", p->out); - }else{ - fputs(",\n{", p->out); - } - p->cnt++; - for(i=0; iout, azCol[i], -1); - putc(':', p->out); - if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ - fputs("null",p->out); - }else if( aiType && aiType[i]==SQLITE_FLOAT ){ - char z[50]; - double r = sqlite3_column_double(p->pStmt, i); - sqlite3_uint64 ur; - memcpy(&ur,&r,sizeof(r)); - if( ur==0x7ff0000000000000LL ){ - raw_printf(p->out, "1e999"); - }else if( ur==0xfff0000000000000LL ){ - raw_printf(p->out, "-1e999"); - }else{ - sqlite3_snprintf(50,z,"%!.20g", r); - raw_printf(p->out, "%s", z); - } - }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ - const void *pBlob = sqlite3_column_blob(p->pStmt, i); - int nBlob = sqlite3_column_bytes(p->pStmt, i); - output_json_string(p->out, pBlob, nBlob); - }else if( aiType && aiType[i]==SQLITE_TEXT ){ - output_json_string(p->out, azArg[i], -1); - }else{ - utf8_printf(p->out,"%s", azArg[i]); - } - if( iout); - } - } - putc('}', p->out); - break; - } - case MODE_Quote: { - if( azArg==0 ) break; - if( p->cnt==0 && p->showHeader ){ - for(i=0; i0 ) fputs(p->colSeparator, p->out); - output_quoted_string(p->out, azCol[i]); - } - fputs(p->rowSeparator, p->out); - } - p->cnt++; - for(i=0; i0 ) fputs(p->colSeparator, p->out); - if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ - utf8_printf(p->out,"NULL"); - }else if( aiType && aiType[i]==SQLITE_TEXT ){ - output_quoted_string(p->out, azArg[i]); - }else if( aiType && aiType[i]==SQLITE_INTEGER ){ - utf8_printf(p->out,"%s", azArg[i]); - }else if( aiType && aiType[i]==SQLITE_FLOAT ){ - char z[50]; - double r = sqlite3_column_double(p->pStmt, i); - sqlite3_snprintf(50,z,"%!.20g", r); - raw_printf(p->out, "%s", z); - }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ - const void *pBlob = sqlite3_column_blob(p->pStmt, i); - int nBlob = sqlite3_column_bytes(p->pStmt, i); - output_hex_blob(p->out, pBlob, nBlob); - }else if( isNumber(azArg[i], 0) ){ - utf8_printf(p->out,"%s", azArg[i]); - }else{ - output_quoted_string(p->out, azArg[i]); - } - } - fputs(p->rowSeparator, p->out); - break; - } - case MODE_Ascii: { - if( p->cnt++==0 && p->showHeader ){ - for(i=0; i0 ) utf8_printf(p->out, "%s", p->colSeparator); - utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : ""); - } - utf8_printf(p->out, "%s", p->rowSeparator); - } - if( azArg==0 ) break; - for(i=0; i0 ) utf8_printf(p->out, "%s", p->colSeparator); - utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue); - } - utf8_printf(p->out, "%s", p->rowSeparator); - break; + }else{ + raw_printf(p->out, "%s", azCol[i]); + } + } + raw_printf(p->out,")"); + } + p->cnt++; + for(i=0; iout, i>0 ? "," : " VALUES("); + if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ + utf8_printf(p->out,"NULL"); + }else if( aiType && aiType[i]==SQLITE_TEXT ){ + if( ShellHasFlag(p, SHFLG_Newlines) ){ + output_quoted_string(p->out, azArg[i]); + }else{ + output_quoted_escaped_string(p->out, azArg[i]); + } + }else if( aiType && aiType[i]==SQLITE_INTEGER ){ + utf8_printf(p->out,"%s", azArg[i]); + }else if( aiType && aiType[i]==SQLITE_FLOAT ){ + char z[50]; + double r = sqlite3_column_double(p->pStmt, i); + sqlite3_uint64 ur; + memcpy(&ur,&r,sizeof(r)); + if( ur==0x7ff0000000000000LL ){ + raw_printf(p->out, "1e999"); + }else if( ur==0xfff0000000000000LL ){ + raw_printf(p->out, "-1e999"); + }else{ + sqlite3_snprintf(50,z,"%!.20g", r); + raw_printf(p->out, "%s", z); + } + }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ + const void *pBlob = sqlite3_column_blob(p->pStmt, i); + int nBlob = sqlite3_column_bytes(p->pStmt, i); + output_hex_blob(p->out, pBlob, nBlob); + }else if( isNumber(azArg[i], 0) ){ + utf8_printf(p->out,"%s", azArg[i]); + }else if( ShellHasFlag(p, SHFLG_Newlines) ){ + output_quoted_string(p->out, azArg[i]); + }else{ + output_quoted_escaped_string(p->out, azArg[i]); + } + } + raw_printf(p->out,");\n"); + break; + } + case MODE_Json: { + if( azArg==0 ) break; + if( p->cnt==0 ){ + fputs("[{", p->out); + }else{ + fputs(",\n{", p->out); + } + p->cnt++; + for(i=0; iout, azCol[i], -1); + putc(':', p->out); + if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ + fputs("null",p->out); + }else if( aiType && aiType[i]==SQLITE_FLOAT ){ + char z[50]; + double r = sqlite3_column_double(p->pStmt, i); + sqlite3_uint64 ur; + memcpy(&ur,&r,sizeof(r)); + if( ur==0x7ff0000000000000LL ){ + raw_printf(p->out, "1e999"); + }else if( ur==0xfff0000000000000LL ){ + raw_printf(p->out, "-1e999"); + }else{ + sqlite3_snprintf(50,z,"%!.20g", r); + raw_printf(p->out, "%s", z); + } + }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ + const void *pBlob = sqlite3_column_blob(p->pStmt, i); + int nBlob = sqlite3_column_bytes(p->pStmt, i); + output_json_string(p->out, pBlob, nBlob); + }else if( aiType && aiType[i]==SQLITE_TEXT ){ + output_json_string(p->out, azArg[i], -1); + }else{ + utf8_printf(p->out,"%s", azArg[i]); + } + if( iout); + } + } + putc('}', p->out); + break; + } + case MODE_Quote: { + if( azArg==0 ) break; + if( p->cnt==0 && p->showHeader ){ + for(i=0; i0 ) fputs(p->colSeparator, p->out); + output_quoted_string(p->out, azCol[i]); + } + fputs(p->rowSeparator, p->out); + } + p->cnt++; + for(i=0; i0 ) fputs(p->colSeparator, p->out); + if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ + utf8_printf(p->out,"NULL"); + }else if( aiType && aiType[i]==SQLITE_TEXT ){ + output_quoted_string(p->out, azArg[i]); + }else if( aiType && aiType[i]==SQLITE_INTEGER ){ + utf8_printf(p->out,"%s", azArg[i]); + }else if( aiType && aiType[i]==SQLITE_FLOAT ){ + char z[50]; + double r = sqlite3_column_double(p->pStmt, i); + sqlite3_snprintf(50,z,"%!.20g", r); + raw_printf(p->out, "%s", z); + }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){ + const void *pBlob = sqlite3_column_blob(p->pStmt, i); + int nBlob = sqlite3_column_bytes(p->pStmt, i); + output_hex_blob(p->out, pBlob, nBlob); + }else if( isNumber(azArg[i], 0) ){ + utf8_printf(p->out,"%s", azArg[i]); + }else{ + output_quoted_string(p->out, azArg[i]); } - case MODE_EQP: { - eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]); - break; + } + fputs(p->rowSeparator, p->out); + break; + } + case MODE_Ascii: { + if( p->cnt++==0 && p->showHeader ){ + for(i=0; i0 ) utf8_printf(p->out, "%s", p->colSeparator); + utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : ""); } + utf8_printf(p->out, "%s", p->rowSeparator); + } + if( azArg==0 ) break; + for(i=0; i0 ) utf8_printf(p->out, "%s", p->colSeparator); + utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue); + } + utf8_printf(p->out, "%s", p->rowSeparator); + break; } - return 0; + case MODE_EQP: { + eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]); + break; + } + } + return 0; } /* @@ -13507,8 +13507,8 @@ static int shell_callback( ** invokes for each row of a query result. */ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ - /* since we don't have type info, call the shell_callback with a NULL value */ - return shell_callback(pArg, nArg, azArg, azCol, NULL); + /* since we don't have type info, call the shell_callback with a NULL value */ + return shell_callback(pArg, nArg, azArg, azCol, NULL); } /* @@ -13516,64 +13516,64 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ ** output onto the end of a ShellText object. */ static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){ - ShellText *p = (ShellText*)pArg; - int i; - UNUSED_PARAMETER(az); - if( azArg==0 ) return 0; - if( p->n ) appendText(p, "|", 0); - for(i=0; in ) appendText(p, "|", 0); + for(i=0; idb, - "SAVEPOINT selftest_init;\n" - "CREATE TABLE IF NOT EXISTS selftest(\n" - " tno INTEGER PRIMARY KEY,\n" /* Test number */ - " op TEXT,\n" /* Operator: memo run */ - " cmd TEXT,\n" /* Command text */ - " ans TEXT\n" /* Desired answer */ - ");" - "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n" - "INSERT INTO [_shell$self](rowid,op,cmd)\n" - " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n" - " 'memo','Tests generated by --init');\n" - "INSERT INTO [_shell$self]\n" - " SELECT 'run',\n" - " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql " - "FROM sqlite_schema ORDER BY 2'',224))',\n" - " hex(sha3_query('SELECT type,name,tbl_name,sql " - "FROM sqlite_schema ORDER BY 2',224));\n" - "INSERT INTO [_shell$self]\n" - " SELECT 'run'," - " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||" - " printf('%w',name) || '\" NOT INDEXED'',224))',\n" - " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n" - " FROM (\n" - " SELECT name FROM sqlite_schema\n" - " WHERE type='table'\n" - " AND name<>'selftest'\n" - " AND coalesce(rootpage,0)>0\n" - " )\n" - " ORDER BY name;\n" - "INSERT INTO [_shell$self]\n" - " VALUES('run','PRAGMA integrity_check','ok');\n" - "INSERT INTO selftest(tno,op,cmd,ans)" - " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n" - "DROP TABLE [_shell$self];" - ,0,0,&zErrMsg); - if( zErrMsg ){ - utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg); - sqlite3_free(zErrMsg); - } - sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0); + char *zErrMsg = 0; + sqlite3_exec(p->db, + "SAVEPOINT selftest_init;\n" + "CREATE TABLE IF NOT EXISTS selftest(\n" + " tno INTEGER PRIMARY KEY,\n" /* Test number */ + " op TEXT,\n" /* Operator: memo run */ + " cmd TEXT,\n" /* Command text */ + " ans TEXT\n" /* Desired answer */ + ");" + "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n" + "INSERT INTO [_shell$self](rowid,op,cmd)\n" + " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n" + " 'memo','Tests generated by --init');\n" + "INSERT INTO [_shell$self]\n" + " SELECT 'run',\n" + " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql " + "FROM sqlite_schema ORDER BY 2'',224))',\n" + " hex(sha3_query('SELECT type,name,tbl_name,sql " + "FROM sqlite_schema ORDER BY 2',224));\n" + "INSERT INTO [_shell$self]\n" + " SELECT 'run'," + " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||" + " printf('%w',name) || '\" NOT INDEXED'',224))',\n" + " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n" + " FROM (\n" + " SELECT name FROM sqlite_schema\n" + " WHERE type='table'\n" + " AND name<>'selftest'\n" + " AND coalesce(rootpage,0)>0\n" + " )\n" + " ORDER BY name;\n" + "INSERT INTO [_shell$self]\n" + " VALUES('run','PRAGMA integrity_check','ok');\n" + "INSERT INTO selftest(tno,op,cmd,ans)" + " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n" + "DROP TABLE [_shell$self];" + ,0,0,&zErrMsg); + if( zErrMsg ){ + utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg); + sqlite3_free(zErrMsg); + } + sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0); } @@ -13583,28 +13583,28 @@ static void createSelftestTable(ShellState *p){ ** table name. */ static void set_table_name(ShellState *p, const char *zName){ - int i, n; - char cQuote; - char *z; - - if( p->zDestTable ){ - free(p->zDestTable); - p->zDestTable = 0; - } - if( zName==0 ) return; - cQuote = quoteChar(zName); - n = strlen30(zName); - if( cQuote ) n += n+2; - z = p->zDestTable = malloc( n+1 ); - if( z==0 ) shell_out_of_memory(); - n = 0; - if( cQuote ) z[n++] = cQuote; - for(i=0; zName[i]; i++){ - z[n++] = zName[i]; - if( zName[i]==cQuote ) z[n++] = cQuote; - } - if( cQuote ) z[n++] = cQuote; - z[n] = 0; + int i, n; + char cQuote; + char *z; + + if( p->zDestTable ){ + free(p->zDestTable); + p->zDestTable = 0; + } + if( zName==0 ) return; + cQuote = quoteChar(zName); + n = strlen30(zName); + if( cQuote ) n += n+2; + z = p->zDestTable = malloc( n+1 ); + if( z==0 ) shell_out_of_memory(); + n = 0; + if( cQuote ) z[n++] = cQuote; + for(i=0; zName[i]; i++){ + z[n++] = zName[i]; + if( zName[i]==cQuote ) z[n++] = cQuote; + } + if( cQuote ) z[n++] = cQuote; + z[n] = 0; } @@ -13619,58 +13619,58 @@ static void set_table_name(ShellState *p, const char *zName){ ** won't consume the semicolon terminator. */ static int run_table_dump_query( - ShellState *p, /* Query context */ - const char *zSelect /* SELECT statement to extract content */ + ShellState *p, /* Query context */ + const char *zSelect /* SELECT statement to extract content */ ){ - sqlite3_stmt *pSelect; - int rc; - int nResult; - int i; - const char *z; - rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0); - if( rc!=SQLITE_OK || !pSelect ){ - utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, - sqlite3_errmsg(p->db)); - if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; - return rc; + sqlite3_stmt *pSelect; + int rc; + int nResult; + int i; + const char *z; + rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0); + if( rc!=SQLITE_OK || !pSelect ){ + utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, + sqlite3_errmsg(p->db)); + if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; + return rc; + } + rc = sqlite3_step(pSelect); + nResult = sqlite3_column_count(pSelect); + while( rc==SQLITE_ROW ){ + z = (const char*)sqlite3_column_text(pSelect, 0); + utf8_printf(p->out, "%s", z); + for(i=1; iout, ",%s", sqlite3_column_text(pSelect, i)); } - rc = sqlite3_step(pSelect); - nResult = sqlite3_column_count(pSelect); - while( rc==SQLITE_ROW ){ - z = (const char*)sqlite3_column_text(pSelect, 0); - utf8_printf(p->out, "%s", z); - for(i=1; iout, ",%s", sqlite3_column_text(pSelect, i)); - } - if( z==0 ) z = ""; - while( z[0] && (z[0]!='-' || z[1]!='-') ) z++; - if( z[0] ){ - raw_printf(p->out, "\n;\n"); - }else{ - raw_printf(p->out, ";\n"); - } - rc = sqlite3_step(pSelect); - } - rc = sqlite3_finalize(pSelect); - if( rc!=SQLITE_OK ){ - utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, - sqlite3_errmsg(p->db)); - if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; + if( z==0 ) z = ""; + while( z[0] && (z[0]!='-' || z[1]!='-') ) z++; + if( z[0] ){ + raw_printf(p->out, "\n;\n"); + }else{ + raw_printf(p->out, ";\n"); } - return rc; + rc = sqlite3_step(pSelect); + } + rc = sqlite3_finalize(pSelect); + if( rc!=SQLITE_OK ){ + utf8_printf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, + sqlite3_errmsg(p->db)); + if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; + } + return rc; } /* ** Allocate space and save off string indicating current error. */ static char *save_err_msg( - sqlite3 *db, /* Database to query */ - const char *zWhen, /* Qualifier (format) wrapper */ - int rc /* Error code returned from API */ + sqlite3 *db, /* Database to query */ + const char *zWhen, /* Qualifier (format) wrapper */ + int rc /* Error code returned from API */ ){ - if( zWhen==0 ) - zWhen = "%s (%d)"; - return sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc); + if( zWhen==0 ) + zWhen = "%s (%d)"; + return sqlite3_mprintf(zWhen, sqlite3_errmsg(db), rc); } #ifdef __linux__ @@ -13678,34 +13678,34 @@ static char *save_err_msg( ** Attempt to display I/O stats on Linux using /proc/PID/io */ static void displayLinuxIoStats(FILE *out){ - FILE *in; - char z[200]; - sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid()); - in = fopen(z, "rb"); - if( in==0 ) return; - while( fgets(z, sizeof(z), in)!=0 ){ - static const struct { - const char *zPattern; - const char *zDesc; - } aTrans[] = { - { "rchar: ", "Bytes received by read():" }, - { "wchar: ", "Bytes sent to write():" }, - { "syscr: ", "Read() system calls:" }, - { "syscw: ", "Write() system calls:" }, - { "read_bytes: ", "Bytes read from storage:" }, - { "write_bytes: ", "Bytes written to storage:" }, - { "cancelled_write_bytes: ", "Cancelled write bytes:" }, - }; - int i; - for(i=0; i1 ){ - sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr); - }else{ - sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr); - } - raw_printf(p->out, "%-36s %s\n", zLabel, zLine); + sqlite3_int64 iCur = -1; + sqlite3_int64 iHiwtr = -1; + int i, nPercent; + char zLine[200]; + sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset); + for(i=0, nPercent=0; zFormat[i]; i++){ + if( zFormat[i]=='%' ) nPercent++; + } + if( nPercent>1 ){ + sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr); + }else{ + sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr); + } + raw_printf(p->out, "%-36s %s\n", zLabel, zLine); } /* ** Display memory stats. */ static int display_stats( - sqlite3 *db, /* Database to query */ - ShellState *pArg, /* Pointer to ShellState */ - int bReset /* True to reset the stats */ + sqlite3 *db, /* Database to query */ + ShellState *pArg, /* Pointer to ShellState */ + int bReset /* True to reset the stats */ ){ - int iCur; - int iHiwtr; - FILE *out; - if( pArg==0 || pArg->out==0 ) return 0; - out = pArg->out; - - if( pArg->pStmt && pArg->statsOn==2 ){ - int nCol, i, x; - sqlite3_stmt *pStmt = pArg->pStmt; - char z[100]; - nCol = sqlite3_column_count(pStmt); - raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol); - for(i=0; iout==0 ) return 0; + out = pArg->out; + + if( pArg->pStmt && pArg->statsOn==2 ){ + int nCol, i, x; + sqlite3_stmt *pStmt = pArg->pStmt; + char z[100]; + nCol = sqlite3_column_count(pStmt); + raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol); + for(i=0; istatsOn==3 ){ - if( pArg->pStmt ){ - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); - raw_printf(pArg->out, "VM-steps: %d\n", iCur); - } - return 0; + if( pArg->statsOn==3 ){ + if( pArg->pStmt ){ + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); + raw_printf(pArg->out, "VM-steps: %d\n", iCur); } - - displayStatLine(pArg, "Memory Used:", - "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset); - displayStatLine(pArg, "Number of Outstanding Allocations:", - "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset); - if( pArg->shellFlgs & SHFLG_Pagecache ){ - displayStatLine(pArg, "Number of Pcache Pages Used:", - "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset); - } - displayStatLine(pArg, "Number of Pcache Overflow Bytes:", - "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset); - displayStatLine(pArg, "Largest Allocation:", - "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset); - displayStatLine(pArg, "Largest Pcache Allocation:", - "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset); + return 0; + } + + displayStatLine(pArg, "Memory Used:", + "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset); + displayStatLine(pArg, "Number of Outstanding Allocations:", + "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset); + if( pArg->shellFlgs & SHFLG_Pagecache ){ + displayStatLine(pArg, "Number of Pcache Pages Used:", + "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset); + } + displayStatLine(pArg, "Number of Pcache Overflow Bytes:", + "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset); + displayStatLine(pArg, "Largest Allocation:", + "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset); + displayStatLine(pArg, "Largest Pcache Allocation:", + "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset); #ifdef YYTRACKMAXSTACKDEPTH - displayStatLine(pArg, "Deepest Parser Stack:", - "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset); + displayStatLine(pArg, "Deepest Parser Stack:", + "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset); #endif - if( db ){ - if( pArg->shellFlgs & SHFLG_Lookaside ){ - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, - &iCur, &iHiwtr, bReset); - raw_printf(pArg->out, - "Lookaside Slots Used: %d (max %d)\n", - iCur, iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, - &iCur, &iHiwtr, bReset); - raw_printf(pArg->out, "Successful lookaside attempts: %d\n", - iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, - &iCur, &iHiwtr, bReset); - raw_printf(pArg->out, "Lookaside failures due to size: %d\n", - iHiwtr); - sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, - &iCur, &iHiwtr, bReset); - raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n", - iHiwtr); - } - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); - raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n", + if( db ){ + if( pArg->shellFlgs & SHFLG_Lookaside ){ + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, + &iCur, &iHiwtr, bReset); + raw_printf(pArg->out, + "Lookaside Slots Used: %d (max %d)\n", + iCur, iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, + &iCur, &iHiwtr, bReset); + raw_printf(pArg->out, "Successful lookaside attempts: %d\n", + iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, + &iCur, &iHiwtr, bReset); + raw_printf(pArg->out, "Lookaside failures due to size: %d\n", + iHiwtr); + sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, + &iCur, &iHiwtr, bReset); + raw_printf(pArg->out, "Lookaside failures due to OOM: %d\n", + iHiwtr); + } + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset); + raw_printf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); - raw_printf(pArg->out, "Page cache hits: %d\n", iCur); - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); - raw_printf(pArg->out, "Page cache misses: %d\n", iCur); - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); - raw_printf(pArg->out, "Page cache writes: %d\n", iCur); - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1); - raw_printf(pArg->out, "Page cache spills: %d\n", iCur); - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); - raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n", + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1); + raw_printf(pArg->out, "Page cache hits: %d\n", iCur); + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1); + raw_printf(pArg->out, "Page cache misses: %d\n", iCur); + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1); + raw_printf(pArg->out, "Page cache writes: %d\n", iCur); + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1); + raw_printf(pArg->out, "Page cache spills: %d\n", iCur); + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset); + raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur); - iHiwtr = iCur = -1; - sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); - raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", + iHiwtr = iCur = -1; + sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); + raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); - } - - if( pArg->pStmt ){ - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, - bReset); - raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); - raw_printf(pArg->out, "Sort Operations: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); - raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); - raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset); - raw_printf(pArg->out, "Reprepare operations: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset); - raw_printf(pArg->out, "Number of times run: %d\n", iCur); - iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset); - raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur); - } + } + + if( pArg->pStmt ){ + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, + bReset); + raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset); + raw_printf(pArg->out, "Sort Operations: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset); + raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset); + raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset); + raw_printf(pArg->out, "Reprepare operations: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset); + raw_printf(pArg->out, "Number of times run: %d\n", iCur); + iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset); + raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur); + } #ifdef __linux__ - displayLinuxIoStats(pArg->out); + displayLinuxIoStats(pArg->out); #endif - /* Do not remove this machine readable comment: extra-stats-output-here */ + /* Do not remove this machine readable comment: extra-stats-output-here */ - return 0; + return 0; } /* ** Display scan stats. */ static void display_scanstats( - sqlite3 *db, /* Database to query */ - ShellState *pArg /* Pointer to ShellState */ + sqlite3 *db, /* Database to query */ + ShellState *pArg /* Pointer to ShellState */ ){ #ifndef SQLITE_ENABLE_STMT_SCANSTATUS - UNUSED_PARAMETER(db); - UNUSED_PARAMETER(pArg); + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(pArg); #else - int i, k, n, mx; - raw_printf(pArg->out, "-------- scanstats --------\n"); - mx = 0; - for(k=0; k<=mx; k++){ - double rEstLoop = 1.0; - for(i=n=0; 1; i++){ - sqlite3_stmt *p = pArg->pStmt; - sqlite3_int64 nLoop, nVisit; - double rEst; - int iSid; - const char *zExplain; - if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ - break; - } - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); - if( iSid>mx ) mx = iSid; - if( iSid!=k ) continue; - if( n==0 ){ - rEstLoop = (double)nLoop; - if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k); - } - n++; - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); - utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain); - rEstLoop *= rEst; - raw_printf(pArg->out, - " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", - nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst - ); - } - } - raw_printf(pArg->out, "---------------------------\n"); + int i, k, n, mx; + raw_printf(pArg->out, "-------- scanstats --------\n"); + mx = 0; + for(k=0; k<=mx; k++){ + double rEstLoop = 1.0; + for(i=n=0; 1; i++){ + sqlite3_stmt *p = pArg->pStmt; + sqlite3_int64 nLoop, nVisit; + double rEst; + int iSid; + const char *zExplain; + if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ + break; + } + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); + if( iSid>mx ) mx = iSid; + if( iSid!=k ) continue; + if( n==0 ){ + rEstLoop = (double)nLoop; + if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k); + } + n++; + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); + utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain); + rEstLoop *= rEst; + raw_printf(pArg->out, + " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", + nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst + ); + } + } + raw_printf(pArg->out, "---------------------------\n"); #endif } @@ -13929,11 +13929,11 @@ static void display_scanstats( ** Otherwise, return zero. */ static int str_in_array(const char *zStr, const char **azArray){ - int i; - for(i=0; azArray[i]; i++){ - if( 0==strcmp(zStr, azArray[i]) ) return 1; - } - return 0; + int i; + for(i=0; azArray[i]; i++){ + if( 0==strcmp(zStr, azArray[i]) ) return 1; + } + return 0; } /* @@ -13955,93 +13955,93 @@ static int str_in_array(const char *zStr, const char **azArray){ ** and "Goto" by 2 spaces. */ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ - const char *zSql; /* The text of the SQL statement */ - const char *z; /* Used to check if this is an EXPLAIN */ - int *abYield = 0; /* True if op is an OP_Yield */ - int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ - int iOp; /* Index of operation in p->aiIndent[] */ - - const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 }; - const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", - "Rewind", 0 }; - const char *azGoto[] = { "Goto", 0 }; - - /* Try to figure out if this is really an EXPLAIN statement. If this + const char *zSql; /* The text of the SQL statement */ + const char *z; /* Used to check if this is an EXPLAIN */ + int *abYield = 0; /* True if op is an OP_Yield */ + int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ + int iOp; /* Index of operation in p->aiIndent[] */ + + const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 }; + const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", + "Rewind", 0 }; + const char *azGoto[] = { "Goto", 0 }; + + /* Try to figure out if this is really an EXPLAIN statement. If this ** cannot be verified, return early. */ - if( sqlite3_column_count(pSql)!=8 ){ - p->cMode = p->mode; - return; - } - zSql = sqlite3_sql(pSql); - if( zSql==0 ) return; - for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++); - if( sqlite3_strnicmp(z, "explain", 7) ){ - p->cMode = p->mode; - return; - } - - for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){ - int i; - int iAddr = sqlite3_column_int(pSql, 0); - const char *zOp = (const char*)sqlite3_column_text(pSql, 1); + if( sqlite3_column_count(pSql)!=8 ){ + p->cMode = p->mode; + return; + } + zSql = sqlite3_sql(pSql); + if( zSql==0 ) return; + for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++); + if( sqlite3_strnicmp(z, "explain", 7) ){ + p->cMode = p->mode; + return; + } + + for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){ + int i; + int iAddr = sqlite3_column_int(pSql, 0); + const char *zOp = (const char*)sqlite3_column_text(pSql, 1); - /* Set p2 to the P2 field of the current opcode. Then, assuming that + /* Set p2 to the P2 field of the current opcode. Then, assuming that ** p2 is an instruction address, set variable p2op to the index of that ** instruction in the aiIndent[] array. p2 and p2op may be different if ** the current instruction is part of a sub-program generated by an ** SQL trigger or foreign key. */ - int p2 = sqlite3_column_int(pSql, 3); - int p2op = (p2 + (iOp-iAddr)); + int p2 = sqlite3_column_int(pSql, 3); + int p2op = (p2 + (iOp-iAddr)); - /* Grow the p->aiIndent array as required */ - if( iOp>=nAlloc ){ - if( iOp==0 ){ - /* Do further verfication that this is explain output. Abort if + /* Grow the p->aiIndent array as required */ + if( iOp>=nAlloc ){ + if( iOp==0 ){ + /* Do further verfication that this is explain output. Abort if ** it is not */ - static const char *explainCols[] = { - "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" }; - int jj; - for(jj=0; jjcMode = p->mode; - sqlite3_reset(pSql); - return; - } - } - } - nAlloc += 100; - p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); - if( p->aiIndent==0 ) shell_out_of_memory(); - abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); - if( abYield==0 ) shell_out_of_memory(); + static const char *explainCols[] = { + "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" }; + int jj; + for(jj=0; jjcMode = p->mode; + sqlite3_reset(pSql); + return; + } } - abYield[iOp] = str_in_array(zOp, azYield); - p->aiIndent[iOp] = 0; - p->nIndent = iOp+1; + } + nAlloc += 100; + p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); + if( p->aiIndent==0 ) shell_out_of_memory(); + abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); + if( abYield==0 ) shell_out_of_memory(); + } + abYield[iOp] = str_in_array(zOp, azYield); + p->aiIndent[iOp] = 0; + p->nIndent = iOp+1; - if( str_in_array(zOp, azNext) ){ - for(i=p2op; iaiIndent[i] += 2; - } - if( str_in_array(zOp, azGoto) && p2opnIndent - && (abYield[p2op] || sqlite3_column_int(pSql, 2)) - ){ - for(i=p2op; iaiIndent[i] += 2; - } + if( str_in_array(zOp, azNext) ){ + for(i=p2op; iaiIndent[i] += 2; + } + if( str_in_array(zOp, azGoto) && p2opnIndent + && (abYield[p2op] || sqlite3_column_int(pSql, 2)) + ){ + for(i=p2op; iaiIndent[i] += 2; } + } - p->iIndent = 0; - sqlite3_free(abYield); - sqlite3_reset(pSql); + p->iIndent = 0; + sqlite3_free(abYield); + sqlite3_reset(pSql); } /* ** Free the array allocated by explain_data_prepare(). */ static void explain_data_delete(ShellState *p){ - sqlite3_free(p->aiIndent); - p->aiIndent = 0; - p->nIndent = 0; - p->iIndent = 0; + sqlite3_free(p->aiIndent); + p->aiIndent = 0; + p->nIndent = 0; + p->iIndent = 0; } /* @@ -14050,33 +14050,33 @@ static void explain_data_delete(ShellState *p){ static unsigned int savedSelectTrace; static unsigned int savedWhereTrace; static void disable_debug_trace_modes(void){ - unsigned int zero = 0; - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 0, &savedSelectTrace); - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &zero); - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 2, &savedWhereTrace); - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &zero); + unsigned int zero = 0; + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 0, &savedSelectTrace); + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &zero); + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 2, &savedWhereTrace); + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &zero); } static void restore_debug_trace_modes(void){ - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &savedSelectTrace); - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &savedWhereTrace); + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &savedSelectTrace); + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &savedWhereTrace); } /* Create the TEMP table used to store parameter bindings */ static void bind_table_init(ShellState *p){ - int wrSchema = 0; - int defensiveMode = 0; - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0); - sqlite3_exec(p->db, - "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n" - " key TEXT PRIMARY KEY,\n" - " value\n" - ") WITHOUT ROWID;", - 0, 0, 0); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); - sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0); + int wrSchema = 0; + int defensiveMode = 0; + sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0); + sqlite3_exec(p->db, + "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n" + " key TEXT PRIMARY KEY,\n" + " value\n" + ") WITHOUT ROWID;", + 0, 0, 0); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0); + sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0); } /* @@ -14092,37 +14092,37 @@ static void bind_table_init(ShellState *p){ ** tables. The table must be in the TEMP schema. */ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){ - int nVar; - int i; - int rc; - sqlite3_stmt *pQ = 0; - - nVar = sqlite3_bind_parameter_count(pStmt); - if( nVar==0 ) return; /* Nothing to do */ - if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters", - "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){ - return; /* Parameter table does not exist */ - } - rc = sqlite3_prepare_v2(pArg->db, - "SELECT value FROM temp.sqlite_parameters" - " WHERE key=?1", -1, &pQ, 0); - if( rc || pQ==0 ) return; - for(i=1; i<=nVar; i++){ - char zNum[30]; - const char *zVar = sqlite3_bind_parameter_name(pStmt, i); - if( zVar==0 ){ - sqlite3_snprintf(sizeof(zNum),zNum,"?%d",i); - zVar = zNum; - } - sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC); - if( sqlite3_step(pQ)==SQLITE_ROW ){ - sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0)); - }else{ - sqlite3_bind_null(pStmt, i); - } - sqlite3_reset(pQ); + int nVar; + int i; + int rc; + sqlite3_stmt *pQ = 0; + + nVar = sqlite3_bind_parameter_count(pStmt); + if( nVar==0 ) return; /* Nothing to do */ + if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters", + "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){ + return; /* Parameter table does not exist */ + } + rc = sqlite3_prepare_v2(pArg->db, + "SELECT value FROM temp.sqlite_parameters" + " WHERE key=?1", -1, &pQ, 0); + if( rc || pQ==0 ) return; + for(i=1; i<=nVar; i++){ + char zNum[30]; + const char *zVar = sqlite3_bind_parameter_name(pStmt, i); + if( zVar==0 ){ + sqlite3_snprintf(sizeof(zNum),zNum,"?%d",i); + zVar = zNum; + } + sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC); + if( sqlite3_step(pQ)==SQLITE_ROW ){ + sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0)); + }else{ + sqlite3_bind_null(pStmt, i); } - sqlite3_finalize(pQ); + sqlite3_reset(pQ); + } + sqlite3_finalize(pQ); } /* @@ -14154,39 +14154,39 @@ static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){ ** characters */ static void print_box_line(FILE *out, int N){ - const char zDash[] = - BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 - BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24; - const int nDash = sizeof(zDash) - 1; - N *= 3; - while( N>nDash ){ - utf8_printf(out, zDash); - N -= nDash; - } - utf8_printf(out, "%.*s", N, zDash); + const char zDash[] = + BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 + BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24; + const int nDash = sizeof(zDash) - 1; + N *= 3; + while( N>nDash ){ + utf8_printf(out, zDash); + N -= nDash; + } + utf8_printf(out, "%.*s", N, zDash); } /* ** Draw a horizontal separator for a MODE_Box table. */ static void print_box_row_separator( - ShellState *p, - int nArg, - const char *zSep1, - const char *zSep2, - const char *zSep3 + ShellState *p, + int nArg, + const char *zSep1, + const char *zSep2, + const char *zSep3 ){ - int i; - if( nArg>0 ){ - utf8_printf(p->out, "%s", zSep1); - print_box_line(p->out, p->actualWidth[0]+2); - for(i=1; iout, "%s", zSep2); - print_box_line(p->out, p->actualWidth[i]+2); - } - utf8_printf(p->out, "%s", zSep3); + int i; + if( nArg>0 ){ + utf8_printf(p->out, "%s", zSep1); + print_box_line(p->out, p->actualWidth[0]+2); + for(i=1; iout, "%s", zSep2); + print_box_line(p->out, p->actualWidth[i]+2); } - fputs("\n", p->out); + utf8_printf(p->out, "%s", zSep3); + } + fputs("\n", p->out); } @@ -14202,227 +14202,227 @@ static void print_box_row_separator( ** any output. */ static void exec_prepared_stmt_columnar( - ShellState *p, /* Pointer to ShellState */ - sqlite3_stmt *pStmt /* Statment to run */ + ShellState *p, /* Pointer to ShellState */ + sqlite3_stmt *pStmt /* Statment to run */ ){ - sqlite3_int64 nRow = 0; - int nColumn = 0; - char **azData = 0; - sqlite3_int64 nAlloc = 0; - const char *z; - int rc; - sqlite3_int64 i, nData; - int j, nTotal, w, n; - const char *colSep = 0; - const char *rowSep = 0; - - rc = sqlite3_step(pStmt); - if( rc!=SQLITE_ROW ) return; - nColumn = sqlite3_column_count(pStmt); - nAlloc = nColumn*4; - if( nAlloc<=0 ) nAlloc = 1; - azData = sqlite3_malloc64( nAlloc*sizeof(char*) ); - if( azData==0 ) shell_out_of_memory(); + sqlite3_int64 nRow = 0; + int nColumn = 0; + char **azData = 0; + sqlite3_int64 nAlloc = 0; + const char *z; + int rc; + sqlite3_int64 i, nData; + int j, nTotal, w, n; + const char *colSep = 0; + const char *rowSep = 0; + + rc = sqlite3_step(pStmt); + if( rc!=SQLITE_ROW ) return; + nColumn = sqlite3_column_count(pStmt); + nAlloc = nColumn*4; + if( nAlloc<=0 ) nAlloc = 1; + azData = sqlite3_malloc64( nAlloc*sizeof(char*) ); + if( azData==0 ) shell_out_of_memory(); + for(i=0; i= nAlloc ){ + nAlloc *= 2; + azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*)); + if( azData==0 ) shell_out_of_memory(); + } + nRow++; for(i=0; i= nAlloc ){ - nAlloc *= 2; - azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*)); - if( azData==0 ) shell_out_of_memory(); - } - nRow++; + z = (const char*)sqlite3_column_text(pStmt,i); + azData[nRow*nColumn + i] = z ? strdup(z) : 0; + } + }while( sqlite3_step(pStmt)==SQLITE_ROW ); + if( nColumn>p->nWidth ){ + p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int)); + if( p->colWidth==0 ) shell_out_of_memory(); + for(i=p->nWidth; icolWidth[i] = 0; + p->nWidth = nColumn; + p->actualWidth = &p->colWidth[nColumn]; + } + memset(p->actualWidth, 0, nColumn*sizeof(int)); + for(i=0; icolWidth[i]; + if( w<0 ) w = -w; + p->actualWidth[i] = w; + } + nTotal = nColumn*(nRow+1); + for(i=0; inullValue; + n = strlenChar(z); + j = i%nColumn; + if( n>p->actualWidth[j] ) p->actualWidth[j] = n; + } + if( seenInterrupt ) goto columnar_end; + if( nColumn==0 ) goto columnar_end; + switch( p->cMode ){ + case MODE_Column: { + colSep = " "; + rowSep = "\n"; + if( p->showHeader ){ for(i=0; ip->nWidth ){ - p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int)); - if( p->colWidth==0 ) shell_out_of_memory(); - for(i=p->nWidth; icolWidth[i] = 0; - p->nWidth = nColumn; - p->actualWidth = &p->colWidth[nColumn]; - } - memset(p->actualWidth, 0, nColumn*sizeof(int)); - for(i=0; icolWidth[i]; - if( w<0 ) w = -w; - p->actualWidth[i] = w; - } - nTotal = nColumn*(nRow+1); - for(i=0; inullValue; - n = strlenChar(z); - j = i%nColumn; - if( n>p->actualWidth[j] ) p->actualWidth[j] = n; - } - if( seenInterrupt ) goto columnar_end; - if( nColumn==0 ) goto columnar_end; - switch( p->cMode ){ - case MODE_Column: { - colSep = " "; - rowSep = "\n"; - if( p->showHeader ){ - for(i=0; iactualWidth[i]; - if( p->colWidth[i]<0 ) w = -w; - utf8_width_print(p->out, w, azData[i]); - fputs(i==nColumn-1?"\n":" ", p->out); - } - for(i=0; iout, p->actualWidth[i]); - fputs(i==nColumn-1?"\n":" ", p->out); - } - } - break; - } - case MODE_Table: { - colSep = " | "; - rowSep = " |\n"; - print_row_separator(p, nColumn, "+"); - fputs("| ", p->out); - for(i=0; iactualWidth[i]; - n = strlenChar(azData[i]); - utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); - fputs(i==nColumn-1?" |\n":" | ", p->out); - } - print_row_separator(p, nColumn, "+"); - break; - } - case MODE_Markdown: { - colSep = " | "; - rowSep = " |\n"; - fputs("| ", p->out); - for(i=0; iactualWidth[i]; - n = strlenChar(azData[i]); - utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); - fputs(i==nColumn-1?" |\n":" | ", p->out); - } - print_row_separator(p, nColumn, "|"); - break; - } - case MODE_Box: { - colSep = " " BOX_13 " "; - rowSep = " " BOX_13 "\n"; - print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34); - utf8_printf(p->out, BOX_13 " "); - for(i=0; iactualWidth[i]; - n = strlenChar(azData[i]); - utf8_printf(p->out, "%*s%s%*s%s", - (w-n)/2, "", azData[i], (w-n+1)/2, "", - i==nColumn-1?" "BOX_13"\n":" "BOX_13" "); - } - print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134); - break; + w = p->actualWidth[i]; + if( p->colWidth[i]<0 ) w = -w; + utf8_width_print(p->out, w, azData[i]); + fputs(i==nColumn-1?"\n":" ", p->out); } - } - for(i=nColumn, j=0; icMode!=MODE_Column ){ - utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| "); - } - z = azData[i]; - if( z==0 ) z = p->nullValue; - w = p->actualWidth[j]; - if( p->colWidth[j]<0 ) w = -w; - utf8_width_print(p->out, w, z); - if( j==nColumn-1 ){ - utf8_printf(p->out, "%s", rowSep); - j = -1; - if( seenInterrupt ) goto columnar_end; - }else{ - utf8_printf(p->out, "%s", colSep); - } - } - if( p->cMode==MODE_Table ){ - print_row_separator(p, nColumn, "+"); - }else if( p->cMode==MODE_Box ){ - print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14); - } + for(i=0; iout, p->actualWidth[i]); + fputs(i==nColumn-1?"\n":" ", p->out); + } + } + break; + } + case MODE_Table: { + colSep = " | "; + rowSep = " |\n"; + print_row_separator(p, nColumn, "+"); + fputs("| ", p->out); + for(i=0; iactualWidth[i]; + n = strlenChar(azData[i]); + utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); + fputs(i==nColumn-1?" |\n":" | ", p->out); + } + print_row_separator(p, nColumn, "+"); + break; + } + case MODE_Markdown: { + colSep = " | "; + rowSep = " |\n"; + fputs("| ", p->out); + for(i=0; iactualWidth[i]; + n = strlenChar(azData[i]); + utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, ""); + fputs(i==nColumn-1?" |\n":" | ", p->out); + } + print_row_separator(p, nColumn, "|"); + break; + } + case MODE_Box: { + colSep = " " BOX_13 " "; + rowSep = " " BOX_13 "\n"; + print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34); + utf8_printf(p->out, BOX_13 " "); + for(i=0; iactualWidth[i]; + n = strlenChar(azData[i]); + utf8_printf(p->out, "%*s%s%*s%s", + (w-n)/2, "", azData[i], (w-n+1)/2, "", + i==nColumn-1?" "BOX_13"\n":" "BOX_13" "); + } + print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134); + break; + } + } + for(i=nColumn, j=0; icMode!=MODE_Column ){ + utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| "); + } + z = azData[i]; + if( z==0 ) z = p->nullValue; + w = p->actualWidth[j]; + if( p->colWidth[j]<0 ) w = -w; + utf8_width_print(p->out, w, z); + if( j==nColumn-1 ){ + utf8_printf(p->out, "%s", rowSep); + j = -1; + if( seenInterrupt ) goto columnar_end; + }else{ + utf8_printf(p->out, "%s", colSep); + } + } + if( p->cMode==MODE_Table ){ + print_row_separator(p, nColumn, "+"); + }else if( p->cMode==MODE_Box ){ + print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14); + } columnar_end: - if( seenInterrupt ){ - utf8_printf(p->out, "Interrupt\n"); - } - nData = (nRow+1)*nColumn; - for(i=0; iout, "Interrupt\n"); + } + nData = (nRow+1)*nColumn; + for(i=0; icMode==MODE_Column - || pArg->cMode==MODE_Table - || pArg->cMode==MODE_Box - || pArg->cMode==MODE_Markdown - ){ - exec_prepared_stmt_columnar(pArg, pStmt); - return; - } - - /* perform the first step. this will tell us if we + int rc; + + if( pArg->cMode==MODE_Column + || pArg->cMode==MODE_Table + || pArg->cMode==MODE_Box + || pArg->cMode==MODE_Markdown + ){ + exec_prepared_stmt_columnar(pArg, pStmt); + return; + } + + /* perform the first step. this will tell us if we ** have a result set or not and how wide it is. */ - rc = sqlite3_step(pStmt); - /* if we have a result set... */ - if( SQLITE_ROW == rc ){ - /* allocate space for col name ptr, value ptr, and type */ - int nCol = sqlite3_column_count(pStmt); - void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); - if( !pData ){ - shell_out_of_memory(); - }else{ - char **azCols = (char **)pData; /* Names of result columns */ - char **azVals = &azCols[nCol]; /* Results */ - int *aiTypes = (int *)&azVals[nCol]; /* Result types */ - int i, x; - assert(sizeof(int) <= sizeof(char *)); - /* save off ptrs to column names */ - for(i=0; icMode==MODE_Insert ){ - azVals[i] = ""; - }else{ - azVals[i] = (char*)sqlite3_column_text(pStmt, i); - } - if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ - rc = SQLITE_NOMEM; - break; /* from for */ - } - } /* end for */ - - /* if data and types extracted successfully... */ - if( SQLITE_ROW == rc ){ - /* call the supplied callback with the result row data */ - if( shell_callback(pArg, nCol, azVals, azCols, aiTypes) ){ - rc = SQLITE_ABORT; - }else{ - rc = sqlite3_step(pStmt); - } - } - } while( SQLITE_ROW == rc ); - sqlite3_free(pData); - if( pArg->cMode==MODE_Json ){ - fputs("]\n", pArg->out); - } + rc = sqlite3_step(pStmt); + /* if we have a result set... */ + if( SQLITE_ROW == rc ){ + /* allocate space for col name ptr, value ptr, and type */ + int nCol = sqlite3_column_count(pStmt); + void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1); + if( !pData ){ + shell_out_of_memory(); + }else{ + char **azCols = (char **)pData; /* Names of result columns */ + char **azVals = &azCols[nCol]; /* Results */ + int *aiTypes = (int *)&azVals[nCol]; /* Result types */ + int i, x; + assert(sizeof(int) <= sizeof(char *)); + /* save off ptrs to column names */ + for(i=0; icMode==MODE_Insert ){ + azVals[i] = ""; + }else{ + azVals[i] = (char*)sqlite3_column_text(pStmt, i); + } + if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ + rc = SQLITE_NOMEM; + break; /* from for */ + } + } /* end for */ + + /* if data and types extracted successfully... */ + if( SQLITE_ROW == rc ){ + /* call the supplied callback with the result row data */ + if( shell_callback(pArg, nCol, azVals, azCols, aiTypes) ){ + rc = SQLITE_ABORT; + }else{ + rc = sqlite3_step(pStmt); + } } + } while( SQLITE_ROW == rc ); + sqlite3_free(pData); + if( pArg->cMode==MODE_Json ){ + fputs("]\n", pArg->out); + } } + } } #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -14437,18 +14437,18 @@ static void exec_prepared_stmt( ** caller to eventually free this buffer using sqlite3_free(). */ static int expertHandleSQL( - ShellState *pState, - const char *zSql, - char **pzErr + ShellState *pState, + const char *zSql, + char **pzErr ){ - assert( pState->expert.pExpert ); - assert( pzErr==0 || *pzErr==0 ); - return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr); + assert( pState->expert.pExpert ); + assert( pzErr==0 || *pzErr==0 ); + return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr); } /* ** This function is called either to silently clean up the object -** created by the ".expert" command (if bCancel==1), or to generate a +** created by the ".expert" command (if bCancel==1), or to generate a ** report from it and then clean it up (if bCancel==0). ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error @@ -14457,102 +14457,102 @@ static int expertHandleSQL( ** caller to eventually free this buffer using sqlite3_free(). */ static int expertFinish( - ShellState *pState, - int bCancel, - char **pzErr + ShellState *pState, + int bCancel, + char **pzErr ){ - int rc = SQLITE_OK; - sqlite3expert *p = pState->expert.pExpert; - assert( p ); - assert( bCancel || pzErr==0 || *pzErr==0 ); - if( bCancel==0 ){ - FILE *out = pState->out; - int bVerbose = pState->expert.bVerbose; - - rc = sqlite3_expert_analyze(p, pzErr); - if( rc==SQLITE_OK ){ - int nQuery = sqlite3_expert_count(p); - int i; - - if( bVerbose ){ - const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES); - raw_printf(out, "-- Candidates -----------------------------\n"); - raw_printf(out, "%s\n", zCand); - } - for(i=0; iexpert.pExpert = 0; - return rc; + int rc = SQLITE_OK; + sqlite3expert *p = pState->expert.pExpert; + assert( p ); + assert( bCancel || pzErr==0 || *pzErr==0 ); + if( bCancel==0 ){ + FILE *out = pState->out; + int bVerbose = pState->expert.bVerbose; + + rc = sqlite3_expert_analyze(p, pzErr); + if( rc==SQLITE_OK ){ + int nQuery = sqlite3_expert_count(p); + int i; + + if( bVerbose ){ + const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES); + raw_printf(out, "-- Candidates -----------------------------\n"); + raw_printf(out, "%s\n", zCand); + } + for(i=0; iexpert.pExpert = 0; + return rc; } /* ** Implementation of ".expert" dot command. */ static int expertDotCommand( - ShellState *pState, /* Current shell tool state */ - char **azArg, /* Array of arguments passed to dot command */ - int nArg /* Number of entries in azArg[] */ + ShellState *pState, /* Current shell tool state */ + char **azArg, /* Array of arguments passed to dot command */ + int nArg /* Number of entries in azArg[] */ ){ - int rc = SQLITE_OK; - char *zErr = 0; - int i; - int iSample = 0; + int rc = SQLITE_OK; + char *zErr = 0; + int i; + int iSample = 0; - assert( pState->expert.pExpert==0 ); - memset(&pState->expert, 0, sizeof(ExpertInfo)); + assert( pState->expert.pExpert==0 ); + memset(&pState->expert, 0, sizeof(ExpertInfo)); - for(i=1; rc==SQLITE_OK && i=2 && 0==strncmp(z, "-verbose", n) ){ - pState->expert.bVerbose = 1; - } - else if( n>=2 && 0==strncmp(z, "-sample", n) ){ - if( i==(nArg-1) ){ - raw_printf(stderr, "option requires an argument: %s\n", z); - rc = SQLITE_ERROR; - }else{ - iSample = (int)integerValue(azArg[++i]); - if( iSample<0 || iSample>100 ){ - raw_printf(stderr, "value out of range: %s\n", azArg[i]); - rc = SQLITE_ERROR; - } - } - } - else{ - raw_printf(stderr, "unknown option: %s\n", z); - rc = SQLITE_ERROR; + for(i=1; rc==SQLITE_OK && i=2 && 0==strncmp(z, "-verbose", n) ){ + pState->expert.bVerbose = 1; + } + else if( n>=2 && 0==strncmp(z, "-sample", n) ){ + if( i==(nArg-1) ){ + raw_printf(stderr, "option requires an argument: %s\n", z); + rc = SQLITE_ERROR; + }else{ + iSample = (int)integerValue(azArg[++i]); + if( iSample<0 || iSample>100 ){ + raw_printf(stderr, "value out of range: %s\n", azArg[i]); + rc = SQLITE_ERROR; } + } + } + else{ + raw_printf(stderr, "unknown option: %s\n", z); + rc = SQLITE_ERROR; } + } - if( rc==SQLITE_OK ){ - pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); - if( pState->expert.pExpert==0 ){ - raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr); - rc = SQLITE_ERROR; - }else{ - sqlite3_expert_config( - pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample - ); - } + if( rc==SQLITE_OK ){ + pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); + if( pState->expert.pExpert==0 ){ + raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr); + rc = SQLITE_ERROR; + }else{ + sqlite3_expert_config( + pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample + ); } + } - return rc; + return rc; } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ @@ -14566,169 +14566,169 @@ static int expertDotCommand( ** and callback data argument. */ static int shell_exec( - ShellState *pArg, /* Pointer to ShellState */ - const char *zSql, /* SQL to be evaluated */ - char **pzErrMsg /* Error msg written here */ + ShellState *pArg, /* Pointer to ShellState */ + const char *zSql, /* SQL to be evaluated */ + char **pzErrMsg /* Error msg written here */ ){ - sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ - int rc = SQLITE_OK; /* Return Code */ - int rc2; - const char *zLeftover; /* Tail of unprocessed SQL */ - sqlite3 *db = pArg->db; + sqlite3_stmt *pStmt = NULL; /* Statement to execute. */ + int rc = SQLITE_OK; /* Return Code */ + int rc2; + const char *zLeftover; /* Tail of unprocessed SQL */ + sqlite3 *db = pArg->db; - if( pzErrMsg ){ - *pzErrMsg = NULL; - } + if( pzErrMsg ){ + *pzErrMsg = NULL; + } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pArg->expert.pExpert ){ - rc = expertHandleSQL(pArg, zSql, pzErrMsg); - return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg); - } + if( pArg->expert.pExpert ){ + rc = expertHandleSQL(pArg, zSql, pzErrMsg); + return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg); + } #endif - while( zSql[0] && (SQLITE_OK == rc) ){ - static const char *zStmtSql; - rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); - if( SQLITE_OK != rc ){ - if( pzErrMsg ){ - *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)", rc); - } - }else{ - if( !pStmt ){ - /* this happens for a comment or white-space */ - zSql = zLeftover; - while( IsSpace(zSql[0]) ) zSql++; - continue; - } - zStmtSql = sqlite3_sql(pStmt); - if( zStmtSql==0 ) zStmtSql = ""; - while( IsSpace(zStmtSql[0]) ) zStmtSql++; - - /* save off the prepared statment handle and reset row count */ - if( pArg ){ - pArg->pStmt = pStmt; - pArg->cnt = 0; - } - - /* echo the sql statement if echo on */ - if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){ - utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); - } - - /* Show the EXPLAIN QUERY PLAN if .eqp is on */ - if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){ - sqlite3_stmt *pExplain; - char *zEQP; - int triggerEQP = 0; - disable_debug_trace_modes(); - sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP); - if( pArg->autoEQP>=AUTOEQP_trigger ){ - sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0); - } - zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql); - rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); - if( rc==SQLITE_OK ){ - while( sqlite3_step(pExplain)==SQLITE_ROW ){ - const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3); - int iEqpId = sqlite3_column_int(pExplain, 0); - int iParentId = sqlite3_column_int(pExplain, 1); - if( zEQPLine==0 ) zEQPLine = ""; - if( zEQPLine[0]=='-' ) eqp_render(pArg); - eqp_append(pArg, iEqpId, iParentId, zEQPLine); - } - eqp_render(pArg); - } - sqlite3_finalize(pExplain); - sqlite3_free(zEQP); - if( pArg->autoEQP>=AUTOEQP_full ){ - /* Also do an EXPLAIN for ".eqp full" mode */ - zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql); - rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); - if( rc==SQLITE_OK ){ - pArg->cMode = MODE_Explain; - explain_data_prepare(pArg, pExplain); - exec_prepared_stmt(pArg, pExplain); - explain_data_delete(pArg); - } - sqlite3_finalize(pExplain); - sqlite3_free(zEQP); - } - if( pArg->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){ - sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 0, 0); - /* Reprepare pStmt before reactiving trace modes */ - sqlite3_finalize(pStmt); - sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); - if( pArg ) pArg->pStmt = pStmt; - } - restore_debug_trace_modes(); - } - - if( pArg ){ - pArg->cMode = pArg->mode; - if( pArg->autoExplain ){ - if( sqlite3_stmt_isexplain(pStmt)==1 ){ - pArg->cMode = MODE_Explain; - } - if( sqlite3_stmt_isexplain(pStmt)==2 ){ - pArg->cMode = MODE_EQP; - } - } - - /* If the shell is currently in ".explain" mode, gather the extra + while( zSql[0] && (SQLITE_OK == rc) ){ + static const char *zStmtSql; + rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); + if( SQLITE_OK != rc ){ + if( pzErrMsg ){ + *pzErrMsg = save_err_msg(db, "in prepare, %s (%d)", rc); + } + }else{ + if( !pStmt ){ + /* this happens for a comment or white-space */ + zSql = zLeftover; + while( IsSpace(zSql[0]) ) zSql++; + continue; + } + zStmtSql = sqlite3_sql(pStmt); + if( zStmtSql==0 ) zStmtSql = ""; + while( IsSpace(zStmtSql[0]) ) zStmtSql++; + + /* save off the prepared statment handle and reset row count */ + if( pArg ){ + pArg->pStmt = pStmt; + pArg->cnt = 0; + } + + /* echo the sql statement if echo on */ + if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){ + utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); + } + + /* Show the EXPLAIN QUERY PLAN if .eqp is on */ + if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){ + sqlite3_stmt *pExplain; + char *zEQP; + int triggerEQP = 0; + disable_debug_trace_modes(); + sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP); + if( pArg->autoEQP>=AUTOEQP_trigger ){ + sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0); + } + zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql); + rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); + if( rc==SQLITE_OK ){ + while( sqlite3_step(pExplain)==SQLITE_ROW ){ + const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3); + int iEqpId = sqlite3_column_int(pExplain, 0); + int iParentId = sqlite3_column_int(pExplain, 1); + if( zEQPLine==0 ) zEQPLine = ""; + if( zEQPLine[0]=='-' ) eqp_render(pArg); + eqp_append(pArg, iEqpId, iParentId, zEQPLine); + } + eqp_render(pArg); + } + sqlite3_finalize(pExplain); + sqlite3_free(zEQP); + if( pArg->autoEQP>=AUTOEQP_full ){ + /* Also do an EXPLAIN for ".eqp full" mode */ + zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql); + rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); + if( rc==SQLITE_OK ){ + pArg->cMode = MODE_Explain; + explain_data_prepare(pArg, pExplain); + exec_prepared_stmt(pArg, pExplain); + explain_data_delete(pArg); + } + sqlite3_finalize(pExplain); + sqlite3_free(zEQP); + } + if( pArg->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){ + sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 0, 0); + /* Reprepare pStmt before reactiving trace modes */ + sqlite3_finalize(pStmt); + sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); + if( pArg ) pArg->pStmt = pStmt; + } + restore_debug_trace_modes(); + } + + if( pArg ){ + pArg->cMode = pArg->mode; + if( pArg->autoExplain ){ + if( sqlite3_stmt_isexplain(pStmt)==1 ){ + pArg->cMode = MODE_Explain; + } + if( sqlite3_stmt_isexplain(pStmt)==2 ){ + pArg->cMode = MODE_EQP; + } + } + + /* If the shell is currently in ".explain" mode, gather the extra ** data required to add indents to the output.*/ - if( pArg->cMode==MODE_Explain ){ - explain_data_prepare(pArg, pStmt); - } - } + if( pArg->cMode==MODE_Explain ){ + explain_data_prepare(pArg, pStmt); + } + } - bind_prepared_stmt(pArg, pStmt); - exec_prepared_stmt(pArg, pStmt); - explain_data_delete(pArg); - eqp_render(pArg); + bind_prepared_stmt(pArg, pStmt); + exec_prepared_stmt(pArg, pStmt); + explain_data_delete(pArg); + eqp_render(pArg); - /* print usage stats if stats on */ - if( pArg && pArg->statsOn ){ - display_stats(db, pArg, 0); - } + /* print usage stats if stats on */ + if( pArg && pArg->statsOn ){ + display_stats(db, pArg, 0); + } - /* print loop-counters if required */ - if( pArg && pArg->scanstatsOn ){ - display_scanstats(db, pArg); - } + /* print loop-counters if required */ + if( pArg && pArg->scanstatsOn ){ + display_scanstats(db, pArg); + } - /* Finalize the statement just executed. If this fails, save a + /* Finalize the statement just executed. If this fails, save a ** copy of the error message. Otherwise, set zSql to point to the ** next statement to execute. */ - rc2 = sqlite3_finalize(pStmt); - if( rc!=SQLITE_NOMEM ) rc = rc2; - if( rc==SQLITE_OK ){ - zSql = zLeftover; - while( IsSpace(zSql[0]) ) zSql++; - }else if( pzErrMsg ){ - *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc); - } + rc2 = sqlite3_finalize(pStmt); + if( rc!=SQLITE_NOMEM ) rc = rc2; + if( rc==SQLITE_OK ){ + zSql = zLeftover; + while( IsSpace(zSql[0]) ) zSql++; + }else if( pzErrMsg ){ + *pzErrMsg = save_err_msg(db, "stepping, %s (%d)", rc); + } - /* clear saved stmt handle */ - if( pArg ){ - pArg->pStmt = NULL; - } - } - } /* end while */ + /* clear saved stmt handle */ + if( pArg ){ + pArg->pStmt = NULL; + } + } + } /* end while */ - return rc; + return rc; } /* ** Release memory previously allocated by tableColumnList(). */ static void freeColumnList(char **azCol){ - int i; - for(i=1; azCol[i]; i++){ - sqlite3_free(azCol[i]); - } - /* azCol[0] is a static string */ - sqlite3_free(azCol); + int i; + for(i=1; azCol[i]; i++){ + sqlite3_free(azCol[i]); + } + /* azCol[0] is a static string */ + sqlite3_free(azCol); } /* @@ -14745,108 +14745,108 @@ static void freeColumnList(char **azCol){ ** by an entry with azCol[i]==0. */ static char **tableColumnList(ShellState *p, const char *zTab){ - char **azCol = 0; - sqlite3_stmt *pStmt; - char *zSql; - int nCol = 0; - int nAlloc = 0; - int nPK = 0; /* Number of PRIMARY KEY columns seen */ - int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */ - int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid); - int rc; - - zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab); - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - if( rc ) return 0; - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - if( nCol>=nAlloc-2 ){ - nAlloc = nAlloc*2 + nCol + 10; - azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0])); - if( azCol==0 ) shell_out_of_memory(); - } - azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); - if( sqlite3_column_int(pStmt, 5) ){ - nPK++; - if( nPK==1 - && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2), - "INTEGER")==0 - ){ - isIPK = 1; - }else{ - isIPK = 0; - } - } - } - sqlite3_finalize(pStmt); - if( azCol==0 ) return 0; - azCol[0] = 0; - azCol[nCol+1] = 0; - - /* The decision of whether or not a rowid really needs to be preserved + char **azCol = 0; + sqlite3_stmt *pStmt; + char *zSql; + int nCol = 0; + int nAlloc = 0; + int nPK = 0; /* Number of PRIMARY KEY columns seen */ + int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */ + int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid); + int rc; + + zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rc ) return 0; + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + if( nCol>=nAlloc-2 ){ + nAlloc = nAlloc*2 + nCol + 10; + azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0])); + if( azCol==0 ) shell_out_of_memory(); + } + azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); + if( sqlite3_column_int(pStmt, 5) ){ + nPK++; + if( nPK==1 + && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2), + "INTEGER")==0 + ){ + isIPK = 1; + }else{ + isIPK = 0; + } + } + } + sqlite3_finalize(pStmt); + if( azCol==0 ) return 0; + azCol[0] = 0; + azCol[nCol+1] = 0; + + /* The decision of whether or not a rowid really needs to be preserved ** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table ** or a table with an INTEGER PRIMARY KEY. We are unable to preserve ** rowids on tables where the rowid is inaccessible because there are other ** columns in the table named "rowid", "_rowid_", and "oid". */ - if( preserveRowid && isIPK ){ - /* If a single PRIMARY KEY column with type INTEGER was seen, then it + if( preserveRowid && isIPK ){ + /* If a single PRIMARY KEY column with type INTEGER was seen, then it ** might be an alise for the ROWID. But it might also be a WITHOUT ROWID ** table or a INTEGER PRIMARY KEY DESC column, neither of which are ** ROWID aliases. To distinguish these cases, check to see if ** there is a "pk" entry in "PRAGMA index_list". There will be ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID. */ - zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)" - " WHERE origin='pk'", zTab); - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - if( rc ){ - freeColumnList(azCol); - return 0; - } - rc = sqlite3_step(pStmt); - sqlite3_finalize(pStmt); - preserveRowid = rc==SQLITE_ROW; + zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)" + " WHERE origin='pk'", zTab); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rc ){ + freeColumnList(azCol); + return 0; } - if( preserveRowid ){ - /* Only preserve the rowid if we can find a name to use for the + rc = sqlite3_step(pStmt); + sqlite3_finalize(pStmt); + preserveRowid = rc==SQLITE_ROW; + } + if( preserveRowid ){ + /* Only preserve the rowid if we can find a name to use for the ** rowid */ - static char *azRowid[] = { "rowid", "_rowid_", "oid" }; - int i, j; - for(j=0; j<3; j++){ - for(i=1; i<=nCol; i++){ - if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break; - } - if( i>nCol ){ - /* At this point, we know that azRowid[j] is not the name of any + static char *azRowid[] = { "rowid", "_rowid_", "oid" }; + int i, j; + for(j=0; j<3; j++){ + for(i=1; i<=nCol; i++){ + if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break; + } + if( i>nCol ){ + /* At this point, we know that azRowid[j] is not the name of any ** ordinary column in the table. Verify that azRowid[j] is a valid ** name for the rowid before adding it to azCol[0]. WITHOUT ROWID ** tables will fail this last check */ - rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0); - if( rc==SQLITE_OK ) azCol[0] = azRowid[j]; - break; - } - } + rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0); + if( rc==SQLITE_OK ) azCol[0] = azRowid[j]; + break; + } } - return azCol; + } + return azCol; } /* ** Toggle the reverse_unordered_selects setting. */ static void toggleSelectOrder(sqlite3 *db){ - sqlite3_stmt *pStmt = 0; - int iSetting = 0; - char zStmt[100]; - sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0); - if( sqlite3_step(pStmt)==SQLITE_ROW ){ - iSetting = sqlite3_column_int(pStmt, 0); - } - sqlite3_finalize(pStmt); - sqlite3_snprintf(sizeof(zStmt), zStmt, - "PRAGMA reverse_unordered_selects(%d)", !iSetting); - sqlite3_exec(db, zStmt, 0, 0, 0); + sqlite3_stmt *pStmt = 0; + int iSetting = 0; + char zStmt[100]; + sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0); + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + iSetting = sqlite3_column_int(pStmt, 0); + } + sqlite3_finalize(pStmt); + sqlite3_snprintf(sizeof(zStmt), zStmt, + "PRAGMA reverse_unordered_selects(%d)", !iSetting); + sqlite3_exec(db, zStmt, 0, 0, 0); } /* @@ -14856,114 +14856,114 @@ static void toggleSelectOrder(sqlite3 *db){ ** This routine should print text sufficient to recreate the table. */ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){ - int rc; - const char *zTable; - const char *zType; - const char *zSql; - ShellState *p = (ShellState *)pArg; - int dataOnly; - int noSys; - - UNUSED_PARAMETER(azNotUsed); - if( nArg!=3 || azArg==0 ) return 0; - zTable = azArg[0]; - zType = azArg[1]; - zSql = azArg[2]; - dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0; - noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0; - - if( strcmp(zTable, "sqlite_sequence")==0 && !noSys ){ - if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n"); - }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){ - if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n"); - }else if( strncmp(zTable, "sqlite_", 7)==0 ){ - return 0; - }else if( dataOnly ){ - /* no-op */ - }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ - char *zIns; - if( !p->writableSchema ){ - raw_printf(p->out, "PRAGMA writable_schema=ON;\n"); - p->writableSchema = 1; - } - zIns = sqlite3_mprintf( - "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)" - "VALUES('table','%q','%q',0,'%q');", - zTable, zTable, zSql); - utf8_printf(p->out, "%s\n", zIns); - sqlite3_free(zIns); - return 0; - }else{ - printSchemaLine(p->out, zSql, ";\n"); - } - - if( strcmp(zType, "table")==0 ){ - ShellText sSelect; - ShellText sTable; - char **azCol; - int i; - char *savedDestTable; - int savedMode; + int rc; + const char *zTable; + const char *zType; + const char *zSql; + ShellState *p = (ShellState *)pArg; + int dataOnly; + int noSys; + + UNUSED_PARAMETER(azNotUsed); + if( nArg!=3 || azArg==0 ) return 0; + zTable = azArg[0]; + zType = azArg[1]; + zSql = azArg[2]; + dataOnly = (p->shellFlgs & SHFLG_DumpDataOnly)!=0; + noSys = (p->shellFlgs & SHFLG_DumpNoSys)!=0; + + if( strcmp(zTable, "sqlite_sequence")==0 && !noSys ){ + if( !dataOnly ) raw_printf(p->out, "DELETE FROM sqlite_sequence;\n"); + }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 && !noSys ){ + if( !dataOnly ) raw_printf(p->out, "ANALYZE sqlite_schema;\n"); + }else if( strncmp(zTable, "sqlite_", 7)==0 ){ + return 0; + }else if( dataOnly ){ + /* no-op */ + }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){ + char *zIns; + if( !p->writableSchema ){ + raw_printf(p->out, "PRAGMA writable_schema=ON;\n"); + p->writableSchema = 1; + } + zIns = sqlite3_mprintf( + "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)" + "VALUES('table','%q','%q',0,'%q');", + zTable, zTable, zSql); + utf8_printf(p->out, "%s\n", zIns); + sqlite3_free(zIns); + return 0; + }else{ + printSchemaLine(p->out, zSql, ";\n"); + } + + if( strcmp(zType, "table")==0 ){ + ShellText sSelect; + ShellText sTable; + char **azCol; + int i; + char *savedDestTable; + int savedMode; - azCol = tableColumnList(p, zTable); - if( azCol==0 ){ - p->nErr++; - return 0; - } + azCol = tableColumnList(p, zTable); + if( azCol==0 ){ + p->nErr++; + return 0; + } - /* Always quote the table name, even if it appears to be pure ascii, + /* Always quote the table name, even if it appears to be pure ascii, ** in case it is a keyword. Ex: INSERT INTO "table" ... */ - initText(&sTable); - appendText(&sTable, zTable, quoteChar(zTable)); - /* If preserving the rowid, add a column list after the table name. + initText(&sTable); + appendText(&sTable, zTable, quoteChar(zTable)); + /* If preserving the rowid, add a column list after the table name. ** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)" ** instead of the usual "INSERT INTO tab VALUES(...)". */ - if( azCol[0] ){ - appendText(&sTable, "(", 0); - appendText(&sTable, azCol[0], 0); - for(i=1; azCol[i]; i++){ - appendText(&sTable, ",", 0); - appendText(&sTable, azCol[i], quoteChar(azCol[i])); - } - appendText(&sTable, ")", 0); - } - - /* Build an appropriate SELECT statement */ - initText(&sSelect); - appendText(&sSelect, "SELECT ", 0); - if( azCol[0] ){ - appendText(&sSelect, azCol[0], 0); - appendText(&sSelect, ",", 0); - } - for(i=1; azCol[i]; i++){ - appendText(&sSelect, azCol[i], quoteChar(azCol[i])); - if( azCol[i+1] ){ - appendText(&sSelect, ",", 0); - } - } - freeColumnList(azCol); - appendText(&sSelect, " FROM ", 0); - appendText(&sSelect, zTable, quoteChar(zTable)); - - savedDestTable = p->zDestTable; - savedMode = p->mode; - p->zDestTable = sTable.z; - p->mode = p->cMode = MODE_Insert; - rc = shell_exec(p, sSelect.z, 0); - if( (rc&0xff)==SQLITE_CORRUPT ){ - raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); - toggleSelectOrder(p->db); - shell_exec(p, sSelect.z, 0); - toggleSelectOrder(p->db); - } - p->zDestTable = savedDestTable; - p->mode = savedMode; - freeText(&sTable); - freeText(&sSelect); - if( rc ) p->nErr++; + if( azCol[0] ){ + appendText(&sTable, "(", 0); + appendText(&sTable, azCol[0], 0); + for(i=1; azCol[i]; i++){ + appendText(&sTable, ",", 0); + appendText(&sTable, azCol[i], quoteChar(azCol[i])); + } + appendText(&sTable, ")", 0); + } + + /* Build an appropriate SELECT statement */ + initText(&sSelect); + appendText(&sSelect, "SELECT ", 0); + if( azCol[0] ){ + appendText(&sSelect, azCol[0], 0); + appendText(&sSelect, ",", 0); } - return 0; + for(i=1; azCol[i]; i++){ + appendText(&sSelect, azCol[i], quoteChar(azCol[i])); + if( azCol[i+1] ){ + appendText(&sSelect, ",", 0); + } + } + freeColumnList(azCol); + appendText(&sSelect, " FROM ", 0); + appendText(&sSelect, zTable, quoteChar(zTable)); + + savedDestTable = p->zDestTable; + savedMode = p->mode; + p->zDestTable = sTable.z; + p->mode = p->cMode = MODE_Insert; + rc = shell_exec(p, sSelect.z, 0); + if( (rc&0xff)==SQLITE_CORRUPT ){ + raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); + toggleSelectOrder(p->db); + shell_exec(p, sSelect.z, 0); + toggleSelectOrder(p->db); + } + p->zDestTable = savedDestTable; + p->mode = savedMode; + freeText(&sTable); + freeText(&sSelect); + if( rc ) p->nErr++; + } + return 0; } /* @@ -14974,34 +14974,34 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){ ** "ORDER BY rowid DESC" to the end. */ static int run_schema_dump_query( - ShellState *p, - const char *zQuery + ShellState *p, + const char *zQuery ){ - int rc; - char *zErr = 0; - rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); - if( rc==SQLITE_CORRUPT ){ - char *zQ2; - int len = strlen30(zQuery); - raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); - if( zErr ){ - utf8_printf(p->out, "/****** %s ******/\n", zErr); - sqlite3_free(zErr); - zErr = 0; - } - zQ2 = malloc( len+100 ); - if( zQ2==0 ) return rc; - sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery); - rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); - if( rc ){ - utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr); - }else{ - rc = SQLITE_CORRUPT; - } - sqlite3_free(zErr); - free(zQ2); + int rc; + char *zErr = 0; + rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr); + if( rc==SQLITE_CORRUPT ){ + char *zQ2; + int len = strlen30(zQuery); + raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n"); + if( zErr ){ + utf8_printf(p->out, "/****** %s ******/\n", zErr); + sqlite3_free(zErr); + zErr = 0; + } + zQ2 = malloc( len+100 ); + if( zQ2==0 ) return rc; + sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery); + rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr); + if( rc ){ + utf8_printf(p->out, "/****** ERROR: %s ******/\n", zErr); + }else{ + rc = SQLITE_CORRUPT; } - return rc; + sqlite3_free(zErr); + free(zQ2); + } + return rc; } /* @@ -15015,249 +15015,249 @@ static int run_schema_dump_query( */ static const char *(azHelp[]) = { #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) - ".archive ... Manage SQL archives", - " Each command must have exactly one of the following options:", - " -c, --create Create a new archive", - " -u, --update Add or update files with changed mtime", - " -i, --insert Like -u but always add even if unchanged", - " -r, --remove Remove files from archive", - " -t, --list List contents of archive", - " -x, --extract Extract files from archive", - " Optional arguments:", - " -v, --verbose Print each filename as it is processed", - " -f FILE, --file FILE Use archive FILE (default is current db)", - " -a FILE, --append FILE Open FILE using the apndvfs VFS", - " -C DIR, --directory DIR Read/extract files from directory DIR", - " -g, --glob Use glob matching for names in archive", - " -n, --dryrun Show the SQL that would have occurred", - " Examples:", - " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar", - " .ar -tf ARCHIVE # List members of ARCHIVE", - " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE", - " See also:", - " http://sqlite.org/cli.html#sqlite_archive_support", + ".archive ... Manage SQL archives", + " Each command must have exactly one of the following options:", + " -c, --create Create a new archive", + " -u, --update Add or update files with changed mtime", + " -i, --insert Like -u but always add even if unchanged", + " -r, --remove Remove files from archive", + " -t, --list List contents of archive", + " -x, --extract Extract files from archive", + " Optional arguments:", + " -v, --verbose Print each filename as it is processed", + " -f FILE, --file FILE Use archive FILE (default is current db)", + " -a FILE, --append FILE Open FILE using the apndvfs VFS", + " -C DIR, --directory DIR Read/extract files from directory DIR", + " -g, --glob Use glob matching for names in archive", + " -n, --dryrun Show the SQL that would have occurred", + " Examples:", + " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar", + " .ar -tf ARCHIVE # List members of ARCHIVE", + " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE", + " See also:", + " http://sqlite.org/cli.html#sqlite_archive_support", #endif #ifndef SQLITE_OMIT_AUTHORIZATION - ".auth ON|OFF Show authorizer callbacks", + ".auth ON|OFF Show authorizer callbacks", #endif - ".backup ?DB? FILE Backup DB (default \"main\") to FILE", - " --append Use the appendvfs", - " --async Write to FILE without journal and fsync()", - ".bail on|off Stop after hitting an error. Default OFF", - ".binary on|off Turn binary output on or off. Default OFF", - ".cd DIRECTORY Change the working directory to DIRECTORY", - ".changes on|off Show number of rows changed by SQL", - ".check GLOB Fail if output since .testcase does not match", - ".clone NEWDB Clone data into NEWDB from the existing database", - ".connection [close] [#] Open or close an auxiliary database connection", - ".databases List names and files of attached databases", - ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", - ".dbinfo ?DB? Show status information about the database", - ".dump ?OBJECTS? Render database content as SQL", - " Options:", - " --data-only Output only INSERT statements", - " --newlines Allow unescaped newline characters in output", - " --nosys Omit system tables (ex: \"sqlite_stat1\")", - " --preserve-rowids Include ROWID values in the output", - " OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump", - " Additional LIKE patterns can be given in subsequent arguments", - ".echo on|off Turn command echo on or off", - ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", - " Other Modes:", + ".backup ?DB? FILE Backup DB (default \"main\") to FILE", + " --append Use the appendvfs", + " --async Write to FILE without journal and fsync()", + ".bail on|off Stop after hitting an error. Default OFF", + ".binary on|off Turn binary output on or off. Default OFF", + ".cd DIRECTORY Change the working directory to DIRECTORY", + ".changes on|off Show number of rows changed by SQL", + ".check GLOB Fail if output since .testcase does not match", + ".clone NEWDB Clone data into NEWDB from the existing database", + ".connection [close] [#] Open or close an auxiliary database connection", + ".databases List names and files of attached databases", + ".dbconfig ?op? ?val? List or change sqlite3_db_config() options", + ".dbinfo ?DB? Show status information about the database", + ".dump ?OBJECTS? Render database content as SQL", + " Options:", + " --data-only Output only INSERT statements", + " --newlines Allow unescaped newline characters in output", + " --nosys Omit system tables (ex: \"sqlite_stat1\")", + " --preserve-rowids Include ROWID values in the output", + " OBJECTS is a LIKE pattern for tables, indexes, triggers or views to dump", + " Additional LIKE patterns can be given in subsequent arguments", + ".echo on|off Turn command echo on or off", + ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN", + " Other Modes:", #ifdef SQLITE_DEBUG - " test Show raw EXPLAIN QUERY PLAN output", - " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"", + " test Show raw EXPLAIN QUERY PLAN output", + " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"", #endif - " trigger Like \"full\" but also show trigger bytecode", - ".excel Display the output of next command in spreadsheet", - " --bom Put a UTF8 byte-order mark on intermediate file", - ".exit ?CODE? Exit this program with return-code CODE", - ".expert EXPERIMENTAL. Suggest indexes for queries", - ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto", - ".filectrl CMD ... Run various sqlite3_file_control() operations", - " --schema SCHEMA Use SCHEMA instead of \"main\"", - " --help Show CMD details", - ".fullschema ?--indent? Show schema and the content of sqlite_stat tables", - ".headers on|off Turn display of headers on or off", - ".help ?-all? ?PATTERN? Show help text for PATTERN", - ".import FILE TABLE Import data from FILE into TABLE", - " Options:", - " --ascii Use \\037 and \\036 as column and row separators", - " --csv Use , and \\n as column and row separators", - " --skip N Skip the first N rows of input", - " -v \"Verbose\" - increase auxiliary output", - " Notes:", - " * If TABLE does not exist, it is created. The first row of input", - " determines the column names.", - " * If neither --csv or --ascii are used, the input mode is derived", - " from the \".mode\" output mode", - " * If FILE begins with \"|\" then it is a command that generates the", - " input text.", + " trigger Like \"full\" but also show trigger bytecode", + ".excel Display the output of next command in spreadsheet", + " --bom Put a UTF8 byte-order mark on intermediate file", + ".exit ?CODE? Exit this program with return-code CODE", + ".expert EXPERIMENTAL. Suggest indexes for queries", + ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto", + ".filectrl CMD ... Run various sqlite3_file_control() operations", + " --schema SCHEMA Use SCHEMA instead of \"main\"", + " --help Show CMD details", + ".fullschema ?--indent? Show schema and the content of sqlite_stat tables", + ".headers on|off Turn display of headers on or off", + ".help ?-all? ?PATTERN? Show help text for PATTERN", + ".import FILE TABLE Import data from FILE into TABLE", + " Options:", + " --ascii Use \\037 and \\036 as column and row separators", + " --csv Use , and \\n as column and row separators", + " --skip N Skip the first N rows of input", + " -v \"Verbose\" - increase auxiliary output", + " Notes:", + " * If TABLE does not exist, it is created. The first row of input", + " determines the column names.", + " * If neither --csv or --ascii are used, the input mode is derived", + " from the \".mode\" output mode", + " * If FILE begins with \"|\" then it is a command that generates the", + " input text.", #ifndef SQLITE_OMIT_TEST_CONTROL - ".imposter INDEX TABLE Create imposter table TABLE on index INDEX", + ".imposter INDEX TABLE Create imposter table TABLE on index INDEX", #endif - ".indexes ?TABLE? Show names of indexes", - " If TABLE is specified, only show indexes for", - " tables matching TABLE using the LIKE operator.", + ".indexes ?TABLE? Show names of indexes", + " If TABLE is specified, only show indexes for", + " tables matching TABLE using the LIKE operator.", #ifdef SQLITE_ENABLE_IOTRACE - ".iotrace FILE Enable I/O diagnostic logging to FILE", + ".iotrace FILE Enable I/O diagnostic logging to FILE", #endif - ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT", - ".lint OPTIONS Report potential schema issues.", - " Options:", - " fkey-indexes Find missing foreign key indexes", + ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT", + ".lint OPTIONS Report potential schema issues.", + " Options:", + " fkey-indexes Find missing foreign key indexes", #ifndef SQLITE_OMIT_LOAD_EXTENSION - ".load FILE ?ENTRY? Load an extension library", + ".load FILE ?ENTRY? Load an extension library", #endif - ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", - ".mode MODE ?TABLE? Set output mode", - " MODE is one of:", - " ascii Columns/rows delimited by 0x1F and 0x1E", - " box Tables using unicode box-drawing characters", - " csv Comma-separated values", - " column Output in columns. (See .width)", - " html HTML
"); + output_html_string(p->out, azCol[i]); + raw_printf(p->out,"
"); + output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue); + raw_printf(p->out,"
"); - output_html_string(p->out, azCol[i]); - raw_printf(p->out,"
"); - output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue); - raw_printf(p->out,"
code", - " insert SQL insert statements for TABLE", - " json Results in a JSON array", - " line One value per line", - " list Values delimited by \"|\"", - " markdown Markdown table format", - " quote Escape answers as for SQL", - " table ASCII-art table", - " tabs Tab-separated values", - " tcl TCL list elements", - ".nonce STRING Disable safe mode for one command if the nonce matches", - ".nullvalue STRING Use STRING in place of NULL values", - ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE", - " If FILE begins with '|' then open as a pipe", - " --bom Put a UTF8 byte-order mark at the beginning", - " -e Send output to the system text editor", - " -x Send output as CSV to a spreadsheet (same as \".excel\")", + ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", + ".mode MODE ?TABLE? Set output mode", + " MODE is one of:", + " ascii Columns/rows delimited by 0x1F and 0x1E", + " box Tables using unicode box-drawing characters", + " csv Comma-separated values", + " column Output in columns. (See .width)", + " html HTML
code", + " insert SQL insert statements for TABLE", + " json Results in a JSON array", + " line One value per line", + " list Values delimited by \"|\"", + " markdown Markdown table format", + " quote Escape answers as for SQL", + " table ASCII-art table", + " tabs Tab-separated values", + " tcl TCL list elements", + ".nonce STRING Disable safe mode for one command if the nonce matches", + ".nullvalue STRING Use STRING in place of NULL values", + ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE", + " If FILE begins with '|' then open as a pipe", + " --bom Put a UTF8 byte-order mark at the beginning", + " -e Send output to the system text editor", + " -x Send output as CSV to a spreadsheet (same as \".excel\")", #ifdef SQLITE_DEBUG - ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation", -#endif - ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", - " Options:", - " --append Use appendvfs to append database to the end of FILE", + ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation", +#endif + ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", + " Options:", + " --append Use appendvfs to append database to the end of FILE", #ifndef SQLITE_OMIT_DESERIALIZE - " --deserialize Load into memory using sqlite3_deserialize()", - " --hexdb Load the output of \"dbtotxt\" as an in-memory db", - " --maxsize N Maximum size for --hexdb or --deserialized database", + " --deserialize Load into memory using sqlite3_deserialize()", + " --hexdb Load the output of \"dbtotxt\" as an in-memory db", + " --maxsize N Maximum size for --hexdb or --deserialized database", #endif - " --new Initialize FILE to an empty database", - " --nofollow Do not follow symbolic links", - " --readonly Open FILE readonly", - " --zip FILE is a ZIP archive", - ".output ?FILE? Send output to FILE or stdout if FILE is omitted", - " If FILE begins with '|' then open it as a pipe.", - " Options:", - " --bom Prefix output with a UTF8 byte-order mark", - " -e Send output to the system text editor", - " -x Send output as CSV to a spreadsheet", - ".parameter CMD ... Manage SQL parameter bindings", - " clear Erase all bindings", - " init Initialize the TEMP table that holds bindings", - " list List the current parameter bindings", - " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE", - " PARAMETER should start with one of: $ : @ ?", - " unset PARAMETER Remove PARAMETER from the binding table", - ".print STRING... Print literal STRING", + " --new Initialize FILE to an empty database", + " --nofollow Do not follow symbolic links", + " --readonly Open FILE readonly", + " --zip FILE is a ZIP archive", + ".output ?FILE? Send output to FILE or stdout if FILE is omitted", + " If FILE begins with '|' then open it as a pipe.", + " Options:", + " --bom Prefix output with a UTF8 byte-order mark", + " -e Send output to the system text editor", + " -x Send output as CSV to a spreadsheet", + ".parameter CMD ... Manage SQL parameter bindings", + " clear Erase all bindings", + " init Initialize the TEMP table that holds bindings", + " list List the current parameter bindings", + " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE", + " PARAMETER should start with one of: $ : @ ?", + " unset PARAMETER Remove PARAMETER from the binding table", + ".print STRING... Print literal STRING", #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - ".progress N Invoke progress handler after every N opcodes", - " --limit N Interrupt after N progress callbacks", - " --once Do no more than one progress interrupt", - " --quiet|-q No output except at interrupts", - " --reset Reset the count for each input and interrupt", + ".progress N Invoke progress handler after every N opcodes", + " --limit N Interrupt after N progress callbacks", + " --once Do no more than one progress interrupt", + " --quiet|-q No output except at interrupts", + " --reset Reset the count for each input and interrupt", #endif - ".prompt MAIN CONTINUE Replace the standard prompts", - ".quit Exit this program", - ".read FILE Read input from FILE", + ".prompt MAIN CONTINUE Replace the standard prompts", + ".quit Exit this program", + ".read FILE Read input from FILE", #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) - ".recover Recover as much data as possible from corrupt db.", - " --freelist-corrupt Assume the freelist is corrupt", - " --recovery-db NAME Store recovery metadata in database file NAME", - " --lost-and-found TABLE Alternative name for the lost-and-found table", - " --no-rowids Do not attempt to recover rowid values", - " that are not also INTEGER PRIMARY KEYs", + ".recover Recover as much data as possible from corrupt db.", + " --freelist-corrupt Assume the freelist is corrupt", + " --recovery-db NAME Store recovery metadata in database file NAME", + " --lost-and-found TABLE Alternative name for the lost-and-found table", + " --no-rowids Do not attempt to recover rowid values", + " that are not also INTEGER PRIMARY KEYs", #endif - ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", - ".save FILE Write in-memory database into FILE", - ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", - ".schema ?PATTERN? Show the CREATE statements matching PATTERN", - " Options:", - " --indent Try to pretty-print the schema", - " --nosys Omit objects whose names start with \"sqlite_\"", - ".selftest ?OPTIONS? Run tests defined in the SELFTEST table", - " Options:", - " --init Create a new SELFTEST table", - " -v Verbose output", - ".separator COL ?ROW? Change the column and row separators", + ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE", + ".save FILE Write in-memory database into FILE", + ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off", + ".schema ?PATTERN? Show the CREATE statements matching PATTERN", + " Options:", + " --indent Try to pretty-print the schema", + " --nosys Omit objects whose names start with \"sqlite_\"", + ".selftest ?OPTIONS? Run tests defined in the SELFTEST table", + " Options:", + " --init Create a new SELFTEST table", + " -v Verbose output", + ".separator COL ?ROW? Change the column and row separators", #if defined(SQLITE_ENABLE_SESSION) - ".session ?NAME? CMD ... Create or control sessions", - " Subcommands:", - " attach TABLE Attach TABLE", - " changeset FILE Write a changeset into FILE", - " close Close one session", - " enable ?BOOLEAN? Set or query the enable bit", - " filter GLOB... Reject tables matching GLOBs", - " indirect ?BOOLEAN? Mark or query the indirect status", - " isempty Query whether the session is empty", - " list List currently open session names", - " open DB NAME Open a new session on DB", - " patchset FILE Write a patchset into FILE", - " If ?NAME? is omitted, the first defined session is used.", + ".session ?NAME? CMD ... Create or control sessions", + " Subcommands:", + " attach TABLE Attach TABLE", + " changeset FILE Write a changeset into FILE", + " close Close one session", + " enable ?BOOLEAN? Set or query the enable bit", + " filter GLOB... Reject tables matching GLOBs", + " indirect ?BOOLEAN? Mark or query the indirect status", + " isempty Query whether the session is empty", + " list List currently open session names", + " open DB NAME Open a new session on DB", + " patchset FILE Write a patchset into FILE", + " If ?NAME? is omitted, the first defined session is used.", #endif - ".sha3sum ... Compute a SHA3 hash of database content", - " Options:", - " --schema Also hash the sqlite_schema table", - " --sha3-224 Use the sha3-224 algorithm", - " --sha3-256 Use the sha3-256 algorithm (default)", - " --sha3-384 Use the sha3-384 algorithm", - " --sha3-512 Use the sha3-512 algorithm", - " Any other argument is a LIKE pattern for tables to hash", + ".sha3sum ... Compute a SHA3 hash of database content", + " Options:", + " --schema Also hash the sqlite_schema table", + " --sha3-224 Use the sha3-224 algorithm", + " --sha3-256 Use the sha3-256 algorithm (default)", + " --sha3-384 Use the sha3-384 algorithm", + " --sha3-512 Use the sha3-512 algorithm", + " Any other argument is a LIKE pattern for tables to hash", #ifndef SQLITE_NOHAVE_SYSTEM - ".shell CMD ARGS... Run CMD ARGS... in a system shell", + ".shell CMD ARGS... Run CMD ARGS... in a system shell", #endif - ".show Show the current values for various settings", - ".stats ?ARG? Show stats or turn stats on or off", - " off Turn off automatic stat display", - " on Turn on automatic stat display", - " stmt Show statement stats", - " vmstep Show the virtual machine step count only", + ".show Show the current values for various settings", + ".stats ?ARG? Show stats or turn stats on or off", + " off Turn off automatic stat display", + " on Turn on automatic stat display", + " stmt Show statement stats", + " vmstep Show the virtual machine step count only", #ifndef SQLITE_NOHAVE_SYSTEM - ".system CMD ARGS... Run CMD ARGS... in a system shell", + ".system CMD ARGS... Run CMD ARGS... in a system shell", #endif - ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", - ".testcase NAME Begin redirecting output to 'testcase-out.txt'", - ".testctrl CMD ... Run various sqlite3_test_control() operations", - " Run \".testctrl\" with no arguments for details", - ".timeout MS Try opening locked tables for MS milliseconds", - ".timer on|off Turn SQL timer on or off", + ".tables ?TABLE? List names of tables matching LIKE pattern TABLE", + ".testcase NAME Begin redirecting output to 'testcase-out.txt'", + ".testctrl CMD ... Run various sqlite3_test_control() operations", + " Run \".testctrl\" with no arguments for details", + ".timeout MS Try opening locked tables for MS milliseconds", + ".timer on|off Turn SQL timer on or off", #ifndef SQLITE_OMIT_TRACE - ".trace ?OPTIONS? Output each SQL statement as it is run", - " FILE Send output to FILE", - " stdout Send output to stdout", - " stderr Send output to stderr", - " off Disable tracing", - " --expanded Expand query parameters", + ".trace ?OPTIONS? Output each SQL statement as it is run", + " FILE Send output to FILE", + " stdout Send output to stdout", + " stderr Send output to stderr", + " off Disable tracing", + " --expanded Expand query parameters", #ifdef SQLITE_ENABLE_NORMALIZE - " --normalized Normal the SQL statements", + " --normalized Normal the SQL statements", #endif - " --plain Show SQL as it is input", - " --stmt Trace statement execution (SQLITE_TRACE_STMT)", - " --profile Profile statements (SQLITE_TRACE_PROFILE)", - " --row Trace each row (SQLITE_TRACE_ROW)", - " --close Trace connection close (SQLITE_TRACE_CLOSE)", + " --plain Show SQL as it is input", + " --stmt Trace statement execution (SQLITE_TRACE_STMT)", + " --profile Profile statements (SQLITE_TRACE_PROFILE)", + " --row Trace each row (SQLITE_TRACE_ROW)", + " --close Trace connection close (SQLITE_TRACE_CLOSE)", #endif /* SQLITE_OMIT_TRACE */ #ifdef SQLITE_DEBUG - ".unmodule NAME ... Unregister virtual table modules", - " --allexcept Unregister everything except those named", + ".unmodule NAME ... Unregister virtual table modules", + " --allexcept Unregister everything except those named", #endif - ".vfsinfo ?AUX? Information about the top-level VFS", - ".vfslist List all available VFSes", - ".vfsname ?AUX? Print the name of the VFS stack", - ".width NUM1 NUM2 ... Set minimum column widths for columnar output", - " Negative values right-justify", + ".vfsinfo ?AUX? Information about the top-level VFS", + ".vfslist List all available VFSes", + ".vfsname ?AUX? Print the name of the VFS stack", + ".width NUM1 NUM2 ... Set minimum column widths for columnar output", + " Negative values right-justify", }; /* @@ -15270,64 +15270,64 @@ static const char *(azHelp[]) = { ** Return the number of matches. */ static int showHelp(FILE *out, const char *zPattern){ - int i = 0; - int j = 0; - int n = 0; - char *zPat; - if( zPattern==0 - || zPattern[0]=='0' - || strcmp(zPattern,"-a")==0 - || strcmp(zPattern,"-all")==0 - || strcmp(zPattern,"--all")==0 - ){ - /* Show all commands, but only one line per command */ - if( zPattern==0 ) zPattern = ""; - for(i=0; ip); - sqlite3_free(pSession->zName); - for(i=0; inFilter; i++){ - sqlite3_free(pSession->azFilter[i]); - } - sqlite3_free(pSession->azFilter); - memset(pSession, 0, sizeof(OpenSession)); + int i; + sqlite3session_delete(pSession->p); + sqlite3_free(pSession->zName); + for(i=0; inFilter; i++){ + sqlite3_free(pSession->azFilter[i]); + } + sqlite3_free(pSession->azFilter); + memset(pSession, 0, sizeof(OpenSession)); } #endif @@ -15392,12 +15392,12 @@ static void session_close(OpenSession *pSession){ */ #if defined(SQLITE_ENABLE_SESSION) static void session_close_all(ShellState *p, int i){ - int j; - struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i]; - for(j=0; jnSession; j++){ - session_close(&pAuxDb->aSession[j]); - } - pAuxDb->nSession = 0; + int j; + struct AuxDb *pAuxDb = i<0 ? p->pAuxDb : &p->aAuxDb[i]; + for(j=0; jnSession; j++){ + session_close(&pAuxDb->aSession[j]); + } + pAuxDb->nSession = 0; } #else # define session_close_all(X,Y) @@ -15409,12 +15409,12 @@ static void session_close_all(ShellState *p, int i){ */ #if defined(SQLITE_ENABLE_SESSION) static int session_filter(void *pCtx, const char *zTab){ - OpenSession *pSession = (OpenSession*)pCtx; - int i; - for(i=0; inFilter; i++){ - if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0; - } - return 1; + OpenSession *pSession = (OpenSession*)pCtx; + int i; + for(i=0; inFilter; i++){ + if( sqlite3_strglob(pSession->azFilter[i], zTab)==0 ) return 0; + } + return 1; } #endif @@ -15428,38 +15428,38 @@ static int session_filter(void *pCtx, const char *zTab){ ** the type cannot be determined from content. */ int deduceDatabaseType(const char *zName, int dfltZip){ - FILE *f = fopen(zName, "rb"); - size_t n; - int rc = SHELL_OPEN_UNSPEC; - char zBuf[100]; - if( f==0 ){ - if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ - return SHELL_OPEN_ZIPFILE; - }else{ - return SHELL_OPEN_NORMAL; - } - } - n = fread(zBuf, 16, 1, f); - if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){ - fclose(f); - return SHELL_OPEN_NORMAL; - } - fseek(f, -25, SEEK_END); - n = fread(zBuf, 25, 1, f); - if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){ - rc = SHELL_OPEN_APPENDVFS; + FILE *f = fopen(zName, "rb"); + size_t n; + int rc = SHELL_OPEN_UNSPEC; + char zBuf[100]; + if( f==0 ){ + if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ + return SHELL_OPEN_ZIPFILE; }else{ - fseek(f, -22, SEEK_END); - n = fread(zBuf, 22, 1, f); - if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05 - && zBuf[3]==0x06 ){ - rc = SHELL_OPEN_ZIPFILE; - }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ - rc = SHELL_OPEN_ZIPFILE; - } + return SHELL_OPEN_NORMAL; } + } + n = fread(zBuf, 16, 1, f); + if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){ fclose(f); - return rc; + return SHELL_OPEN_NORMAL; + } + fseek(f, -25, SEEK_END); + n = fread(zBuf, 25, 1, f); + if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){ + rc = SHELL_OPEN_APPENDVFS; + }else{ + fseek(f, -22, SEEK_END); + n = fread(zBuf, 22, 1, f); + if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05 + && zBuf[3]==0x06 ){ + rc = SHELL_OPEN_ZIPFILE; + }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ + rc = SHELL_OPEN_ZIPFILE; + } + } + fclose(f); + return rc; } #ifndef SQLITE_OMIT_DESERIALIZE @@ -15469,88 +15469,88 @@ int deduceDatabaseType(const char *zName, int dfltZip){ ** If p->aAuxDb[].zDbFilename is 0, then read from standard input. */ static unsigned char *readHexDb(ShellState *p, int *pnData){ - unsigned char *a = 0; - int nLine; - int n = 0; - int pgsz = 0; - int iOffset = 0; - int j, k; - int rc; - FILE *in; - const char *zDbFilename = p->pAuxDb->zDbFilename; - unsigned int x[16]; - char zLine[1000]; - if( zDbFilename ){ - in = fopen(zDbFilename, "r"); - if( in==0 ){ - utf8_printf(stderr, "cannot open \"%s\" for reading\n", zDbFilename); - return 0; - } - nLine = 0; - }else{ - in = p->in; - nLine = p->lineno; - if( in==0 ) in = stdin; - } - *pnData = 0; - nLine++; - if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error; - rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz); - if( rc!=2 ) goto readHexDb_error; - if( n<0 ) goto readHexDb_error; - if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error; - n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ - a = sqlite3_malloc( n ? n : 1 ); - if( a==0 ){ - utf8_printf(stderr, "Out of memory!\n"); - goto readHexDb_error; - } - memset(a, 0, n); - if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ - utf8_printf(stderr, "invalid pagesize\n"); - goto readHexDb_error; - } - for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){ - rc = sscanf(zLine, "| page %d offset %d", &j, &k); - if( rc==2 ){ - iOffset = k; - continue; - } - if( strncmp(zLine, "| end ", 6)==0 ){ - break; - } - rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", - &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], - &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); - if( rc==17 ){ - k = iOffset+j; - if( k+16<=n && k>=0 ){ - int ii; - for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; - } - } - } - *pnData = n; - if( in!=p->in ){ - fclose(in); - }else{ - p->lineno = nLine; - } - return a; + unsigned char *a = 0; + int nLine; + int n = 0; + int pgsz = 0; + int iOffset = 0; + int j, k; + int rc; + FILE *in; + const char *zDbFilename = p->pAuxDb->zDbFilename; + unsigned int x[16]; + char zLine[1000]; + if( zDbFilename ){ + in = fopen(zDbFilename, "r"); + if( in==0 ){ + utf8_printf(stderr, "cannot open \"%s\" for reading\n", zDbFilename); + return 0; + } + nLine = 0; + }else{ + in = p->in; + nLine = p->lineno; + if( in==0 ) in = stdin; + } + *pnData = 0; + nLine++; + if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error; + rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz); + if( rc!=2 ) goto readHexDb_error; + if( n<0 ) goto readHexDb_error; + if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error; + n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */ + a = sqlite3_malloc( n ? n : 1 ); + if( a==0 ){ + utf8_printf(stderr, "Out of memory!\n"); + goto readHexDb_error; + } + memset(a, 0, n); + if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){ + utf8_printf(stderr, "invalid pagesize\n"); + goto readHexDb_error; + } + for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){ + rc = sscanf(zLine, "| page %d offset %d", &j, &k); + if( rc==2 ){ + iOffset = k; + continue; + } + if( strncmp(zLine, "| end ", 6)==0 ){ + break; + } + rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], + &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]); + if( rc==17 ){ + k = iOffset+j; + if( k+16<=n && k>=0 ){ + int ii; + for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff; + } + } + } + *pnData = n; + if( in!=p->in ){ + fclose(in); + }else{ + p->lineno = nLine; + } + return a; readHexDb_error: - if( in!=p->in ){ - fclose(in); - }else{ - while( fgets(zLine, sizeof(zLine), p->in)!=0 ){ - nLine++; - if(strncmp(zLine, "| end ", 6)==0 ) break; - } - p->lineno = nLine; + if( in!=p->in ){ + fclose(in); + }else{ + while( fgets(zLine, sizeof(zLine), p->in)!=0 ){ + nLine++; + if(strncmp(zLine, "| end ", 6)==0 ) break; } - sqlite3_free(a); - utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine); - return 0; + p->lineno = nLine; + } + sqlite3_free(a); + utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine); + return 0; } #endif /* SQLITE_OMIT_DESERIALIZE */ @@ -15561,27 +15561,27 @@ readHexDb_error: ** offset (4*) of the blob. */ static void shellInt32( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - const unsigned char *pBlob; - int nBlob; - int iInt; + const unsigned char *pBlob; + int nBlob; + int iInt; - UNUSED_PARAMETER(argc); - nBlob = sqlite3_value_bytes(argv[0]); - pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]); - iInt = sqlite3_value_int(argv[1]); + UNUSED_PARAMETER(argc); + nBlob = sqlite3_value_bytes(argv[0]); + pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]); + iInt = sqlite3_value_int(argv[1]); - if( iInt>=0 && (iInt+1)*4<=nBlob ){ - const unsigned char *a = &pBlob[iInt*4]; - sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24) - + ((sqlite3_int64)a[1]<<16) - + ((sqlite3_int64)a[2]<< 8) - + ((sqlite3_int64)a[3]<< 0); - sqlite3_result_int64(context, iVal); - } + if( iInt>=0 && (iInt+1)*4<=nBlob ){ + const unsigned char *a = &pBlob[iInt*4]; + sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24) + + ((sqlite3_int64)a[1]<<16) + + ((sqlite3_int64)a[2]<< 8) + + ((sqlite3_int64)a[3]<< 0); + sqlite3_result_int64(context, iVal); + } } /* @@ -15589,36 +15589,36 @@ static void shellInt32( ** using "..." with internal double-quote characters doubled. */ static void shellIdQuote( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - const char *zName = (const char*)sqlite3_value_text(argv[0]); - UNUSED_PARAMETER(argc); - if( zName ){ - char *z = sqlite3_mprintf("\"%w\"", zName); - sqlite3_result_text(context, z, -1, sqlite3_free); - } + const char *zName = (const char*)sqlite3_value_text(argv[0]); + UNUSED_PARAMETER(argc); + if( zName ){ + char *z = sqlite3_mprintf("\"%w\"", zName); + sqlite3_result_text(context, z, -1, sqlite3_free); + } } /* ** Scalar function "usleep(X)" invokes sqlite3_sleep(X) and returns X. */ static void shellUSleepFunc( - sqlite3_context *context, - int argcUnused, - sqlite3_value **argv + sqlite3_context *context, + int argcUnused, + sqlite3_value **argv ){ - int sleep = sqlite3_value_int(argv[0]); - (void)argcUnused; - sqlite3_sleep(sleep/1000); - sqlite3_result_int(context, sleep); + int sleep = sqlite3_value_int(argv[0]); + (void)argcUnused; + sqlite3_sleep(sleep/1000); + sqlite3_result_int(context, sleep); } /* ** Scalar function "shell_escape_crnl" used by the .recover command. ** The argument passed to this function is the output of built-in -** function quote(). If the first character of the input is "'", +** function quote(). If the first character of the input is "'", ** indicating that the value passed to quote() was a text value, ** then this function searches the input for "\n" and "\r" characters ** and adds a wrapper similar to the following: @@ -15629,81 +15629,81 @@ static void shellUSleepFunc( ** of the input is returned. */ static void shellEscapeCrnl( - sqlite3_context *context, - int argc, - sqlite3_value **argv + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ - const char *zText = (const char*)sqlite3_value_text(argv[0]); - UNUSED_PARAMETER(argc); - if( zText[0]=='\'' ){ - int nText = sqlite3_value_bytes(argv[0]); - int i; - char zBuf1[20]; - char zBuf2[20]; - const char *zNL = 0; - const char *zCR = 0; - int nCR = 0; - int nNL = 0; - - for(i=0; zText[i]; i++){ - if( zNL==0 && zText[i]=='\n' ){ - zNL = unused_string(zText, "\\n", "\\012", zBuf1); - nNL = (int)strlen(zNL); - } - if( zCR==0 && zText[i]=='\r' ){ - zCR = unused_string(zText, "\\r", "\\015", zBuf2); - nCR = (int)strlen(zCR); - } + const char *zText = (const char*)sqlite3_value_text(argv[0]); + UNUSED_PARAMETER(argc); + if( zText[0]=='\'' ){ + int nText = sqlite3_value_bytes(argv[0]); + int i; + char zBuf1[20]; + char zBuf2[20]; + const char *zNL = 0; + const char *zCR = 0; + int nCR = 0; + int nNL = 0; + + for(i=0; zText[i]; i++){ + if( zNL==0 && zText[i]=='\n' ){ + zNL = unused_string(zText, "\\n", "\\012", zBuf1); + nNL = (int)strlen(zNL); + } + if( zCR==0 && zText[i]=='\r' ){ + zCR = unused_string(zText, "\\r", "\\015", zBuf2); + nCR = (int)strlen(zCR); + } + } + + if( zNL || zCR ){ + int iOut = 0; + i64 nMax = (nNL > nCR) ? nNL : nCR; + i64 nAlloc = nMax * nText + (nMax+64)*2; + char *zOut = (char*)sqlite3_malloc64(nAlloc); + if( zOut==0 ){ + sqlite3_result_error_nomem(context); + return; + } + + if( zNL && zCR ){ + memcpy(&zOut[iOut], "replace(replace(", 16); + iOut += 16; + }else{ + memcpy(&zOut[iOut], "replace(", 8); + iOut += 8; + } + for(i=0; zText[i]; i++){ + if( zText[i]=='\n' ){ + memcpy(&zOut[iOut], zNL, nNL); + iOut += nNL; + }else if( zText[i]=='\r' ){ + memcpy(&zOut[iOut], zCR, nCR); + iOut += nCR; + }else{ + zOut[iOut] = zText[i]; + iOut++; } + } - if( zNL || zCR ){ - int iOut = 0; - i64 nMax = (nNL > nCR) ? nNL : nCR; - i64 nAlloc = nMax * nText + (nMax+64)*2; - char *zOut = (char*)sqlite3_malloc64(nAlloc); - if( zOut==0 ){ - sqlite3_result_error_nomem(context); - return; - } - - if( zNL && zCR ){ - memcpy(&zOut[iOut], "replace(replace(", 16); - iOut += 16; - }else{ - memcpy(&zOut[iOut], "replace(", 8); - iOut += 8; - } - for(i=0; zText[i]; i++){ - if( zText[i]=='\n' ){ - memcpy(&zOut[iOut], zNL, nNL); - iOut += nNL; - }else if( zText[i]=='\r' ){ - memcpy(&zOut[iOut], zCR, nCR); - iOut += nCR; - }else{ - zOut[iOut] = zText[i]; - iOut++; - } - } - - if( zNL ){ - memcpy(&zOut[iOut], ",'", 2); iOut += 2; - memcpy(&zOut[iOut], zNL, nNL); iOut += nNL; - memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12; - } - if( zCR ){ - memcpy(&zOut[iOut], ",'", 2); iOut += 2; - memcpy(&zOut[iOut], zCR, nCR); iOut += nCR; - memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12; - } + if( zNL ){ + memcpy(&zOut[iOut], ",'", 2); iOut += 2; + memcpy(&zOut[iOut], zNL, nNL); iOut += nNL; + memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12; + } + if( zCR ){ + memcpy(&zOut[iOut], ",'", 2); iOut += 2; + memcpy(&zOut[iOut], zCR, nCR); iOut += nCR; + memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12; + } - sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT); - sqlite3_free(zOut); - return; - } + sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT); + sqlite3_free(zOut); + return; } + } - sqlite3_result_value(context, argv[0]); + sqlite3_result_value(context, argv[0]); } /* Flags for open_db(). @@ -15724,137 +15724,137 @@ static void shellEscapeCrnl( ** the database fails to open, print an error message and exit. */ static void open_db(ShellState *p, int openFlags){ - if( p->db==0 ){ - const char *zDbFilename = p->pAuxDb->zDbFilename; - if( p->openMode==SHELL_OPEN_UNSPEC ){ - if( zDbFilename==0 || zDbFilename[0]==0 ){ - p->openMode = SHELL_OPEN_NORMAL; - }else{ - p->openMode = (u8)deduceDatabaseType(zDbFilename, - (openFlags & OPEN_DB_ZIPFILE)!=0); - } - } - switch( p->openMode ){ - case SHELL_OPEN_APPENDVFS: { - sqlite3_open_v2(zDbFilename, &p->db, - SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs"); - break; - } - case SHELL_OPEN_HEXDB: - case SHELL_OPEN_DESERIALIZE: { - sqlite3_open(0, &p->db); - break; - } - case SHELL_OPEN_ZIPFILE: { - sqlite3_open(":memory:", &p->db); - break; - } - case SHELL_OPEN_READONLY: { - sqlite3_open_v2(zDbFilename, &p->db, - SQLITE_OPEN_READONLY|p->openFlags, 0); - break; - } - case SHELL_OPEN_UNSPEC: - case SHELL_OPEN_NORMAL: { - sqlite3_open_v2(zDbFilename, &p->db, - SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0); - break; - } - } - globalDb = p->db; - if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ - utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", - zDbFilename, sqlite3_errmsg(p->db)); - if( openFlags & OPEN_DB_KEEPALIVE ){ - sqlite3_open(":memory:", &p->db); - return; - } - exit(1); - } + if( p->db==0 ){ + const char *zDbFilename = p->pAuxDb->zDbFilename; + if( p->openMode==SHELL_OPEN_UNSPEC ){ + if( zDbFilename==0 || zDbFilename[0]==0 ){ + p->openMode = SHELL_OPEN_NORMAL; + }else{ + p->openMode = (u8)deduceDatabaseType(zDbFilename, + (openFlags & OPEN_DB_ZIPFILE)!=0); + } + } + switch( p->openMode ){ + case SHELL_OPEN_APPENDVFS: { + sqlite3_open_v2(zDbFilename, &p->db, + SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs"); + break; + } + case SHELL_OPEN_HEXDB: + case SHELL_OPEN_DESERIALIZE: { + sqlite3_open(0, &p->db); + break; + } + case SHELL_OPEN_ZIPFILE: { + sqlite3_open(":memory:", &p->db); + break; + } + case SHELL_OPEN_READONLY: { + sqlite3_open_v2(zDbFilename, &p->db, + SQLITE_OPEN_READONLY|p->openFlags, 0); + break; + } + case SHELL_OPEN_UNSPEC: + case SHELL_OPEN_NORMAL: { + sqlite3_open_v2(zDbFilename, &p->db, + SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0); + break; + } + } + globalDb = p->db; + if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ + utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", + zDbFilename, sqlite3_errmsg(p->db)); + if( openFlags & OPEN_DB_KEEPALIVE ){ + sqlite3_open(":memory:", &p->db); + return; + } + exit(1); + } #ifndef SQLITE_OMIT_LOAD_EXTENSION - sqlite3_enable_load_extension(p->db, 1); + sqlite3_enable_load_extension(p->db, 1); #endif - sqlite3_fileio_init(p->db, 0, 0); - sqlite3_shathree_init(p->db, 0, 0); - sqlite3_completion_init(p->db, 0, 0); - sqlite3_uint_init(p->db, 0, 0); - sqlite3_decimal_init(p->db, 0, 0); - sqlite3_regexp_init(p->db, 0, 0); - sqlite3_ieee_init(p->db, 0, 0); - sqlite3_series_init(p->db, 0, 0); + sqlite3_fileio_init(p->db, 0, 0); + sqlite3_shathree_init(p->db, 0, 0); + sqlite3_completion_init(p->db, 0, 0); + sqlite3_uint_init(p->db, 0, 0); + sqlite3_decimal_init(p->db, 0, 0); + sqlite3_regexp_init(p->db, 0, 0); + sqlite3_ieee_init(p->db, 0, 0); + sqlite3_series_init(p->db, 0, 0); #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) - sqlite3_dbdata_init(p->db, 0, 0); + sqlite3_dbdata_init(p->db, 0, 0); #endif #ifdef SQLITE_HAVE_ZLIB - sqlite3_zipfile_init(p->db, 0, 0); - sqlite3_sqlar_init(p->db, 0, 0); + sqlite3_zipfile_init(p->db, 0, 0); + sqlite3_sqlar_init(p->db, 0, 0); #endif - sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, - shellAddSchemaName, 0, 0); - sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, - shellModuleSchema, 0, 0); - sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, - shellPutsFunc, 0, 0); - sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0, - shellEscapeCrnl, 0, 0); - sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0, - shellInt32, 0, 0); - sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0, - shellIdQuote, 0, 0); - sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0, - shellUSleepFunc, 0, 0); + sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, + shellAddSchemaName, 0, 0); + sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, + shellModuleSchema, 0, 0); + sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, + shellPutsFunc, 0, 0); + sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0, + shellEscapeCrnl, 0, 0); + sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0, + shellInt32, 0, 0); + sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0, + shellIdQuote, 0, 0); + sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0, + shellUSleepFunc, 0, 0); #ifndef SQLITE_NOHAVE_SYSTEM - sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, - editFunc, 0, 0); - sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, - editFunc, 0, 0); -#endif - if( p->openMode==SHELL_OPEN_ZIPFILE ){ - char *zSql = sqlite3_mprintf( - "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename); - sqlite3_exec(p->db, zSql, 0, 0, 0); - sqlite3_free(zSql); - } -#ifndef SQLITE_OMIT_DESERIALIZE - else - if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){ - int rc; - int nData = 0; - unsigned char *aData; - if( p->openMode==SHELL_OPEN_DESERIALIZE ){ - aData = (unsigned char*)readFile(zDbFilename, &nData); - }else{ - aData = readHexDb(p, &nData); - if( aData==0 ){ - return; - } - } - rc = sqlite3_deserialize(p->db, "main", aData, nData, nData, - SQLITE_DESERIALIZE_RESIZEABLE | - SQLITE_DESERIALIZE_FREEONCLOSE); - if( rc ){ - utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc); - } - if( p->szMax>0 ){ - sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax); - } - } + sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, + editFunc, 0, 0); + sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, + editFunc, 0, 0); #endif + if( p->openMode==SHELL_OPEN_ZIPFILE ){ + char *zSql = sqlite3_mprintf( + "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", zDbFilename); + sqlite3_exec(p->db, zSql, 0, 0, 0); + sqlite3_free(zSql); } - if( p->bSafeModePersist && p->db!=0 ){ - sqlite3_set_authorizer(p->db, safeModeAuth, p); +#ifndef SQLITE_OMIT_DESERIALIZE + else + if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){ + int rc; + int nData = 0; + unsigned char *aData; + if( p->openMode==SHELL_OPEN_DESERIALIZE ){ + aData = (unsigned char*)readFile(zDbFilename, &nData); + }else{ + aData = readHexDb(p, &nData); + if( aData==0 ){ + return; + } + } + rc = sqlite3_deserialize(p->db, "main", aData, nData, nData, + SQLITE_DESERIALIZE_RESIZEABLE | + SQLITE_DESERIALIZE_FREEONCLOSE); + if( rc ){ + utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc); + } + if( p->szMax>0 ){ + sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax); + } } +#endif + } + if( p->bSafeModePersist && p->db!=0 ){ + sqlite3_set_authorizer(p->db, safeModeAuth, p); + } } /* ** Attempt to close the databaes connection. Report errors. */ void close_db(sqlite3 *db){ - int rc = sqlite3_close(db); - if( rc ){ - utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", - rc, sqlite3_errmsg(db)); - } + int rc = sqlite3_close(db); + if( rc ){ + utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", + rc, sqlite3_errmsg(db)); + } } #if HAVE_READLINE || HAVE_EDITLINE @@ -15862,28 +15862,28 @@ void close_db(sqlite3 *db){ ** Readline completion callbacks */ static char *readline_completion_generator(const char *text, int state){ - static sqlite3_stmt *pStmt = 0; - char *zRet; - if( state==0 ){ - char *zSql; - sqlite3_finalize(pStmt); - zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase" - " FROM completion(%Q) ORDER BY 1", text); - sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - } - if( sqlite3_step(pStmt)==SQLITE_ROW ){ - zRet = strdup((const char*)sqlite3_column_text(pStmt, 0)); - }else{ - sqlite3_finalize(pStmt); - pStmt = 0; - zRet = 0; - } - return zRet; + static sqlite3_stmt *pStmt = 0; + char *zRet; + if( state==0 ){ + char *zSql; + sqlite3_finalize(pStmt); + zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase" + " FROM completion(%Q) ORDER BY 1", text); + sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + } + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + zRet = strdup((const char*)sqlite3_column_text(pStmt, 0)); + }else{ + sqlite3_finalize(pStmt); + pStmt = 0; + zRet = 0; + } + return zRet; } static char **readline_completion(const char *zText, int iStart, int iEnd){ - rl_attempted_completion_over = 1; - return rl_completion_matches(zText, readline_completion_generator); + rl_attempted_completion_over = 1; + return rl_completion_matches(zText, readline_completion_generator); } #elif HAVE_LINENOISE @@ -15891,33 +15891,33 @@ static char **readline_completion(const char *zText, int iStart, int iEnd){ ** Linenoise completion callback */ static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){ - int nLine = strlen30(zLine); - int i, iStart; - sqlite3_stmt *pStmt = 0; - char *zSql; - char zBuf[1000]; - - if( nLine>sizeof(zBuf)-30 ) return; - if( zLine[0]=='.' || zLine[0]=='#') return; - for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){} - if( i==nLine-1 ) return; - iStart = i+1; - memcpy(zBuf, zLine, iStart); - zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase" - " FROM completion(%Q,%Q) ORDER BY 1", - &zLine[iStart], zLine); - sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */ - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0); - int nCompletion = sqlite3_column_bytes(pStmt, 0); - if( iStart+nCompletion < sizeof(zBuf)-1 ){ - memcpy(zBuf+iStart, zCompletion, nCompletion+1); - linenoiseAddCompletion(lc, zBuf); - } - } - sqlite3_finalize(pStmt); + int nLine = strlen30(zLine); + int i, iStart; + sqlite3_stmt *pStmt = 0; + char *zSql; + char zBuf[1000]; + + if( nLine>sizeof(zBuf)-30 ) return; + if( zLine[0]=='.' || zLine[0]=='#') return; + for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){} + if( i==nLine-1 ) return; + iStart = i+1; + memcpy(zBuf, zLine, iStart); + zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase" + " FROM completion(%Q,%Q) ORDER BY 1", + &zLine[iStart], zLine); + sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */ + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0); + int nCompletion = sqlite3_column_bytes(pStmt, 0); + if( iStart+nCompletion < sizeof(zBuf)-1 ){ + memcpy(zBuf+iStart, zCompletion, nCompletion+1); + linenoiseAddCompletion(lc, zBuf); + } + } + sqlite3_finalize(pStmt); } #endif @@ -15938,47 +15938,47 @@ static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){ ** \NNN -> ascii character NNN in octal */ static void resolve_backslashes(char *z){ - int i, j; - char c; - while( *z && *z!='\\' ) z++; - for(i=j=0; (c = z[i])!=0; i++, j++){ - if( c=='\\' && z[i+1]!=0 ){ - c = z[++i]; - if( c=='a' ){ - c = '\a'; - }else if( c=='b' ){ - c = '\b'; - }else if( c=='t' ){ - c = '\t'; - }else if( c=='n' ){ - c = '\n'; - }else if( c=='v' ){ - c = '\v'; - }else if( c=='f' ){ - c = '\f'; - }else if( c=='r' ){ - c = '\r'; - }else if( c=='"' ){ - c = '"'; - }else if( c=='\'' ){ - c = '\''; - }else if( c=='\\' ){ - c = '\\'; - }else if( c>='0' && c<='7' ){ - c -= '0'; - if( z[i+1]>='0' && z[i+1]<='7' ){ - i++; - c = (c<<3) + z[i] - '0'; - if( z[i+1]>='0' && z[i+1]<='7' ){ - i++; - c = (c<<3) + z[i] - '0'; - } - } - } + int i, j; + char c; + while( *z && *z!='\\' ) z++; + for(i=j=0; (c = z[i])!=0; i++, j++){ + if( c=='\\' && z[i+1]!=0 ){ + c = z[++i]; + if( c=='a' ){ + c = '\a'; + }else if( c=='b' ){ + c = '\b'; + }else if( c=='t' ){ + c = '\t'; + }else if( c=='n' ){ + c = '\n'; + }else if( c=='v' ){ + c = '\v'; + }else if( c=='f' ){ + c = '\f'; + }else if( c=='r' ){ + c = '\r'; + }else if( c=='"' ){ + c = '"'; + }else if( c=='\'' ){ + c = '\''; + }else if( c=='\\' ){ + c = '\\'; + }else if( c>='0' && c<='7' ){ + c -= '0'; + if( z[i+1]>='0' && z[i+1]<='7' ){ + i++; + c = (c<<3) + z[i] - '0'; + if( z[i+1]>='0' && z[i+1]<='7' ){ + i++; + c = (c<<3) + z[i] - '0'; + } } - z[j] = c; + } } - if( j=0; i++){} - }else{ - for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} - } - if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff); - if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ - return 1; - } - if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ - return 0; - } - utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", - zArg); + int i; + if( zArg[0]=='0' && zArg[1]=='x' ){ + for(i=2; hexDigitValue(zArg[i])>=0; i++){} + }else{ + for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} + } + if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff); + if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ + return 1; + } + if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ return 0; + } + utf8_printf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", + zArg); + return 0; } /* ** Set or clear a shell flag according to a boolean value. */ static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){ - if( booleanValue(zArg) ){ - ShellSetFlag(p, mFlag); - }else{ - ShellClearFlag(p, mFlag); - } + if( booleanValue(zArg) ){ + ShellSetFlag(p, mFlag); + }else{ + ShellClearFlag(p, mFlag); + } } /* ** Close an output file, assuming it is not stderr or stdout */ static void output_file_close(FILE *f){ - if( f && f!=stdout && f!=stderr ) fclose(f); + if( f && f!=stdout && f!=stderr ) fclose(f); } /* @@ -16028,20 +16028,20 @@ static void output_file_close(FILE *f){ ** filename is "off". */ static FILE *output_file_open(const char *zFile, int bTextMode){ - FILE *f; - if( strcmp(zFile,"stdout")==0 ){ - f = stdout; - }else if( strcmp(zFile, "stderr")==0 ){ - f = stderr; - }else if( strcmp(zFile, "off")==0 ){ - f = 0; - }else{ - f = fopen(zFile, bTextMode ? "w" : "wb"); - if( f==0 ){ - utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); - } + FILE *f; + if( strcmp(zFile,"stdout")==0 ){ + f = stdout; + }else if( strcmp(zFile, "stderr")==0 ){ + f = stderr; + }else if( strcmp(zFile, "off")==0 ){ + f = 0; + }else{ + f = fopen(zFile, bTextMode ? "w" : "wb"); + if( f==0 ){ + utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); } - return f; + } + return f; } #ifndef SQLITE_OMIT_TRACE @@ -16049,57 +16049,57 @@ static FILE *output_file_open(const char *zFile, int bTextMode){ ** A routine for handling output from sqlite3_trace(). */ static int sql_trace_callback( - unsigned mType, /* The trace type */ - void *pArg, /* The ShellState pointer */ - void *pP, /* Usually a pointer to sqlite_stmt */ - void *pX /* Auxiliary output */ + unsigned mType, /* The trace type */ + void *pArg, /* The ShellState pointer */ + void *pP, /* Usually a pointer to sqlite_stmt */ + void *pX /* Auxiliary output */ ){ - ShellState *p = (ShellState*)pArg; - sqlite3_stmt *pStmt; - const char *zSql; - int nSql; - if( p->traceOut==0 ) return 0; - if( mType==SQLITE_TRACE_CLOSE ){ - utf8_printf(p->traceOut, "-- closing database connection\n"); - return 0; - } - if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){ - zSql = (const char*)pX; - }else{ - pStmt = (sqlite3_stmt*)pP; - switch( p->eTraceType ){ - case SHELL_TRACE_EXPANDED: { - zSql = sqlite3_expanded_sql(pStmt); - break; - } + ShellState *p = (ShellState*)pArg; + sqlite3_stmt *pStmt; + const char *zSql; + int nSql; + if( p->traceOut==0 ) return 0; + if( mType==SQLITE_TRACE_CLOSE ){ + utf8_printf(p->traceOut, "-- closing database connection\n"); + return 0; + } + if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){ + zSql = (const char*)pX; + }else{ + pStmt = (sqlite3_stmt*)pP; + switch( p->eTraceType ){ + case SHELL_TRACE_EXPANDED: { + zSql = sqlite3_expanded_sql(pStmt); + break; + } #ifdef SQLITE_ENABLE_NORMALIZE - case SHELL_TRACE_NORMALIZED: { - zSql = sqlite3_normalized_sql(pStmt); - break; - } + case SHELL_TRACE_NORMALIZED: { + zSql = sqlite3_normalized_sql(pStmt); + break; + } #endif - default: { - zSql = sqlite3_sql(pStmt); - break; - } - } - } - if( zSql==0 ) return 0; - nSql = strlen30(zSql); - while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; } - switch( mType ){ - case SQLITE_TRACE_ROW: - case SQLITE_TRACE_STMT: { - utf8_printf(p->traceOut, "%.*s;\n", nSql, zSql); - break; - } - case SQLITE_TRACE_PROFILE: { - sqlite3_int64 nNanosec = *(sqlite3_int64*)pX; - utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", nSql, zSql, nNanosec); - break; - } - } - return 0; + default: { + zSql = sqlite3_sql(pStmt); + break; + } + } + } + if( zSql==0 ) return 0; + nSql = strlen30(zSql); + while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; } + switch( mType ){ + case SQLITE_TRACE_ROW: + case SQLITE_TRACE_STMT: { + utf8_printf(p->traceOut, "%.*s;\n", nSql, zSql); + break; + } + case SQLITE_TRACE_PROFILE: { + sqlite3_int64 nNanosec = *(sqlite3_int64*)pX; + utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", nSql, zSql, nNanosec); + break; + } + } + return 0; } #endif @@ -16108,8 +16108,8 @@ static int sql_trace_callback( ** a useful spot to set a debugger breakpoint. */ static void test_breakpoint(void){ - static int nCall = 0; - nCall++; + static int nCall = 0; + nCall++; } /* @@ -16117,39 +16117,39 @@ static void test_breakpoint(void){ */ typedef struct ImportCtx ImportCtx; struct ImportCtx { - const char *zFile; /* Name of the input file */ - FILE *in; /* Read the CSV text from this input stream */ - int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */ - char *z; /* Accumulated text for a field */ - int n; /* Number of bytes in z */ - int nAlloc; /* Space allocated for z[] */ - int nLine; /* Current line number */ - int nRow; /* Number of rows imported */ - int nErr; /* Number of errors encountered */ - int bNotFirst; /* True if one or more bytes already read */ - int cTerm; /* Character that terminated the most recent field */ - int cColSep; /* The column separator character. (Usually ",") */ - int cRowSep; /* The row separator character. (Usually "\n") */ + const char *zFile; /* Name of the input file */ + FILE *in; /* Read the CSV text from this input stream */ + int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */ + char *z; /* Accumulated text for a field */ + int n; /* Number of bytes in z */ + int nAlloc; /* Space allocated for z[] */ + int nLine; /* Current line number */ + int nRow; /* Number of rows imported */ + int nErr; /* Number of errors encountered */ + int bNotFirst; /* True if one or more bytes already read */ + int cTerm; /* Character that terminated the most recent field */ + int cColSep; /* The column separator character. (Usually ",") */ + int cRowSep; /* The row separator character. (Usually "\n") */ }; /* Clean up resourced used by an ImportCtx */ static void import_cleanup(ImportCtx *p){ - if( p->in!=0 && p->xCloser!=0 ){ - p->xCloser(p->in); - p->in = 0; - } - sqlite3_free(p->z); - p->z = 0; + if( p->in!=0 && p->xCloser!=0 ){ + p->xCloser(p->in); + p->in = 0; + } + sqlite3_free(p->z); + p->z = 0; } /* Append a single byte to z[] */ static void import_append_char(ImportCtx *p, int c){ - if( p->n+1>=p->nAlloc ){ - p->nAlloc += p->nAlloc + 100; - p->z = sqlite3_realloc64(p->z, p->nAlloc); - if( p->z==0 ) shell_out_of_memory(); - } - p->z[p->n++] = (char)c; + if( p->n+1>=p->nAlloc ){ + p->nAlloc += p->nAlloc + 100; + p->z = sqlite3_realloc64(p->z, p->nAlloc); + if( p->z==0 ) shell_out_of_memory(); + } + p->z[p->n++] = (char)c; } /* Read a single field of CSV text. Compatible with rfc4180 and extended @@ -16166,81 +16166,81 @@ static void import_append_char(ImportCtx *p, int c){ ** + Report syntax errors on stderr */ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){ - int c; - int cSep = p->cColSep; - int rSep = p->cRowSep; - p->n = 0; - c = fgetc(p->in); - if( c==EOF || seenInterrupt ){ - p->cTerm = EOF; - return 0; - } - if( c=='"' ){ - int pc, ppc; - int startLine = p->nLine; - int cQuote = c; - pc = ppc = 0; - while( 1 ){ - c = fgetc(p->in); - if( c==rSep ) p->nLine++; - if( c==cQuote ){ - if( pc==cQuote ){ - pc = 0; - continue; - } - } - if( (c==cSep && pc==cQuote) - || (c==rSep && pc==cQuote) - || (c==rSep && pc=='\r' && ppc==cQuote) - || (c==EOF && pc==cQuote) - ){ - do{ p->n--; }while( p->z[p->n]!=cQuote ); - p->cTerm = c; - break; - } - if( pc==cQuote && c!='\r' ){ - utf8_printf(stderr, "%s:%d: unescaped %c character\n", - p->zFile, p->nLine, cQuote); - } - if( c==EOF ){ - utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n", - p->zFile, startLine, cQuote); - p->cTerm = c; - break; - } - import_append_char(p, c); - ppc = pc; - pc = c; - } - }else{ - /* If this is the first field being parsed and it begins with the + int c; + int cSep = p->cColSep; + int rSep = p->cRowSep; + p->n = 0; + c = fgetc(p->in); + if( c==EOF || seenInterrupt ){ + p->cTerm = EOF; + return 0; + } + if( c=='"' ){ + int pc, ppc; + int startLine = p->nLine; + int cQuote = c; + pc = ppc = 0; + while( 1 ){ + c = fgetc(p->in); + if( c==rSep ) p->nLine++; + if( c==cQuote ){ + if( pc==cQuote ){ + pc = 0; + continue; + } + } + if( (c==cSep && pc==cQuote) + || (c==rSep && pc==cQuote) + || (c==rSep && pc=='\r' && ppc==cQuote) + || (c==EOF && pc==cQuote) + ){ + do{ p->n--; }while( p->z[p->n]!=cQuote ); + p->cTerm = c; + break; + } + if( pc==cQuote && c!='\r' ){ + utf8_printf(stderr, "%s:%d: unescaped %c character\n", + p->zFile, p->nLine, cQuote); + } + if( c==EOF ){ + utf8_printf(stderr, "%s:%d: unterminated %c-quoted field\n", + p->zFile, startLine, cQuote); + p->cTerm = c; + break; + } + import_append_char(p, c); + ppc = pc; + pc = c; + } + }else{ + /* If this is the first field being parsed and it begins with the ** UTF-8 BOM (0xEF BB BF) then skip the BOM */ - if( (c&0xff)==0xef && p->bNotFirst==0 ){ - import_append_char(p, c); - c = fgetc(p->in); - if( (c&0xff)==0xbb ){ - import_append_char(p, c); - c = fgetc(p->in); - if( (c&0xff)==0xbf ){ - p->bNotFirst = 1; - p->n = 0; - return csv_read_one_field(p); - } - } - } - while( c!=EOF && c!=cSep && c!=rSep ){ - import_append_char(p, c); - c = fgetc(p->in); - } - if( c==rSep ){ - p->nLine++; - if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; + if( (c&0xff)==0xef && p->bNotFirst==0 ){ + import_append_char(p, c); + c = fgetc(p->in); + if( (c&0xff)==0xbb ){ + import_append_char(p, c); + c = fgetc(p->in); + if( (c&0xff)==0xbf ){ + p->bNotFirst = 1; + p->n = 0; + return csv_read_one_field(p); } - p->cTerm = c; + } + } + while( c!=EOF && c!=cSep && c!=rSep ){ + import_append_char(p, c); + c = fgetc(p->in); + } + if( c==rSep ){ + p->nLine++; + if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; } - if( p->z ) p->z[p->n] = 0; - p->bNotFirst = 1; - return p->z; + p->cTerm = c; + } + if( p->z ) p->z[p->n] = 0; + p->bNotFirst = 1; + return p->z; } /* Read a single field of ASCII delimited text. @@ -16256,25 +16256,25 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){ ** + Report syntax errors on stderr */ static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){ - int c; - int cSep = p->cColSep; - int rSep = p->cRowSep; - p->n = 0; + int c; + int cSep = p->cColSep; + int rSep = p->cRowSep; + p->n = 0; + c = fgetc(p->in); + if( c==EOF || seenInterrupt ){ + p->cTerm = EOF; + return 0; + } + while( c!=EOF && c!=cSep && c!=rSep ){ + import_append_char(p, c); c = fgetc(p->in); - if( c==EOF || seenInterrupt ){ - p->cTerm = EOF; - return 0; - } - while( c!=EOF && c!=cSep && c!=rSep ){ - import_append_char(p, c); - c = fgetc(p->in); - } - if( c==rSep ){ - p->nLine++; - } - p->cTerm = c; - if( p->z ) p->z[p->n] = 0; - return p->z; + } + if( c==rSep ){ + p->nLine++; + } + p->cTerm = c; + if( p->z ) p->z[p->n] = 0; + return p->z; } /* @@ -16283,106 +16283,106 @@ static char *SQLITE_CDECL ascii_read_one_field(ImportCtx *p){ ** work for WITHOUT ROWID tables. */ static void tryToCloneData( - ShellState *p, - sqlite3 *newDb, - const char *zTable + ShellState *p, + sqlite3 *newDb, + const char *zTable ){ - sqlite3_stmt *pQuery = 0; - sqlite3_stmt *pInsert = 0; - char *zQuery = 0; - char *zInsert = 0; - int rc; - int i, j, n; - int nTable = strlen30(zTable); - int k = 0; - int cnt = 0; - const int spinRate = 10000; - - zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); - rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); - if( rc ){ - utf8_printf(stderr, "Error %d: %s on [%s]\n", + sqlite3_stmt *pQuery = 0; + sqlite3_stmt *pInsert = 0; + char *zQuery = 0; + char *zInsert = 0; + int rc; + int i, j, n; + int nTable = strlen30(zTable); + int k = 0; + int cnt = 0; + const int spinRate = 10000; + + zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); + rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); + if( rc ){ + utf8_printf(stderr, "Error %d: %s on [%s]\n", sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery); - goto end_data_xfer; - } - n = sqlite3_column_count(pQuery); - zInsert = sqlite3_malloc64(200 + nTable + n*3); - if( zInsert==0 ) shell_out_of_memory(); - sqlite3_snprintf(200+nTable,zInsert, - "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable); - i = strlen30(zInsert); - for(j=1; jdb, zQuery, -1, &pQuery, 0); - if( rc ){ - utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable); + goto end_data_xfer; + } + for(k=0; k<2; k++){ + while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ + for(i=0; idb, zQuery, -1, &pQuery, 0); + if( rc ){ + utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable); + break; + } + } /* End for(k=0...) */ + +end_data_xfer: + sqlite3_finalize(pQuery); + sqlite3_finalize(pInsert); + sqlite3_free(zQuery); + sqlite3_free(zInsert); } @@ -16393,73 +16393,73 @@ end_data_xfer: ** sqlite_schema table, try again moving backwards. */ static void tryToCloneSchema( - ShellState *p, - sqlite3 *newDb, - const char *zWhere, - void (*xForEach)(ShellState*,sqlite3*,const char*) + ShellState *p, + sqlite3 *newDb, + const char *zWhere, + void (*xForEach)(ShellState*,sqlite3*,const char*) ){ - sqlite3_stmt *pQuery = 0; - char *zQuery = 0; - int rc; - const unsigned char *zName; - const unsigned char *zSql; - char *zErrMsg = 0; - - zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" - " WHERE %s", zWhere); - rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); - if( rc ){ - utf8_printf(stderr, "Error: (%d) %s on [%s]\n", - sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), - zQuery); - goto end_schema_xfer; + sqlite3_stmt *pQuery = 0; + char *zQuery = 0; + int rc; + const unsigned char *zName; + const unsigned char *zSql; + char *zErrMsg = 0; + + zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" + " WHERE %s", zWhere); + rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); + if( rc ){ + utf8_printf(stderr, "Error: (%d) %s on [%s]\n", + sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), + zQuery); + goto end_schema_xfer; + } + while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ + zName = sqlite3_column_text(pQuery, 0); + zSql = sqlite3_column_text(pQuery, 1); + printf("%s... ", zName); fflush(stdout); + sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); + if( zErrMsg ){ + utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); + sqlite3_free(zErrMsg); + zErrMsg = 0; } - while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){ - zName = sqlite3_column_text(pQuery, 0); - zSql = sqlite3_column_text(pQuery, 1); - printf("%s... ", zName); fflush(stdout); - sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); - if( zErrMsg ){ - utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); - sqlite3_free(zErrMsg); - zErrMsg = 0; - } - if( xForEach ){ - xForEach(p, newDb, (const char*)zName); - } - printf("done\n"); - } - if( rc!=SQLITE_DONE ){ - sqlite3_finalize(pQuery); - sqlite3_free(zQuery); - zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" - " WHERE %s ORDER BY rowid DESC", zWhere); - rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); - if( rc ){ - utf8_printf(stderr, "Error: (%d) %s on [%s]\n", - sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), - zQuery); - goto end_schema_xfer; - } - while( sqlite3_step(pQuery)==SQLITE_ROW ){ - zName = sqlite3_column_text(pQuery, 0); - zSql = sqlite3_column_text(pQuery, 1); - printf("%s... ", zName); fflush(stdout); - sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); - if( zErrMsg ){ - utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); - sqlite3_free(zErrMsg); - zErrMsg = 0; - } - if( xForEach ){ - xForEach(p, newDb, (const char*)zName); - } - printf("done\n"); - } + if( xForEach ){ + xForEach(p, newDb, (const char*)zName); } -end_schema_xfer: + printf("done\n"); + } + if( rc!=SQLITE_DONE ){ sqlite3_finalize(pQuery); sqlite3_free(zQuery); + zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema" + " WHERE %s ORDER BY rowid DESC", zWhere); + rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); + if( rc ){ + utf8_printf(stderr, "Error: (%d) %s on [%s]\n", + sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), + zQuery); + goto end_schema_xfer; + } + while( sqlite3_step(pQuery)==SQLITE_ROW ){ + zName = sqlite3_column_text(pQuery, 0); + zSql = sqlite3_column_text(pQuery, 1); + printf("%s... ", zName); fflush(stdout); + sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg); + if( zErrMsg ){ + utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql); + sqlite3_free(zErrMsg); + zErrMsg = 0; + } + if( xForEach ){ + xForEach(p, newDb, (const char*)zName); + } + printf("done\n"); + } + } +end_schema_xfer: + sqlite3_finalize(pQuery); + sqlite3_free(zQuery); } /* @@ -16468,25 +16468,25 @@ end_schema_xfer: ** into zNewDb. */ static void tryToClone(ShellState *p, const char *zNewDb){ - int rc; - sqlite3 *newDb = 0; - if( access(zNewDb,0)==0 ){ - utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb); - return; - } - rc = sqlite3_open(zNewDb, &newDb); - if( rc ){ - utf8_printf(stderr, "Cannot create output database: %s\n", + int rc; + sqlite3 *newDb = 0; + if( access(zNewDb,0)==0 ){ + utf8_printf(stderr, "File \"%s\" already exists.\n", zNewDb); + return; + } + rc = sqlite3_open(zNewDb, &newDb); + if( rc ){ + utf8_printf(stderr, "Cannot create output database: %s\n", sqlite3_errmsg(newDb)); - }else{ - sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0); - sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); - tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); - tryToCloneSchema(p, newDb, "type!='table'", 0); - sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); - sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); - } - close_db(newDb); + }else{ + sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0); + sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); + tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); + tryToCloneSchema(p, newDb, "type!='table'", 0); + sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); + sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); + } + close_db(newDb); } /* @@ -16497,64 +16497,64 @@ static void tryToClone(ShellState *p, const char *zNewDb){ ** launch start/open/xdg-open on that temporary file. */ static void output_reset(ShellState *p){ - if( p->outfile[0]=='|' ){ + if( p->outfile[0]=='|' ){ #ifndef SQLITE_OMIT_POPEN - pclose(p->out); + pclose(p->out); #endif - }else{ - output_file_close(p->out); + }else{ + output_file_close(p->out); #ifndef SQLITE_NOHAVE_SYSTEM - if( p->doXdgOpen ){ - const char *zXdgOpenCmd = + if( p->doXdgOpen ){ + const char *zXdgOpenCmd = #if defined(_WIN32) - "start"; + "start"; #elif defined(__APPLE__) - "open"; + "open"; #else - "xdg-open"; + "xdg-open"; #endif - char *zCmd; - zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); - if( system(zCmd) ){ - utf8_printf(stderr, "Failed: [%s]\n", zCmd); - }else{ - /* Give the start/open/xdg-open command some time to get + char *zCmd; + zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); + if( system(zCmd) ){ + utf8_printf(stderr, "Failed: [%s]\n", zCmd); + }else{ + /* Give the start/open/xdg-open command some time to get ** going before we continue, and potential delete the ** p->zTempFile data file out from under it */ - sqlite3_sleep(2000); - } - sqlite3_free(zCmd); - outputModePop(p); - p->doXdgOpen = 0; - } -#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ + sqlite3_sleep(2000); + } + sqlite3_free(zCmd); + outputModePop(p); + p->doXdgOpen = 0; } - p->outfile[0] = 0; - p->out = stdout; +#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */ + } + p->outfile[0] = 0; + p->out = stdout; } /* ** Run an SQL command and return the single integer result. */ static int db_int(ShellState *p, const char *zSql){ - sqlite3_stmt *pStmt; - int res = 0; - sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ - res = sqlite3_column_int(pStmt,0); - } - sqlite3_finalize(pStmt); - return res; + sqlite3_stmt *pStmt; + int res = 0; + sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ + res = sqlite3_column_int(pStmt,0); + } + sqlite3_finalize(pStmt); + return res; } /* ** Convert a 2-byte or 4-byte big-endian integer into a native integer */ static unsigned int get2byteInt(unsigned char *a){ - return (a[0]<<8) + a[1]; + return (a[0]<<8) + a[1]; } static unsigned int get4byteInt(unsigned char *a){ - return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; + return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; } /* @@ -16563,104 +16563,104 @@ static unsigned int get4byteInt(unsigned char *a){ ** Return 1 on error, 2 to exit, and 0 otherwise. */ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){ - static const struct { const char *zName; int ofst; } aField[] = { - { "file change counter:", 24 }, - { "database page count:", 28 }, - { "freelist page count:", 36 }, - { "schema cookie:", 40 }, - { "schema format:", 44 }, - { "default cache size:", 48 }, - { "autovacuum top root:", 52 }, - { "incremental vacuum:", 64 }, - { "text encoding:", 56 }, - { "user version:", 60 }, - { "application id:", 68 }, - { "software version:", 96 }, - }; - static const struct { const char *zName; const char *zSql; } aQuery[] = { - { "number of tables:", - "SELECT count(*) FROM %s WHERE type='table'" }, - { "number of indexes:", - "SELECT count(*) FROM %s WHERE type='index'" }, - { "number of triggers:", - "SELECT count(*) FROM %s WHERE type='trigger'" }, - { "number of views:", - "SELECT count(*) FROM %s WHERE type='view'" }, - { "schema size:", - "SELECT total(length(sql)) FROM %s" }, - }; - int i, rc; - unsigned iDataVersion; - char *zSchemaTab; - char *zDb = nArg>=2 ? azArg[1] : "main"; - sqlite3_stmt *pStmt = 0; - unsigned char aHdr[100]; - open_db(p, 0); - if( p->db==0 ) return 1; - rc = sqlite3_prepare_v2(p->db, - "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", - -1, &pStmt, 0); - if( rc ){ - utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db)); - sqlite3_finalize(pStmt); - return 1; - } - sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC); - if( sqlite3_step(pStmt)==SQLITE_ROW - && sqlite3_column_bytes(pStmt,0)>100 - ){ - memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100); - sqlite3_finalize(pStmt); - }else{ - raw_printf(stderr, "unable to read database header\n"); - sqlite3_finalize(pStmt); - return 1; - } - i = get2byteInt(aHdr+16); - if( i==1 ) i = 65536; - utf8_printf(p->out, "%-20s %d\n", "database page size:", i); - utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]); - utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]); - utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); - for(i=0; iout, "%-20s %u", aField[i].zName, val); - switch( ofst ){ - case 56: { - if( val==1 ) raw_printf(p->out, " (utf8)"); - if( val==2 ) raw_printf(p->out, " (utf16le)"); - if( val==3 ) raw_printf(p->out, " (utf16be)"); - } - } - raw_printf(p->out, "\n"); - } - if( zDb==0 ){ - zSchemaTab = sqlite3_mprintf("main.sqlite_schema"); - }else if( strcmp(zDb,"temp")==0 ){ - zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema"); - }else{ - zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb); - } - for(i=0; iout, "%-20s %d\n", aQuery[i].zName, val); + static const struct { const char *zName; int ofst; } aField[] = { + { "file change counter:", 24 }, + { "database page count:", 28 }, + { "freelist page count:", 36 }, + { "schema cookie:", 40 }, + { "schema format:", 44 }, + { "default cache size:", 48 }, + { "autovacuum top root:", 52 }, + { "incremental vacuum:", 64 }, + { "text encoding:", 56 }, + { "user version:", 60 }, + { "application id:", 68 }, + { "software version:", 96 }, + }; + static const struct { const char *zName; const char *zSql; } aQuery[] = { + { "number of tables:", + "SELECT count(*) FROM %s WHERE type='table'" }, + { "number of indexes:", + "SELECT count(*) FROM %s WHERE type='index'" }, + { "number of triggers:", + "SELECT count(*) FROM %s WHERE type='trigger'" }, + { "number of views:", + "SELECT count(*) FROM %s WHERE type='view'" }, + { "schema size:", + "SELECT total(length(sql)) FROM %s" }, + }; + int i, rc; + unsigned iDataVersion; + char *zSchemaTab; + char *zDb = nArg>=2 ? azArg[1] : "main"; + sqlite3_stmt *pStmt = 0; + unsigned char aHdr[100]; + open_db(p, 0); + if( p->db==0 ) return 1; + rc = sqlite3_prepare_v2(p->db, + "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1", + -1, &pStmt, 0); + if( rc ){ + utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db)); + sqlite3_finalize(pStmt); + return 1; + } + sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC); + if( sqlite3_step(pStmt)==SQLITE_ROW + && sqlite3_column_bytes(pStmt,0)>100 + ){ + memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100); + sqlite3_finalize(pStmt); + }else{ + raw_printf(stderr, "unable to read database header\n"); + sqlite3_finalize(pStmt); + return 1; + } + i = get2byteInt(aHdr+16); + if( i==1 ) i = 65536; + utf8_printf(p->out, "%-20s %d\n", "database page size:", i); + utf8_printf(p->out, "%-20s %d\n", "write format:", aHdr[18]); + utf8_printf(p->out, "%-20s %d\n", "read format:", aHdr[19]); + utf8_printf(p->out, "%-20s %d\n", "reserved bytes:", aHdr[20]); + for(i=0; iout, "%-20s %u", aField[i].zName, val); + switch( ofst ){ + case 56: { + if( val==1 ) raw_printf(p->out, " (utf8)"); + if( val==2 ) raw_printf(p->out, " (utf16le)"); + if( val==3 ) raw_printf(p->out, " (utf16be)"); + } } - sqlite3_free(zSchemaTab); - sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion); - utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion); - return 0; + raw_printf(p->out, "\n"); + } + if( zDb==0 ){ + zSchemaTab = sqlite3_mprintf("main.sqlite_schema"); + }else if( strcmp(zDb,"temp")==0 ){ + zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema"); + }else{ + zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb); + } + for(i=0; iout, "%-20s %d\n", aQuery[i].zName, val); + } + sqlite3_free(zSchemaTab); + sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion); + utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion); + return 0; } /* ** Print the current sqlite3_errmsg() value to stderr and return 1. */ static int shellDatabaseError(sqlite3 *db){ - const char *zErr = sqlite3_errmsg(db); - utf8_printf(stderr, "Error: %s\n", zErr); - return 1; + const char *zErr = sqlite3_errmsg(db); + utf8_printf(stderr, "Error: %s\n", zErr); + return 1; } /* @@ -16687,77 +16687,77 @@ static int shellDatabaseError(sqlite3 *db){ ** Extra whitespace at the end of z[] is ignored. */ static int testcase_glob(const char *zGlob, const char *z){ - int c, c2; - int invert; - int seen; - - while( (c = (*(zGlob++)))!=0 ){ - if( IsSpace(c) ){ - if( !IsSpace(*z) ) return 0; - while( IsSpace(*zGlob) ) zGlob++; - while( IsSpace(*z) ) z++; - }else if( c=='*' ){ - while( (c=(*(zGlob++))) == '*' || c=='?' ){ - if( c=='?' && (*(z++))==0 ) return 0; - } - if( c==0 ){ - return 1; - }else if( c=='[' ){ - while( *z && testcase_glob(zGlob-1,z)==0 ){ - z++; - } - return (*z)!=0; - } - while( (c2 = (*(z++)))!=0 ){ - while( c2!=c ){ - c2 = *(z++); - if( c2==0 ) return 0; - } - if( testcase_glob(zGlob,z) ) return 1; - } - return 0; - }else if( c=='?' ){ - if( (*(z++))==0 ) return 0; - }else if( c=='[' ){ - int prior_c = 0; - seen = 0; - invert = 0; - c = *(z++); - if( c==0 ) return 0; - c2 = *(zGlob++); - if( c2=='^' ){ - invert = 1; - c2 = *(zGlob++); - } - if( c2==']' ){ - if( c==']' ) seen = 1; - c2 = *(zGlob++); - } - while( c2 && c2!=']' ){ - if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){ - c2 = *(zGlob++); - if( c>=prior_c && c<=c2 ) seen = 1; - prior_c = 0; - }else{ - if( c==c2 ){ - seen = 1; - } - prior_c = c2; - } - c2 = *(zGlob++); - } - if( c2==0 || (seen ^ invert)==0 ) return 0; - }else if( c=='#' ){ - if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++; - if( !IsDigit(z[0]) ) return 0; - z++; - while( IsDigit(z[0]) ){ z++; } + int c, c2; + int invert; + int seen; + + while( (c = (*(zGlob++)))!=0 ){ + if( IsSpace(c) ){ + if( !IsSpace(*z) ) return 0; + while( IsSpace(*zGlob) ) zGlob++; + while( IsSpace(*z) ) z++; + }else if( c=='*' ){ + while( (c=(*(zGlob++))) == '*' || c=='?' ){ + if( c=='?' && (*(z++))==0 ) return 0; + } + if( c==0 ){ + return 1; + }else if( c=='[' ){ + while( *z && testcase_glob(zGlob-1,z)==0 ){ + z++; + } + return (*z)!=0; + } + while( (c2 = (*(z++)))!=0 ){ + while( c2!=c ){ + c2 = *(z++); + if( c2==0 ) return 0; + } + if( testcase_glob(zGlob,z) ) return 1; + } + return 0; + }else if( c=='?' ){ + if( (*(z++))==0 ) return 0; + }else if( c=='[' ){ + int prior_c = 0; + seen = 0; + invert = 0; + c = *(z++); + if( c==0 ) return 0; + c2 = *(zGlob++); + if( c2=='^' ){ + invert = 1; + c2 = *(zGlob++); + } + if( c2==']' ){ + if( c==']' ) seen = 1; + c2 = *(zGlob++); + } + while( c2 && c2!=']' ){ + if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){ + c2 = *(zGlob++); + if( c>=prior_c && c<=c2 ) seen = 1; + prior_c = 0; }else{ - if( c!=(*(z++)) ) return 0; - } + if( c==c2 ){ + seen = 1; + } + prior_c = c2; + } + c2 = *(zGlob++); + } + if( c2==0 || (seen ^ invert)==0 ) return 0; + }else if( c=='#' ){ + if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++; + if( !IsDigit(z[0]) ) return 0; + z++; + while( IsDigit(z[0]) ){ z++; } + }else{ + if( c!=(*(z++)) ) return 0; } - while( IsSpace(*z) ){ z++; } - return *z==0; + } + while( IsSpace(*z) ){ z++; } + return *z==0; } @@ -16766,25 +16766,25 @@ static int testcase_glob(const char *zGlob, const char *z){ ** initial "-" characters. */ static int optionMatch(const char *zStr, const char *zOpt){ - if( zStr[0]!='-' ) return 0; - zStr++; - if( zStr[0]=='-' ) zStr++; - return strcmp(zStr, zOpt)==0; + if( zStr[0]!='-' ) return 0; + zStr++; + if( zStr[0]=='-' ) zStr++; + return strcmp(zStr, zOpt)==0; } /* ** Delete a file. */ int shellDeleteFile(const char *zFilename){ - int rc; + int rc; #ifdef _WIN32 - wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename); - rc = _wunlink(z); - sqlite3_free(z); + wchar_t *z = sqlite3_win32_utf8_to_unicode(zFilename); + rc = _wunlink(z); + sqlite3_free(z); #else - rc = unlink(zFilename); + rc = unlink(zFilename); #endif - return rc; + return rc; } /* @@ -16792,45 +16792,45 @@ int shellDeleteFile(const char *zFilename){ ** memory used to hold the name of the temp file. */ static void clearTempFile(ShellState *p){ - if( p->zTempFile==0 ) return; - if( p->doXdgOpen ) return; - if( shellDeleteFile(p->zTempFile) ) return; - sqlite3_free(p->zTempFile); - p->zTempFile = 0; + if( p->zTempFile==0 ) return; + if( p->doXdgOpen ) return; + if( shellDeleteFile(p->zTempFile) ) return; + sqlite3_free(p->zTempFile); + p->zTempFile = 0; } /* ** Create a new temp file name with the given suffix. */ static void newTempFile(ShellState *p, const char *zSuffix){ - clearTempFile(p); - sqlite3_free(p->zTempFile); - p->zTempFile = 0; - if( p->db ){ - sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile); - } - if( p->zTempFile==0 ){ - /* If p->db is an in-memory database then the TEMPFILENAME file-control + clearTempFile(p); + sqlite3_free(p->zTempFile); + p->zTempFile = 0; + if( p->db ){ + sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile); + } + if( p->zTempFile==0 ){ + /* If p->db is an in-memory database then the TEMPFILENAME file-control ** will not work and we will need to fallback to guessing */ - char *zTemp; - sqlite3_uint64 r; - sqlite3_randomness(sizeof(r), &r); - zTemp = getenv("TEMP"); - if( zTemp==0 ) zTemp = getenv("TMP"); - if( zTemp==0 ){ + char *zTemp; + sqlite3_uint64 r; + sqlite3_randomness(sizeof(r), &r); + zTemp = getenv("TEMP"); + if( zTemp==0 ) zTemp = getenv("TMP"); + if( zTemp==0 ){ #ifdef _WIN32 - zTemp = "\\tmp"; + zTemp = "\\tmp"; #else - zTemp = "/tmp"; + zTemp = "/tmp"; #endif - } - p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix); - }else{ - p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix); - } - if( p->zTempFile==0 ){ - shell_out_of_memory(); } + p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix); + }else{ + p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix); + } + if( p->zTempFile==0 ){ + shell_out_of_memory(); + } } @@ -16850,40 +16850,40 @@ static void newTempFile(ShellState *p, const char *zSuffix){ ** is the default collation sequence of the parent column. */ static void shellFkeyCollateClause( - sqlite3_context *pCtx, - int nVal, - sqlite3_value **apVal + sqlite3_context *pCtx, + int nVal, + sqlite3_value **apVal ){ - sqlite3 *db = sqlite3_context_db_handle(pCtx); - const char *zParent; - const char *zParentCol; - const char *zParentSeq; - const char *zChild; - const char *zChildCol; - const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */ - int rc; - - assert( nVal==4 ); - zParent = (const char*)sqlite3_value_text(apVal[0]); - zParentCol = (const char*)sqlite3_value_text(apVal[1]); - zChild = (const char*)sqlite3_value_text(apVal[2]); - zChildCol = (const char*)sqlite3_value_text(apVal[3]); - - sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); + sqlite3 *db = sqlite3_context_db_handle(pCtx); + const char *zParent; + const char *zParentCol; + const char *zParentSeq; + const char *zChild; + const char *zChildCol; + const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */ + int rc; + + assert( nVal==4 ); + zParent = (const char*)sqlite3_value_text(apVal[0]); + zParentCol = (const char*)sqlite3_value_text(apVal[1]); + zChild = (const char*)sqlite3_value_text(apVal[2]); + zChildCol = (const char*)sqlite3_value_text(apVal[3]); + + sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); + rc = sqlite3_table_column_metadata( + db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0 + ); + if( rc==SQLITE_OK ){ rc = sqlite3_table_column_metadata( - db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0 + db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0 ); - if( rc==SQLITE_OK ){ - rc = sqlite3_table_column_metadata( - db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0 - ); - } + } - if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){ - char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq); - sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); - sqlite3_free(z); - } + if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){ + char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq); + sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); + sqlite3_free(z); + } } @@ -16891,20 +16891,20 @@ static void shellFkeyCollateClause( ** The implementation of dot-command ".lint fkey-indexes". */ static int lintFkeyIndexes( - ShellState *pState, /* Current shell tool state */ - char **azArg, /* Array of arguments passed to dot command */ - int nArg /* Number of entries in azArg[] */ + ShellState *pState, /* Current shell tool state */ + char **azArg, /* Array of arguments passed to dot command */ + int nArg /* Number of entries in azArg[] */ ){ - sqlite3 *db = pState->db; /* Database handle to query "main" db of */ - FILE *out = pState->out; /* Stream to write non-error output to */ - int bVerbose = 0; /* If -verbose is present */ - int bGroupByParent = 0; /* If -groupbyparent is present */ - int i; /* To iterate through azArg[] */ - const char *zIndent = ""; /* How much to indent CREATE INDEX by */ - int rc; /* Return code */ - sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */ - - /* + sqlite3 *db = pState->db; /* Database handle to query "main" db of */ + FILE *out = pState->out; /* Stream to write non-error output to */ + int bVerbose = 0; /* If -verbose is present */ + int bGroupByParent = 0; /* If -groupbyparent is present */ + int i; /* To iterate through azArg[] */ + const char *zIndent = ""; /* How much to indent CREATE INDEX by */ + int rc; /* Return code */ + sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */ + + /* ** This SELECT statement returns one row for each foreign key constraint ** in the schema of the main database. The column values are: ** @@ -16939,167 +16939,167 @@ static int lintFkeyIndexes( ** ** These six values are used by the C logic below to generate the report. */ - const char *zSql = - "SELECT " - " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '" - " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' " - " || fkey_collate_clause(" - " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')" - ", " - " 'SEARCH ' || s.name || ' USING COVERING INDEX*('" - " || group_concat('*=?', ' AND ') || ')'" - ", " - " s.name || '(' || group_concat(f.[from], ', ') || ')'" - ", " - " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'" - ", " - " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))" - " || ' ON ' || quote(s.name) || '('" - " || group_concat(quote(f.[from]) ||" - " fkey_collate_clause(" - " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')" - " || ');'" - ", " - " f.[table] " - "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f " - "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) " - "GROUP BY s.name, f.id " - "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)" - ; - const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)"; - - for(i=2; i1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){ - bVerbose = 1; - } - else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){ - bGroupByParent = 1; - zIndent = " "; + const char *zSql = + "SELECT " + " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '" + " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' " + " || fkey_collate_clause(" + " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')" + ", " + " 'SEARCH ' || s.name || ' USING COVERING INDEX*('" + " || group_concat('*=?', ' AND ') || ')'" + ", " + " s.name || '(' || group_concat(f.[from], ', ') || ')'" + ", " + " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'" + ", " + " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))" + " || ' ON ' || quote(s.name) || '('" + " || group_concat(quote(f.[from]) ||" + " fkey_collate_clause(" + " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')" + " || ');'" + ", " + " f.[table] " + "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f " + "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) " + "GROUP BY s.name, f.id " + "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)" + ; + const char *zGlobIPK = "SEARCH * USING INTEGER PRIMARY KEY (rowid=?)"; + + for(i=2; i1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){ + bVerbose = 1; + } + else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){ + bGroupByParent = 1; + zIndent = " "; + } + else{ + raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n", + azArg[0], azArg[1] + ); + return SQLITE_ERROR; + } + } + + /* Register the fkey_collate_clause() SQL function */ + rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8, + 0, shellFkeyCollateClause, 0, 0 + ); + + + if( rc==SQLITE_OK ){ + rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0); + } + if( rc==SQLITE_OK ){ + sqlite3_bind_int(pSql, 1, bGroupByParent); + } + + if( rc==SQLITE_OK ){ + int rc2; + char *zPrev = 0; + while( SQLITE_ROW==sqlite3_step(pSql) ){ + int res = -1; + sqlite3_stmt *pExplain = 0; + const char *zEQP = (const char*)sqlite3_column_text(pSql, 0); + const char *zGlob = (const char*)sqlite3_column_text(pSql, 1); + const char *zFrom = (const char*)sqlite3_column_text(pSql, 2); + const char *zTarget = (const char*)sqlite3_column_text(pSql, 3); + const char *zCI = (const char*)sqlite3_column_text(pSql, 4); + const char *zParent = (const char*)sqlite3_column_text(pSql, 5); + + rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); + if( rc!=SQLITE_OK ) break; + if( SQLITE_ROW==sqlite3_step(pExplain) ){ + const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3); + res = ( + 0==sqlite3_strglob(zGlob, zPlan) + || 0==sqlite3_strglob(zGlobIPK, zPlan) + ); + } + rc = sqlite3_finalize(pExplain); + if( rc!=SQLITE_OK ) break; + + if( res<0 ){ + raw_printf(stderr, "Error: internal error"); + break; + }else{ + if( bGroupByParent + && (bVerbose || res==0) + && (zPrev==0 || sqlite3_stricmp(zParent, zPrev)) + ){ + raw_printf(out, "-- Parent table %s\n", zParent); + sqlite3_free(zPrev); + zPrev = sqlite3_mprintf("%s", zParent); } - else{ - raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n", - azArg[0], azArg[1] - ); - return SQLITE_ERROR; + + if( res==0 ){ + raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget); + }else if( bVerbose ){ + raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n", + zIndent, zFrom, zTarget + ); } + } } + sqlite3_free(zPrev); - /* Register the fkey_collate_clause() SQL function */ - rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8, - 0, shellFkeyCollateClause, 0, 0 - ); - - - if( rc==SQLITE_OK ){ - rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0); - } - if( rc==SQLITE_OK ){ - sqlite3_bind_int(pSql, 1, bGroupByParent); + if( rc!=SQLITE_OK ){ + raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); } - if( rc==SQLITE_OK ){ - int rc2; - char *zPrev = 0; - while( SQLITE_ROW==sqlite3_step(pSql) ){ - int res = -1; - sqlite3_stmt *pExplain = 0; - const char *zEQP = (const char*)sqlite3_column_text(pSql, 0); - const char *zGlob = (const char*)sqlite3_column_text(pSql, 1); - const char *zFrom = (const char*)sqlite3_column_text(pSql, 2); - const char *zTarget = (const char*)sqlite3_column_text(pSql, 3); - const char *zCI = (const char*)sqlite3_column_text(pSql, 4); - const char *zParent = (const char*)sqlite3_column_text(pSql, 5); - - rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); - if( rc!=SQLITE_OK ) break; - if( SQLITE_ROW==sqlite3_step(pExplain) ){ - const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3); - res = ( - 0==sqlite3_strglob(zGlob, zPlan) - || 0==sqlite3_strglob(zGlobIPK, zPlan) - ); - } - rc = sqlite3_finalize(pExplain); - if( rc!=SQLITE_OK ) break; - - if( res<0 ){ - raw_printf(stderr, "Error: internal error"); - break; - }else{ - if( bGroupByParent - && (bVerbose || res==0) - && (zPrev==0 || sqlite3_stricmp(zParent, zPrev)) - ){ - raw_printf(out, "-- Parent table %s\n", zParent); - sqlite3_free(zPrev); - zPrev = sqlite3_mprintf("%s", zParent); - } - - if( res==0 ){ - raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget); - }else if( bVerbose ){ - raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n", - zIndent, zFrom, zTarget - ); - } - } - } - sqlite3_free(zPrev); - - if( rc!=SQLITE_OK ){ - raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); - } - - rc2 = sqlite3_finalize(pSql); - if( rc==SQLITE_OK && rc2!=SQLITE_OK ){ - rc = rc2; - raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); - } - }else{ - raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); + rc2 = sqlite3_finalize(pSql); + if( rc==SQLITE_OK && rc2!=SQLITE_OK ){ + rc = rc2; + raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); } + }else{ + raw_printf(stderr, "%s\n", sqlite3_errmsg(db)); + } - return rc; + return rc; } /* ** Implementation of ".lint" dot command. */ static int lintDotCommand( - ShellState *pState, /* Current shell tool state */ - char **azArg, /* Array of arguments passed to dot command */ - int nArg /* Number of entries in azArg[] */ + ShellState *pState, /* Current shell tool state */ + char **azArg, /* Array of arguments passed to dot command */ + int nArg /* Number of entries in azArg[] */ ){ - int n; - n = (nArg>=2 ? strlen30(azArg[1]) : 0); - if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage; - return lintFkeyIndexes(pState, azArg, nArg); - -usage: - raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]); - raw_printf(stderr, "Where sub-commands are:\n"); - raw_printf(stderr, " fkey-indexes\n"); - return SQLITE_ERROR; + int n; + n = (nArg>=2 ? strlen30(azArg[1]) : 0); + if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage; + return lintFkeyIndexes(pState, azArg, nArg); + + usage: + raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]); + raw_printf(stderr, "Where sub-commands are:\n"); + raw_printf(stderr, " fkey-indexes\n"); + return SQLITE_ERROR; } #if !defined SQLITE_OMIT_VIRTUALTABLE static void shellPrepare( - sqlite3 *db, - int *pRc, - const char *zSql, - sqlite3_stmt **ppStmt + sqlite3 *db, + int *pRc, + const char *zSql, + sqlite3_stmt **ppStmt ){ - *ppStmt = 0; - if( *pRc==SQLITE_OK ){ - int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); - if( rc!=SQLITE_OK ){ - raw_printf(stderr, "sql error: %s (%d)\n", - sqlite3_errmsg(db), sqlite3_errcode(db) - ); - *pRc = rc; - } + *ppStmt = 0; + if( *pRc==SQLITE_OK ){ + int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); + if( rc!=SQLITE_OK ){ + raw_printf(stderr, "sql error: %s (%d)\n", + sqlite3_errmsg(db), sqlite3_errcode(db) + ); + *pRc = rc; } + } } /* @@ -17110,26 +17110,26 @@ static void shellPrepare( ** nuisance compiler warnings about "defined but not used". */ void shellPreparePrintf( - sqlite3 *db, - int *pRc, - sqlite3_stmt **ppStmt, - const char *zFmt, - ... + sqlite3 *db, + int *pRc, + sqlite3_stmt **ppStmt, + const char *zFmt, + ... ){ - *ppStmt = 0; - if( *pRc==SQLITE_OK ){ - va_list ap; - char *z; - va_start(ap, zFmt); - z = sqlite3_vmprintf(zFmt, ap); - va_end(ap); - if( z==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - shellPrepare(db, pRc, z, ppStmt); - sqlite3_free(z); - } + *ppStmt = 0; + if( *pRc==SQLITE_OK ){ + va_list ap; + char *z; + va_start(ap, zFmt); + z = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( z==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + shellPrepare(db, pRc, z, ppStmt); + sqlite3_free(z); } + } } /* Finalize the prepared statement created using shellPreparePrintf(). @@ -17139,19 +17139,19 @@ void shellPreparePrintf( ** nuisance compiler warnings about "defined but not used". */ void shellFinalize( - int *pRc, - sqlite3_stmt *pStmt + int *pRc, + sqlite3_stmt *pStmt ){ - if( pStmt ){ - sqlite3 *db = sqlite3_db_handle(pStmt); - int rc = sqlite3_finalize(pStmt); - if( *pRc==SQLITE_OK ){ - if( rc!=SQLITE_OK ){ - raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); - } - *pRc = rc; - } + if( pStmt ){ + sqlite3 *db = sqlite3_db_handle(pStmt); + int rc = sqlite3_finalize(pStmt); + if( *pRc==SQLITE_OK ){ + if( rc!=SQLITE_OK ){ + raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); + } + *pRc = rc; } + } } /* Reset the prepared statement created using shellPreparePrintf(). @@ -17161,17 +17161,17 @@ void shellFinalize( ** nuisance compiler warnings about "defined but not used". */ void shellReset( - int *pRc, - sqlite3_stmt *pStmt + int *pRc, + sqlite3_stmt *pStmt ){ - int rc = sqlite3_reset(pStmt); - if( *pRc==SQLITE_OK ){ - if( rc!=SQLITE_OK ){ - sqlite3 *db = sqlite3_db_handle(pStmt); - raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); - } - *pRc = rc; + int rc = sqlite3_reset(pStmt); + if( *pRc==SQLITE_OK ){ + if( rc!=SQLITE_OK ){ + sqlite3 *db = sqlite3_db_handle(pStmt); + raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } + *pRc = rc; + } } #endif /* !defined SQLITE_OMIT_VIRTUALTABLE */ @@ -17184,48 +17184,48 @@ void shellReset( */ typedef struct ArCommand ArCommand; struct ArCommand { - u8 eCmd; /* An AR_CMD_* value */ - u8 bVerbose; /* True if --verbose */ - u8 bZip; /* True if the archive is a ZIP */ - u8 bDryRun; /* True if --dry-run */ - u8 bAppend; /* True if --append */ - u8 bGlob; /* True if --glob */ - u8 fromCmdLine; /* Run from -A instead of .archive */ - int nArg; /* Number of command arguments */ - char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ - const char *zFile; /* --file argument, or NULL */ - const char *zDir; /* --directory argument, or NULL */ - char **azArg; /* Array of command arguments */ - ShellState *p; /* Shell state */ - sqlite3 *db; /* Database containing the archive */ + u8 eCmd; /* An AR_CMD_* value */ + u8 bVerbose; /* True if --verbose */ + u8 bZip; /* True if the archive is a ZIP */ + u8 bDryRun; /* True if --dry-run */ + u8 bAppend; /* True if --append */ + u8 bGlob; /* True if --glob */ + u8 fromCmdLine; /* Run from -A instead of .archive */ + int nArg; /* Number of command arguments */ + char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ + const char *zFile; /* --file argument, or NULL */ + const char *zDir; /* --directory argument, or NULL */ + char **azArg; /* Array of command arguments */ + ShellState *p; /* Shell state */ + sqlite3 *db; /* Database containing the archive */ }; /* ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR. */ static int arUsage(FILE *f){ - showHelp(f,"archive"); - return SQLITE_ERROR; + showHelp(f,"archive"); + return SQLITE_ERROR; } /* -** Print an error message for the .ar command to stderr and return +** Print an error message for the .ar command to stderr and return ** SQLITE_ERROR. */ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){ - va_list ap; - char *z; - va_start(ap, zFmt); - z = sqlite3_vmprintf(zFmt, ap); - va_end(ap); - utf8_printf(stderr, "Error: %s\n", z); - if( pAr->fromCmdLine ){ - utf8_printf(stderr, "Use \"-A\" for more help\n"); - }else{ - utf8_printf(stderr, "Use \".archive --help\" for more help\n"); - } - sqlite3_free(z); - return SQLITE_ERROR; + va_list ap; + char *z; + va_start(ap, zFmt); + z = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + utf8_printf(stderr, "Error: %s\n", z); + if( pAr->fromCmdLine ){ + utf8_printf(stderr, "Use \"-A\" for more help\n"); + }else{ + utf8_printf(stderr, "Use \".archive --help\" for more help\n"); + } + sqlite3_free(z); + return SQLITE_ERROR; } /* @@ -17250,185 +17250,185 @@ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){ #define AR_SWITCH_GLOB 13 static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ - switch( eSwitch ){ - case AR_CMD_CREATE: - case AR_CMD_EXTRACT: - case AR_CMD_LIST: - case AR_CMD_REMOVE: - case AR_CMD_UPDATE: - case AR_CMD_INSERT: - case AR_CMD_HELP: - if( pAr->eCmd ){ - return arErrorMsg(pAr, "multiple command options"); - } - pAr->eCmd = eSwitch; - break; - - case AR_SWITCH_DRYRUN: - pAr->bDryRun = 1; - break; - case AR_SWITCH_GLOB: - pAr->bGlob = 1; - break; - case AR_SWITCH_VERBOSE: - pAr->bVerbose = 1; - break; - case AR_SWITCH_APPEND: - pAr->bAppend = 1; - /* Fall thru into --file */ - case AR_SWITCH_FILE: - pAr->zFile = zArg; - break; - case AR_SWITCH_DIRECTORY: - pAr->zDir = zArg; - break; - } - - return SQLITE_OK; + switch( eSwitch ){ + case AR_CMD_CREATE: + case AR_CMD_EXTRACT: + case AR_CMD_LIST: + case AR_CMD_REMOVE: + case AR_CMD_UPDATE: + case AR_CMD_INSERT: + case AR_CMD_HELP: + if( pAr->eCmd ){ + return arErrorMsg(pAr, "multiple command options"); + } + pAr->eCmd = eSwitch; + break; + + case AR_SWITCH_DRYRUN: + pAr->bDryRun = 1; + break; + case AR_SWITCH_GLOB: + pAr->bGlob = 1; + break; + case AR_SWITCH_VERBOSE: + pAr->bVerbose = 1; + break; + case AR_SWITCH_APPEND: + pAr->bAppend = 1; + /* Fall thru into --file */ + case AR_SWITCH_FILE: + pAr->zFile = zArg; + break; + case AR_SWITCH_DIRECTORY: + pAr->zDir = zArg; + break; + } + + return SQLITE_OK; } /* ** Parse the command line for an ".ar" command. The results are written into ** structure (*pAr). SQLITE_OK is returned if the command line is parsed -** successfully, otherwise an error message is written to stderr and +** successfully, otherwise an error message is written to stderr and ** SQLITE_ERROR returned. */ static int arParseCommand( - char **azArg, /* Array of arguments passed to dot command */ - int nArg, /* Number of entries in azArg[] */ - ArCommand *pAr /* Populate this object */ + char **azArg, /* Array of arguments passed to dot command */ + int nArg, /* Number of entries in azArg[] */ + ArCommand *pAr /* Populate this object */ ){ - struct ArSwitch { - const char *zLong; - char cShort; - u8 eSwitch; - u8 bArg; - } aSwitch[] = { - { "create", 'c', AR_CMD_CREATE, 0 }, - { "extract", 'x', AR_CMD_EXTRACT, 0 }, - { "insert", 'i', AR_CMD_INSERT, 0 }, - { "list", 't', AR_CMD_LIST, 0 }, - { "remove", 'r', AR_CMD_REMOVE, 0 }, - { "update", 'u', AR_CMD_UPDATE, 0 }, - { "help", 'h', AR_CMD_HELP, 0 }, - { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, - { "file", 'f', AR_SWITCH_FILE, 1 }, - { "append", 'a', AR_SWITCH_APPEND, 1 }, - { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, - { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, - { "glob", 'g', AR_SWITCH_GLOB, 0 }, - }; - int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); - struct ArSwitch *pEnd = &aSwitch[nSwitch]; - - if( nArg<=1 ){ - utf8_printf(stderr, "Wrong number of arguments. Usage:\n"); - return arUsage(stderr); + struct ArSwitch { + const char *zLong; + char cShort; + u8 eSwitch; + u8 bArg; + } aSwitch[] = { + { "create", 'c', AR_CMD_CREATE, 0 }, + { "extract", 'x', AR_CMD_EXTRACT, 0 }, + { "insert", 'i', AR_CMD_INSERT, 0 }, + { "list", 't', AR_CMD_LIST, 0 }, + { "remove", 'r', AR_CMD_REMOVE, 0 }, + { "update", 'u', AR_CMD_UPDATE, 0 }, + { "help", 'h', AR_CMD_HELP, 0 }, + { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, + { "file", 'f', AR_SWITCH_FILE, 1 }, + { "append", 'a', AR_SWITCH_APPEND, 1 }, + { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, + { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, + { "glob", 'g', AR_SWITCH_GLOB, 0 }, + }; + int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); + struct ArSwitch *pEnd = &aSwitch[nSwitch]; + + if( nArg<=1 ){ + utf8_printf(stderr, "Wrong number of arguments. Usage:\n"); + return arUsage(stderr); + }else{ + char *z = azArg[1]; + if( z[0]!='-' ){ + /* Traditional style [tar] invocation */ + int i; + int iArg = 2; + for(i=0; z[i]; i++){ + const char *zArg = 0; + struct ArSwitch *pOpt; + for(pOpt=&aSwitch[0]; pOptcShort ) break; + } + if( pOpt==pEnd ){ + return arErrorMsg(pAr, "unrecognized option: %c", z[i]); + } + if( pOpt->bArg ){ + if( iArg>=nArg ){ + return arErrorMsg(pAr, "option requires an argument: %c",z[i]); + } + zArg = azArg[iArg++]; + } + if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; + } + pAr->nArg = nArg-iArg; + if( pAr->nArg>0 ){ + pAr->azArg = &azArg[iArg]; + } }else{ - char *z = azArg[1]; + /* Non-traditional invocation */ + int iArg; + for(iArg=1; iArgcShort ) break; - } - if( pOpt==pEnd ){ - return arErrorMsg(pAr, "unrecognized option: %c", z[i]); - } - if( pOpt->bArg ){ - if( iArg>=nArg ){ - return arErrorMsg(pAr, "option requires an argument: %c",z[i]); - } - zArg = azArg[iArg++]; + /* All remaining command line words are command arguments. */ + pAr->azArg = &azArg[iArg]; + pAr->nArg = nArg-iArg; + break; + } + n = strlen30(z); + + if( z[1]!='-' ){ + int i; + /* One or more short options */ + for(i=1; icShort ) break; + } + if( pOpt==pEnd ){ + return arErrorMsg(pAr, "unrecognized option: %c", z[i]); + } + if( pOpt->bArg ){ + if( i<(n-1) ){ + zArg = &z[i+1]; + i = n; + }else{ + if( iArg>=(nArg-1) ){ + return arErrorMsg(pAr, "option requires an argument: %c", + z[i]); } - if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; + zArg = azArg[++iArg]; + } } - pAr->nArg = nArg-iArg; - if( pAr->nArg>0 ){ - pAr->azArg = &azArg[iArg]; - } - }else{ - /* Non-traditional invocation */ - int iArg; - for(iArg=1; iArgazArg = &azArg[iArg]; - pAr->nArg = nArg-iArg; - break; - } - n = strlen30(z); - - if( z[1]!='-' ){ - int i; - /* One or more short options */ - for(i=1; icShort ) break; - } - if( pOpt==pEnd ){ - return arErrorMsg(pAr, "unrecognized option: %c", z[i]); - } - if( pOpt->bArg ){ - if( i<(n-1) ){ - zArg = &z[i+1]; - i = n; - }else{ - if( iArg>=(nArg-1) ){ - return arErrorMsg(pAr, "option requires an argument: %c", - z[i]); - } - zArg = azArg[++iArg]; - } - } - if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; - } - }else if( z[2]=='\0' ){ - /* A -- option, indicating that all remaining command line words + if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; + } + }else if( z[2]=='\0' ){ + /* A -- option, indicating that all remaining command line words ** are command arguments. */ - pAr->azArg = &azArg[iArg+1]; - pAr->nArg = nArg-iArg-1; - break; - }else{ - /* A long option */ - const char *zArg = 0; /* Argument for option, if any */ - struct ArSwitch *pMatch = 0; /* Matching option */ - struct ArSwitch *pOpt; /* Iterator */ - for(pOpt=&aSwitch[0]; pOptzLong; - if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){ - if( pMatch ){ - return arErrorMsg(pAr, "ambiguous option: %s",z); - }else{ - pMatch = pOpt; - } - } - } - - if( pMatch==0 ){ - return arErrorMsg(pAr, "unrecognized option: %s", z); - } - if( pMatch->bArg ){ - if( iArg>=(nArg-1) ){ - return arErrorMsg(pAr, "option requires an argument: %s", z); - } - zArg = azArg[++iArg]; - } - if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR; - } + pAr->azArg = &azArg[iArg+1]; + pAr->nArg = nArg-iArg-1; + break; + }else{ + /* A long option */ + const char *zArg = 0; /* Argument for option, if any */ + struct ArSwitch *pMatch = 0; /* Matching option */ + struct ArSwitch *pOpt; /* Iterator */ + for(pOpt=&aSwitch[0]; pOptzLong; + if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){ + if( pMatch ){ + return arErrorMsg(pAr, "ambiguous option: %s",z); + }else{ + pMatch = pOpt; + } + } + } + + if( pMatch==0 ){ + return arErrorMsg(pAr, "unrecognized option: %s", z); + } + if( pMatch->bArg ){ + if( iArg>=(nArg-1) ){ + return arErrorMsg(pAr, "option requires an argument: %s", z); } + zArg = azArg[++iArg]; + } + if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR; } + } } + } - return SQLITE_OK; + return SQLITE_OK; } /* @@ -17446,35 +17446,35 @@ static int arParseCommand( ** Linux. */ static int arCheckEntries(ArCommand *pAr){ - int rc = SQLITE_OK; - if( pAr->nArg ){ - int i, j; - sqlite3_stmt *pTest = 0; - const char *zSel = (pAr->bGlob) - ? "SELECT name FROM %s WHERE glob($name,name)" - : "SELECT name FROM %s WHERE name=$name"; - - shellPreparePrintf(pAr->db, &rc, &pTest, zSel, pAr->zSrcTable); - j = sqlite3_bind_parameter_index(pTest, "$name"); - for(i=0; inArg && rc==SQLITE_OK; i++){ - char *z = pAr->azArg[i]; - int n = strlen30(z); - int bOk = 0; - while( n>0 && z[n-1]=='/' ) n--; - z[n] = '\0'; - sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC); - if( SQLITE_ROW==sqlite3_step(pTest) ){ - bOk = 1; - } - shellReset(&rc, pTest); - if( rc==SQLITE_OK && bOk==0 ){ - utf8_printf(stderr, "not found in archive: %s\n", z); - rc = SQLITE_ERROR; - } - } - shellFinalize(&rc, pTest); + int rc = SQLITE_OK; + if( pAr->nArg ){ + int i, j; + sqlite3_stmt *pTest = 0; + const char *zSel = (pAr->bGlob) + ? "SELECT name FROM %s WHERE glob($name,name)" + : "SELECT name FROM %s WHERE name=$name"; + + shellPreparePrintf(pAr->db, &rc, &pTest, zSel, pAr->zSrcTable); + j = sqlite3_bind_parameter_index(pTest, "$name"); + for(i=0; inArg && rc==SQLITE_OK; i++){ + char *z = pAr->azArg[i]; + int n = strlen30(z); + int bOk = 0; + while( n>0 && z[n-1]=='/' ) n--; + z[n] = '\0'; + sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC); + if( SQLITE_ROW==sqlite3_step(pTest) ){ + bOk = 1; + } + shellReset(&rc, pTest); + if( rc==SQLITE_OK && bOk==0 ){ + utf8_printf(stderr, "not found in archive: %s\n", z); + rc = SQLITE_ERROR; + } } - return rc; + shellFinalize(&rc, pTest); + } + return rc; } /* @@ -17486,73 +17486,73 @@ static int arCheckEntries(ArCommand *pAr){ ** when pAr->bGlob is false and GLOB match when pAr->bGlob is true. */ static void arWhereClause( - int *pRc, - ArCommand *pAr, - char **pzWhere /* OUT: New WHERE clause */ + int *pRc, + ArCommand *pAr, + char **pzWhere /* OUT: New WHERE clause */ ){ - char *zWhere = 0; - const char *zSameOp = (pAr->bGlob)? "GLOB" : "="; - if( *pRc==SQLITE_OK ){ - if( pAr->nArg==0 ){ - zWhere = sqlite3_mprintf("1"); - }else{ - int i; - const char *zSep = ""; - for(i=0; inArg; i++){ - const char *z = pAr->azArg[i]; - zWhere = sqlite3_mprintf( - "%z%s name %s '%q' OR substr(name,1,%d) %s '%q/'", - zWhere, zSep, zSameOp, z, strlen30(z)+1, zSameOp, z - ); - if( zWhere==0 ){ - *pRc = SQLITE_NOMEM; - break; - } - zSep = " OR "; - } + char *zWhere = 0; + const char *zSameOp = (pAr->bGlob)? "GLOB" : "="; + if( *pRc==SQLITE_OK ){ + if( pAr->nArg==0 ){ + zWhere = sqlite3_mprintf("1"); + }else{ + int i; + const char *zSep = ""; + for(i=0; inArg; i++){ + const char *z = pAr->azArg[i]; + zWhere = sqlite3_mprintf( + "%z%s name %s '%q' OR substr(name,1,%d) %s '%q/'", + zWhere, zSep, zSameOp, z, strlen30(z)+1, zSameOp, z + ); + if( zWhere==0 ){ + *pRc = SQLITE_NOMEM; + break; } + zSep = " OR "; + } } - *pzWhere = zWhere; + } + *pzWhere = zWhere; } /* -** Implementation of .ar "lisT" command. +** Implementation of .ar "lisT" command. */ static int arListCommand(ArCommand *pAr){ - const char *zSql = "SELECT %s FROM %s WHERE %s"; - const char *azCols[] = { - "name", - "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name" - }; - - char *zWhere = 0; - sqlite3_stmt *pSql = 0; - int rc; - - rc = arCheckEntries(pAr); - arWhereClause(&rc, pAr, &zWhere); - - shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose], - pAr->zSrcTable, zWhere); - if( pAr->bDryRun ){ - utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); - }else{ - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ - if( pAr->bVerbose ){ - utf8_printf(pAr->p->out, "%s % 10d %s %s\n", - sqlite3_column_text(pSql, 0), - sqlite3_column_int(pSql, 1), - sqlite3_column_text(pSql, 2), - sqlite3_column_text(pSql, 3) - ); - }else{ - utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); - } - } + const char *zSql = "SELECT %s FROM %s WHERE %s"; + const char *azCols[] = { + "name", + "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name" + }; + + char *zWhere = 0; + sqlite3_stmt *pSql = 0; + int rc; + + rc = arCheckEntries(pAr); + arWhereClause(&rc, pAr, &zWhere); + + shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose], + pAr->zSrcTable, zWhere); + if( pAr->bDryRun ){ + utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); + }else{ + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ + if( pAr->bVerbose ){ + utf8_printf(pAr->p->out, "%s % 10d %s %s\n", + sqlite3_column_text(pSql, 0), + sqlite3_column_int(pSql, 1), + sqlite3_column_text(pSql, 2), + sqlite3_column_text(pSql, 3) + ); + }else{ + utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); + } } - shellFinalize(&rc, pSql); - sqlite3_free(zWhere); - return rc; + } + shellFinalize(&rc, pSql); + sqlite3_free(zWhere); + return rc; } @@ -17560,132 +17560,132 @@ static int arListCommand(ArCommand *pAr){ ** Implementation of .ar "Remove" command. */ static int arRemoveCommand(ArCommand *pAr){ - int rc = 0; - char *zSql = 0; - char *zWhere = 0; + int rc = 0; + char *zSql = 0; + char *zWhere = 0; - if( pAr->nArg ){ - /* Verify that args actually exist within the archive before proceeding. + if( pAr->nArg ){ + /* Verify that args actually exist within the archive before proceeding. ** And formulate a WHERE clause to match them. */ - rc = arCheckEntries(pAr); - arWhereClause(&rc, pAr, &zWhere); - } - if( rc==SQLITE_OK ){ - zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;", - pAr->zSrcTable, zWhere); - if( pAr->bDryRun ){ - utf8_printf(pAr->p->out, "%s\n", zSql); + rc = arCheckEntries(pAr); + arWhereClause(&rc, pAr, &zWhere); + } + if( rc==SQLITE_OK ){ + zSql = sqlite3_mprintf("DELETE FROM %s WHERE %s;", + pAr->zSrcTable, zWhere); + if( pAr->bDryRun ){ + utf8_printf(pAr->p->out, "%s\n", zSql); + }else{ + char *zErr = 0; + rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0); + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); + if( rc!=SQLITE_OK ){ + sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); }else{ - char *zErr = 0; - rc = sqlite3_exec(pAr->db, "SAVEPOINT ar;", 0, 0, 0); - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); - if( rc!=SQLITE_OK ){ - sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); - }else{ - rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0); - } - } - if( zErr ){ - utf8_printf(stdout, "ERROR: %s\n", zErr); - sqlite3_free(zErr); - } + rc = sqlite3_exec(pAr->db, "RELEASE ar;", 0, 0, 0); } + } + if( zErr ){ + utf8_printf(stdout, "ERROR: %s\n", zErr); + sqlite3_free(zErr); + } } - sqlite3_free(zWhere); - sqlite3_free(zSql); - return rc; + } + sqlite3_free(zWhere); + sqlite3_free(zSql); + return rc; } /* -** Implementation of .ar "eXtract" command. +** Implementation of .ar "eXtract" command. */ static int arExtractCommand(ArCommand *pAr){ - const char *zSql1 = - "SELECT " - " ($dir || name)," - " writefile(($dir || name), %s, mode, mtime) " - "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)" - " AND name NOT GLOB '*..[/\\]*'"; - - const char *azExtraArg[] = { - "sqlar_uncompress(data, sz)", - "data" - }; - - sqlite3_stmt *pSql = 0; - int rc = SQLITE_OK; - char *zDir = 0; - char *zWhere = 0; - int i, j; - - /* If arguments are specified, check that they actually exist within + const char *zSql1 = + "SELECT " + " ($dir || name)," + " writefile(($dir || name), %s, mode, mtime) " + "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)" + " AND name NOT GLOB '*..[/\\]*'"; + + const char *azExtraArg[] = { + "sqlar_uncompress(data, sz)", + "data" + }; + + sqlite3_stmt *pSql = 0; + int rc = SQLITE_OK; + char *zDir = 0; + char *zWhere = 0; + int i, j; + + /* If arguments are specified, check that they actually exist within ** the archive before proceeding. And formulate a WHERE clause to ** match them. */ - rc = arCheckEntries(pAr); - arWhereClause(&rc, pAr, &zWhere); + rc = arCheckEntries(pAr); + arWhereClause(&rc, pAr, &zWhere); - if( rc==SQLITE_OK ){ - if( pAr->zDir ){ - zDir = sqlite3_mprintf("%s/", pAr->zDir); - }else{ - zDir = sqlite3_mprintf(""); - } - if( zDir==0 ) rc = SQLITE_NOMEM; + if( rc==SQLITE_OK ){ + if( pAr->zDir ){ + zDir = sqlite3_mprintf("%s/", pAr->zDir); + }else{ + zDir = sqlite3_mprintf(""); } + if( zDir==0 ) rc = SQLITE_NOMEM; + } - shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, - azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere - ); + shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, + azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere + ); - if( rc==SQLITE_OK ){ - j = sqlite3_bind_parameter_index(pSql, "$dir"); - sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); + if( rc==SQLITE_OK ){ + j = sqlite3_bind_parameter_index(pSql, "$dir"); + sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); - /* Run the SELECT statement twice. The first time, writefile() is called + /* Run the SELECT statement twice. The first time, writefile() is called ** for all archive members that should be extracted. The second time, ** only for the directories. This is because the timestamps for ** extracted directories must be reset after they are populated (as ** populating them changes the timestamp). */ - for(i=0; i<2; i++){ - j = sqlite3_bind_parameter_index(pSql, "$dirOnly"); - sqlite3_bind_int(pSql, j, i); - if( pAr->bDryRun ){ - utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); - }else{ - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ - if( i==0 && pAr->bVerbose ){ - utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); - } - } - } - shellReset(&rc, pSql); + for(i=0; i<2; i++){ + j = sqlite3_bind_parameter_index(pSql, "$dirOnly"); + sqlite3_bind_int(pSql, j, i); + if( pAr->bDryRun ){ + utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); + }else{ + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ + if( i==0 && pAr->bVerbose ){ + utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); + } } - shellFinalize(&rc, pSql); + } + shellReset(&rc, pSql); } + shellFinalize(&rc, pSql); + } - sqlite3_free(zDir); - sqlite3_free(zWhere); - return rc; + sqlite3_free(zDir); + sqlite3_free(zWhere); + return rc; } /* ** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out. */ static int arExecSql(ArCommand *pAr, const char *zSql){ - int rc; - if( pAr->bDryRun ){ - utf8_printf(pAr->p->out, "%s\n", zSql); - rc = SQLITE_OK; - }else{ - char *zErr = 0; - rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); - if( zErr ){ - utf8_printf(stdout, "ERROR: %s\n", zErr); - sqlite3_free(zErr); - } + int rc; + if( pAr->bDryRun ){ + utf8_printf(pAr->p->out, "%s\n", zSql); + rc = SQLITE_OK; + }else{ + char *zErr = 0; + rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); + if( zErr ){ + utf8_printf(stdout, "ERROR: %s\n", zErr); + sqlite3_free(zErr); } - return rc; + } + return rc; } @@ -17708,220 +17708,220 @@ static int arExecSql(ArCommand *pAr, const char *zSql){ ** "update" only overwrites if the size or mtime or mode has changed. */ static int arCreateOrUpdateCommand( - ArCommand *pAr, /* Command arguments and options */ - int bUpdate, /* true for a --create. */ - int bOnlyIfChanged /* Only update if file has changed */ + ArCommand *pAr, /* Command arguments and options */ + int bUpdate, /* true for a --create. */ + int bOnlyIfChanged /* Only update if file has changed */ ){ - const char *zCreate = - "CREATE TABLE IF NOT EXISTS sqlar(\n" - " name TEXT PRIMARY KEY, -- name of the file\n" - " mode INT, -- access permissions\n" - " mtime INT, -- last modification time\n" - " sz INT, -- original file size\n" - " data BLOB -- compressed content\n" - ")"; - const char *zDrop = "DROP TABLE IF EXISTS sqlar"; - const char *zInsertFmt[2] = { - "REPLACE INTO %s(name,mode,mtime,sz,data)\n" - " SELECT\n" - " %s,\n" - " mode,\n" - " mtime,\n" - " CASE substr(lsmode(mode),1,1)\n" - " WHEN '-' THEN length(data)\n" - " WHEN 'd' THEN 0\n" - " ELSE -1 END,\n" - " sqlar_compress(data)\n" - " FROM fsdir(%Q,%Q) AS disk\n" - " WHERE lsmode(mode) NOT LIKE '?%%'%s;" - , - "REPLACE INTO %s(name,mode,mtime,data)\n" - " SELECT\n" - " %s,\n" - " mode,\n" - " mtime,\n" - " data\n" - " FROM fsdir(%Q,%Q) AS disk\n" - " WHERE lsmode(mode) NOT LIKE '?%%'%s;" - }; - int i; /* For iterating through azFile[] */ - int rc; /* Return code */ - const char *zTab = 0; /* SQL table into which to insert */ - char *zSql; - char zTemp[50]; - char *zExists = 0; - - arExecSql(pAr, "PRAGMA page_size=512"); - rc = arExecSql(pAr, "SAVEPOINT ar;"); - if( rc!=SQLITE_OK ) return rc; - zTemp[0] = 0; - if( pAr->bZip ){ - /* Initialize the zipfile virtual table, if necessary */ - if( pAr->zFile ){ - sqlite3_uint64 r; - sqlite3_randomness(sizeof(r),&r); - sqlite3_snprintf(sizeof(zTemp),zTemp,"zip%016llx",r); - zTab = zTemp; - zSql = sqlite3_mprintf( - "CREATE VIRTUAL TABLE temp.%s USING zipfile(%Q)", - zTab, pAr->zFile - ); - rc = arExecSql(pAr, zSql); - sqlite3_free(zSql); - }else{ - zTab = "zip"; - } + const char *zCreate = + "CREATE TABLE IF NOT EXISTS sqlar(\n" + " name TEXT PRIMARY KEY, -- name of the file\n" + " mode INT, -- access permissions\n" + " mtime INT, -- last modification time\n" + " sz INT, -- original file size\n" + " data BLOB -- compressed content\n" + ")"; + const char *zDrop = "DROP TABLE IF EXISTS sqlar"; + const char *zInsertFmt[2] = { + "REPLACE INTO %s(name,mode,mtime,sz,data)\n" + " SELECT\n" + " %s,\n" + " mode,\n" + " mtime,\n" + " CASE substr(lsmode(mode),1,1)\n" + " WHEN '-' THEN length(data)\n" + " WHEN 'd' THEN 0\n" + " ELSE -1 END,\n" + " sqlar_compress(data)\n" + " FROM fsdir(%Q,%Q) AS disk\n" + " WHERE lsmode(mode) NOT LIKE '?%%'%s;" + , + "REPLACE INTO %s(name,mode,mtime,data)\n" + " SELECT\n" + " %s,\n" + " mode,\n" + " mtime,\n" + " data\n" + " FROM fsdir(%Q,%Q) AS disk\n" + " WHERE lsmode(mode) NOT LIKE '?%%'%s;" + }; + int i; /* For iterating through azFile[] */ + int rc; /* Return code */ + const char *zTab = 0; /* SQL table into which to insert */ + char *zSql; + char zTemp[50]; + char *zExists = 0; + + arExecSql(pAr, "PRAGMA page_size=512"); + rc = arExecSql(pAr, "SAVEPOINT ar;"); + if( rc!=SQLITE_OK ) return rc; + zTemp[0] = 0; + if( pAr->bZip ){ + /* Initialize the zipfile virtual table, if necessary */ + if( pAr->zFile ){ + sqlite3_uint64 r; + sqlite3_randomness(sizeof(r),&r); + sqlite3_snprintf(sizeof(zTemp),zTemp,"zip%016llx",r); + zTab = zTemp; + zSql = sqlite3_mprintf( + "CREATE VIRTUAL TABLE temp.%s USING zipfile(%Q)", + zTab, pAr->zFile + ); + rc = arExecSql(pAr, zSql); + sqlite3_free(zSql); }else{ - /* Initialize the table for an SQLAR */ - zTab = "sqlar"; - if( bUpdate==0 ){ - rc = arExecSql(pAr, zDrop); - if( rc!=SQLITE_OK ) goto end_ar_transaction; - } - rc = arExecSql(pAr, zCreate); - } - if( bOnlyIfChanged ){ - zExists = sqlite3_mprintf( - " AND NOT EXISTS(" - "SELECT 1 FROM %s AS mem" - " WHERE mem.name=disk.name" - " AND mem.mtime=disk.mtime" - " AND mem.mode=disk.mode)", zTab); - }else{ - zExists = sqlite3_mprintf(""); - } - if( zExists==0 ) rc = SQLITE_NOMEM; - for(i=0; inArg && rc==SQLITE_OK; i++){ - char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab, - pAr->bVerbose ? "shell_putsnl(name)" : "name", - pAr->azArg[i], pAr->zDir, zExists); - rc = arExecSql(pAr, zSql2); - sqlite3_free(zSql2); - } + zTab = "zip"; + } + }else{ + /* Initialize the table for an SQLAR */ + zTab = "sqlar"; + if( bUpdate==0 ){ + rc = arExecSql(pAr, zDrop); + if( rc!=SQLITE_OK ) goto end_ar_transaction; + } + rc = arExecSql(pAr, zCreate); + } + if( bOnlyIfChanged ){ + zExists = sqlite3_mprintf( + " AND NOT EXISTS(" + "SELECT 1 FROM %s AS mem" + " WHERE mem.name=disk.name" + " AND mem.mtime=disk.mtime" + " AND mem.mode=disk.mode)", zTab); + }else{ + zExists = sqlite3_mprintf(""); + } + if( zExists==0 ) rc = SQLITE_NOMEM; + for(i=0; inArg && rc==SQLITE_OK; i++){ + char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab, + pAr->bVerbose ? "shell_putsnl(name)" : "name", + pAr->azArg[i], pAr->zDir, zExists); + rc = arExecSql(pAr, zSql2); + sqlite3_free(zSql2); + } end_ar_transaction: - if( rc!=SQLITE_OK ){ - sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); - }else{ - rc = arExecSql(pAr, "RELEASE ar;"); - if( pAr->bZip && pAr->zFile ){ - zSql = sqlite3_mprintf("DROP TABLE %s", zTemp); - arExecSql(pAr, zSql); - sqlite3_free(zSql); - } + if( rc!=SQLITE_OK ){ + sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); + }else{ + rc = arExecSql(pAr, "RELEASE ar;"); + if( pAr->bZip && pAr->zFile ){ + zSql = sqlite3_mprintf("DROP TABLE %s", zTemp); + arExecSql(pAr, zSql); + sqlite3_free(zSql); } - sqlite3_free(zExists); - return rc; + } + sqlite3_free(zExists); + return rc; } /* ** Implementation of ".ar" dot command. */ static int arDotCommand( - ShellState *pState, /* Current shell tool state */ - int fromCmdLine, /* True if -A command-line option, not .ar cmd */ - char **azArg, /* Array of arguments passed to dot command */ - int nArg /* Number of entries in azArg[] */ + ShellState *pState, /* Current shell tool state */ + int fromCmdLine, /* True if -A command-line option, not .ar cmd */ + char **azArg, /* Array of arguments passed to dot command */ + int nArg /* Number of entries in azArg[] */ ){ - ArCommand cmd; - int rc; - memset(&cmd, 0, sizeof(cmd)); - cmd.fromCmdLine = fromCmdLine; - rc = arParseCommand(azArg, nArg, &cmd); - if( rc==SQLITE_OK ){ - int eDbType = SHELL_OPEN_UNSPEC; - cmd.p = pState; - cmd.db = pState->db; - if( cmd.zFile ){ - eDbType = deduceDatabaseType(cmd.zFile, 1); + ArCommand cmd; + int rc; + memset(&cmd, 0, sizeof(cmd)); + cmd.fromCmdLine = fromCmdLine; + rc = arParseCommand(azArg, nArg, &cmd); + if( rc==SQLITE_OK ){ + int eDbType = SHELL_OPEN_UNSPEC; + cmd.p = pState; + cmd.db = pState->db; + if( cmd.zFile ){ + eDbType = deduceDatabaseType(cmd.zFile, 1); + }else{ + eDbType = pState->openMode; + } + if( eDbType==SHELL_OPEN_ZIPFILE ){ + if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){ + if( cmd.zFile==0 ){ + cmd.zSrcTable = sqlite3_mprintf("zip"); }else{ - eDbType = pState->openMode; - } - if( eDbType==SHELL_OPEN_ZIPFILE ){ - if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){ - if( cmd.zFile==0 ){ - cmd.zSrcTable = sqlite3_mprintf("zip"); - }else{ - cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); - } - } - cmd.bZip = 1; - }else if( cmd.zFile ){ - int flags; - if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; - if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT - || cmd.eCmd==AR_CMD_REMOVE || cmd.eCmd==AR_CMD_UPDATE ){ - flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; - }else{ - flags = SQLITE_OPEN_READONLY; - } - cmd.db = 0; - if( cmd.bDryRun ){ - utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile, - eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : ""); - } - rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, - eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0); - if( rc!=SQLITE_OK ){ - utf8_printf(stderr, "cannot open file: %s (%s)\n", - cmd.zFile, sqlite3_errmsg(cmd.db) - ); - goto end_ar_command; - } - sqlite3_fileio_init(cmd.db, 0, 0); - sqlite3_sqlar_init(cmd.db, 0, 0); - sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, - shellPutsFunc, 0, 0); - - } - if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){ - if( cmd.eCmd!=AR_CMD_CREATE - && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0) - ){ - utf8_printf(stderr, "database does not contain an 'sqlar' table\n"); - rc = SQLITE_ERROR; - goto end_ar_command; - } - cmd.zSrcTable = sqlite3_mprintf("sqlar"); - } + cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); + } + } + cmd.bZip = 1; + }else if( cmd.zFile ){ + int flags; + if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; + if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT + || cmd.eCmd==AR_CMD_REMOVE || cmd.eCmd==AR_CMD_UPDATE ){ + flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; + }else{ + flags = SQLITE_OPEN_READONLY; + } + cmd.db = 0; + if( cmd.bDryRun ){ + utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile, + eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : ""); + } + rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, + eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0); + if( rc!=SQLITE_OK ){ + utf8_printf(stderr, "cannot open file: %s (%s)\n", + cmd.zFile, sqlite3_errmsg(cmd.db) + ); + goto end_ar_command; + } + sqlite3_fileio_init(cmd.db, 0, 0); + sqlite3_sqlar_init(cmd.db, 0, 0); + sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, + shellPutsFunc, 0, 0); + + } + if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){ + if( cmd.eCmd!=AR_CMD_CREATE + && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0) + ){ + utf8_printf(stderr, "database does not contain an 'sqlar' table\n"); + rc = SQLITE_ERROR; + goto end_ar_command; + } + cmd.zSrcTable = sqlite3_mprintf("sqlar"); + } - switch( cmd.eCmd ){ - case AR_CMD_CREATE: - rc = arCreateOrUpdateCommand(&cmd, 0, 0); - break; + switch( cmd.eCmd ){ + case AR_CMD_CREATE: + rc = arCreateOrUpdateCommand(&cmd, 0, 0); + break; - case AR_CMD_EXTRACT: - rc = arExtractCommand(&cmd); - break; + case AR_CMD_EXTRACT: + rc = arExtractCommand(&cmd); + break; - case AR_CMD_LIST: - rc = arListCommand(&cmd); - break; + case AR_CMD_LIST: + rc = arListCommand(&cmd); + break; - case AR_CMD_HELP: - arUsage(pState->out); - break; + case AR_CMD_HELP: + arUsage(pState->out); + break; - case AR_CMD_INSERT: - rc = arCreateOrUpdateCommand(&cmd, 1, 0); - break; + case AR_CMD_INSERT: + rc = arCreateOrUpdateCommand(&cmd, 1, 0); + break; - case AR_CMD_REMOVE: - rc = arRemoveCommand(&cmd); - break; + case AR_CMD_REMOVE: + rc = arRemoveCommand(&cmd); + break; - default: - assert( cmd.eCmd==AR_CMD_UPDATE ); - rc = arCreateOrUpdateCommand(&cmd, 1, 1); - break; - } + default: + assert( cmd.eCmd==AR_CMD_UPDATE ); + rc = arCreateOrUpdateCommand(&cmd, 1, 1); + break; } + } end_ar_command: - if( cmd.db!=pState->db ){ - close_db(cmd.db); - } - sqlite3_free(cmd.zSrcTable); + if( cmd.db!=pState->db ){ + close_db(cmd.db); + } + sqlite3_free(cmd.zSrcTable); - return rc; + return rc; } /* End of the ".archive" or ".ar" command logic *******************************************************************************/ @@ -17935,35 +17935,35 @@ end_ar_command: ** this function returns. */ static void shellExec(sqlite3 *db, int *pRc, const char *zSql){ - int rc = *pRc; - if( rc==SQLITE_OK ){ - char *zErr = 0; - rc = sqlite3_exec(db, zSql, 0, 0, &zErr); - if( rc!=SQLITE_OK ){ - raw_printf(stderr, "SQL error: %s\n", zErr); - } - sqlite3_free(zErr); - *pRc = rc; + int rc = *pRc; + if( rc==SQLITE_OK ){ + char *zErr = 0; + rc = sqlite3_exec(db, zSql, 0, 0, &zErr); + if( rc!=SQLITE_OK ){ + raw_printf(stderr, "SQL error: %s\n", zErr); } + sqlite3_free(zErr); + *pRc = rc; + } } /* ** Like shellExec(), except that zFmt is a printf() style format string. */ static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){ - char *z = 0; - if( *pRc==SQLITE_OK ){ - va_list ap; - va_start(ap, zFmt); - z = sqlite3_vmprintf(zFmt, ap); - va_end(ap); - if( z==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - shellExec(db, pRc, z); - } - sqlite3_free(z); + char *z = 0; + if( *pRc==SQLITE_OK ){ + va_list ap; + va_start(ap, zFmt); + z = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( z==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + shellExec(db, pRc, z); } + sqlite3_free(z); + } } /* @@ -17973,41 +17973,41 @@ static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){ ** to SQLITE_NOMEM and NULL returned. */ static void *shellMalloc(int *pRc, sqlite3_int64 nByte){ - void *pRet = 0; - if( *pRc==SQLITE_OK ){ - pRet = sqlite3_malloc64(nByte); - if( pRet==0 ){ - *pRc = SQLITE_NOMEM; - }else{ - memset(pRet, 0, nByte); - } + void *pRet = 0; + if( *pRc==SQLITE_OK ){ + pRet = sqlite3_malloc64(nByte); + if( pRet==0 ){ + *pRc = SQLITE_NOMEM; + }else{ + memset(pRet, 0, nByte); } - return pRet; + } + return pRet; } /* ** If *pRc is not SQLITE_OK when this function is called, it is a no-op. ** Otherwise, zFmt is treated as a printf() style string. The result of -** formatting it along with any trailing arguments is written into a +** formatting it along with any trailing arguments is written into a ** buffer obtained from sqlite3_malloc(), and pointer to which is returned. ** It is the responsibility of the caller to eventually free this buffer ** using a call to sqlite3_free(). -** -** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL +** +** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL ** pointer returned. */ static char *shellMPrintf(int *pRc, const char *zFmt, ...){ - char *z = 0; - if( *pRc==SQLITE_OK ){ - va_list ap; - va_start(ap, zFmt); - z = sqlite3_vmprintf(zFmt, ap); - va_end(ap); - if( z==0 ){ - *pRc = SQLITE_NOMEM; - } + char *z = 0; + if( *pRc==SQLITE_OK ){ + va_list ap; + va_start(ap, zFmt); + z = sqlite3_vmprintf(zFmt, ap); + va_end(ap); + if( z==0 ){ + *pRc = SQLITE_NOMEM; } - return z; + } + return z; } /* @@ -18017,10 +18017,10 @@ static char *shellMPrintf(int *pRc, const char *zFmt, ...){ */ typedef struct RecoverTable RecoverTable; struct RecoverTable { - char *zQuoted; /* Quoted version of table name */ - int nCol; /* Number of columns in table */ - char **azlCol; /* Array of column lists */ - int iPk; /* Index of IPK column */ + char *zQuoted; /* Quoted version of table name */ + int nCol; /* Number of columns in table */ + char **azlCol; /* Array of column lists */ + int iPk; /* Index of IPK column */ }; /* @@ -18028,17 +18028,17 @@ struct RecoverTable { ** recoverOrphanTable(). */ static void recoverFreeTable(RecoverTable *pTab){ - if( pTab ){ - sqlite3_free(pTab->zQuoted); - if( pTab->azlCol ){ - int i; - for(i=0; i<=pTab->nCol; i++){ - sqlite3_free(pTab->azlCol[i]); - } - sqlite3_free(pTab->azlCol); - } - sqlite3_free(pTab); + if( pTab ){ + sqlite3_free(pTab->zQuoted); + if( pTab->azlCol ){ + int i; + for(i=0; i<=pTab->nCol; i++){ + sqlite3_free(pTab->azlCol[i]); + } + sqlite3_free(pTab->azlCol); } + sqlite3_free(pTab); + } } /* @@ -18049,120 +18049,120 @@ static void recoverFreeTable(RecoverTable *pTab){ ** recoverFreeTable(). */ static RecoverTable *recoverNewTable( - int *pRc, /* IN/OUT: Error code */ - const char *zName, /* Name of table */ - const char *zSql, /* CREATE TABLE statement */ - int bIntkey, - int nCol + int *pRc, /* IN/OUT: Error code */ + const char *zName, /* Name of table */ + const char *zSql, /* CREATE TABLE statement */ + int bIntkey, + int nCol ){ - sqlite3 *dbtmp = 0; /* sqlite3 handle for testing CREATE TABLE */ - int rc = *pRc; - RecoverTable *pTab = 0; - - pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable)); + sqlite3 *dbtmp = 0; /* sqlite3 handle for testing CREATE TABLE */ + int rc = *pRc; + RecoverTable *pTab = 0; + + pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable)); + if( rc==SQLITE_OK ){ + int nSqlCol = 0; + int bSqlIntkey = 0; + sqlite3_stmt *pStmt = 0; + + rc = sqlite3_open("", &dbtmp); if( rc==SQLITE_OK ){ - int nSqlCol = 0; - int bSqlIntkey = 0; - sqlite3_stmt *pStmt = 0; - - rc = sqlite3_open("", &dbtmp); - if( rc==SQLITE_OK ){ - sqlite3_create_function(dbtmp, "shell_idquote", 1, SQLITE_UTF8, 0, - shellIdQuote, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0); - } - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0); - if( rc==SQLITE_ERROR ){ - rc = SQLITE_OK; - goto finished; - } - } - shellPreparePrintf(dbtmp, &rc, &pStmt, - "SELECT count(*) FROM pragma_table_info(%Q)", zName - ); - if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - nSqlCol = sqlite3_column_int(pStmt, 0); - } - shellFinalize(&rc, pStmt); + sqlite3_create_function(dbtmp, "shell_idquote", 1, SQLITE_UTF8, 0, + shellIdQuote, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0); + } + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0); + if( rc==SQLITE_ERROR ){ + rc = SQLITE_OK; + goto finished; + } + } + shellPreparePrintf(dbtmp, &rc, &pStmt, + "SELECT count(*) FROM pragma_table_info(%Q)", zName + ); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + nSqlCol = sqlite3_column_int(pStmt, 0); + } + shellFinalize(&rc, pStmt); - if( rc!=SQLITE_OK || nSqlColiPk to the index ** of the column, where columns are 0-numbered from left to right. ** Or, if this is a WITHOUT ROWID table or if there is no IPK column, ** leave zPk as "_rowid_" and pTab->iPk at -2. */ - pTab->iPk = -2; - if( bIntkey ){ - shellPreparePrintf(dbtmp, &rc, &pPkFinder, - "SELECT cid, name FROM pragma_table_info(%Q) " - " WHERE pk=1 AND type='integer' COLLATE nocase" - " AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)" - , zName, zName - ); - if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){ - pTab->iPk = sqlite3_column_int(pPkFinder, 0); - zPk = (const char*)sqlite3_column_text(pPkFinder, 1); - } - } - - pTab->zQuoted = shellMPrintf(&rc, "\"%w\"", zName); - pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1)); - pTab->nCol = nSqlCol; - - if( bIntkey ){ - pTab->azlCol[0] = shellMPrintf(&rc, "\"%w\"", zPk); - }else{ - pTab->azlCol[0] = shellMPrintf(&rc, ""); - } - i = 1; - shellPreparePrintf(dbtmp, &rc, &pStmt, - "SELECT %Q || group_concat(shell_idquote(name), ', ') " - " FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) " - "FROM pragma_table_info(%Q)", - bIntkey ? ", " : "", pTab->iPk, - bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ", - zName - ); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *zText = (const char*)sqlite3_column_text(pStmt, 0); - pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText); - i++; - } - shellFinalize(&rc, pStmt); + pTab->iPk = -2; + if( bIntkey ){ + shellPreparePrintf(dbtmp, &rc, &pPkFinder, + "SELECT cid, name FROM pragma_table_info(%Q) " + " WHERE pk=1 AND type='integer' COLLATE nocase" + " AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)" + , zName, zName + ); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){ + pTab->iPk = sqlite3_column_int(pPkFinder, 0); + zPk = (const char*)sqlite3_column_text(pPkFinder, 1); + } + } + + pTab->zQuoted = shellMPrintf(&rc, "\"%w\"", zName); + pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1)); + pTab->nCol = nSqlCol; + + if( bIntkey ){ + pTab->azlCol[0] = shellMPrintf(&rc, "\"%w\"", zPk); + }else{ + pTab->azlCol[0] = shellMPrintf(&rc, ""); + } + i = 1; + shellPreparePrintf(dbtmp, &rc, &pStmt, + "SELECT %Q || group_concat(shell_idquote(name), ', ') " + " FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) " + "FROM pragma_table_info(%Q)", + bIntkey ? ", " : "", pTab->iPk, + bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ", + zName + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zText = (const char*)sqlite3_column_text(pStmt, 0); + pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText); + i++; + } + shellFinalize(&rc, pStmt); - shellFinalize(&rc, pPkFinder); - } + shellFinalize(&rc, pPkFinder); } + } -finished: - sqlite3_close(dbtmp); - *pRc = rc; - if( rc!=SQLITE_OK || (pTab && pTab->zQuoted==0) ){ - recoverFreeTable(pTab); - pTab = 0; - } - return pTab; + finished: + sqlite3_close(dbtmp); + *pRc = rc; + if( rc!=SQLITE_OK || (pTab && pTab->zQuoted==0) ){ + recoverFreeTable(pTab); + pTab = 0; + } + return pTab; } /* @@ -18174,113 +18174,113 @@ finished: ** those. ** ** If a table is found, a (RecoverTable*) object is returned. Or, if -** no such table is found, but bIntkey is false and iRoot is the +** no such table is found, but bIntkey is false and iRoot is the ** root page of an index in the recovered schema, then (*pbNoop) is ** set to true and NULL returned. Or, if there is no such table or ** index, NULL is returned and (*pbNoop) set to 0, indicating that ** the caller should write data to the orphans table. */ static RecoverTable *recoverFindTable( - ShellState *pState, /* Shell state object */ - int *pRc, /* IN/OUT: Error code */ - int iRoot, /* Root page of table */ - int bIntkey, /* True for an intkey table */ - int nCol, /* Number of columns in table */ - int *pbNoop /* OUT: True if iRoot is root of index */ + ShellState *pState, /* Shell state object */ + int *pRc, /* IN/OUT: Error code */ + int iRoot, /* Root page of table */ + int bIntkey, /* True for an intkey table */ + int nCol, /* Number of columns in table */ + int *pbNoop /* OUT: True if iRoot is root of index */ ){ - sqlite3_stmt *pStmt = 0; - RecoverTable *pRet = 0; - int bNoop = 0; - const char *zSql = 0; - const char *zName = 0; + sqlite3_stmt *pStmt = 0; + RecoverTable *pRet = 0; + int bNoop = 0; + const char *zSql = 0; + const char *zName = 0; - /* Search the recovered schema for an object with root page iRoot. */ - shellPreparePrintf(pState->db, pRc, &pStmt, - "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot - ); - while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *zType = (const char*)sqlite3_column_text(pStmt, 0); - if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){ - bNoop = 1; - break; - } - if( sqlite3_stricmp(zType, "table")==0 ){ - zName = (const char*)sqlite3_column_text(pStmt, 1); - zSql = (const char*)sqlite3_column_text(pStmt, 2); - pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol); - break; - } + /* Search the recovered schema for an object with root page iRoot. */ + shellPreparePrintf(pState->db, pRc, &pStmt, + "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot + ); + while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zType = (const char*)sqlite3_column_text(pStmt, 0); + if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){ + bNoop = 1; + break; + } + if( sqlite3_stricmp(zType, "table")==0 ){ + zName = (const char*)sqlite3_column_text(pStmt, 1); + zSql = (const char*)sqlite3_column_text(pStmt, 2); + pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol); + break; } + } - shellFinalize(pRc, pStmt); - *pbNoop = bNoop; - return pRet; + shellFinalize(pRc, pStmt); + *pbNoop = bNoop; + return pRet; } /* ** Return a RecoverTable object representing the orphans table. */ static RecoverTable *recoverOrphanTable( - ShellState *pState, /* Shell state object */ - int *pRc, /* IN/OUT: Error code */ - const char *zLostAndFound, /* Base name for orphans table */ - int nCol /* Number of user data columns */ + ShellState *pState, /* Shell state object */ + int *pRc, /* IN/OUT: Error code */ + const char *zLostAndFound, /* Base name for orphans table */ + int nCol /* Number of user data columns */ ){ - RecoverTable *pTab = 0; - if( nCol>=0 && *pRc==SQLITE_OK ){ - int i; + RecoverTable *pTab = 0; + if( nCol>=0 && *pRc==SQLITE_OK ){ + int i; - /* This block determines the name of the orphan table. The prefered + /* This block determines the name of the orphan table. The prefered ** name is zLostAndFound. But if that clashes with another name ** in the recovered schema, try zLostAndFound_0, zLostAndFound_1 ** and so on until a non-clashing name is found. */ - int iTab = 0; - char *zTab = shellMPrintf(pRc, "%s", zLostAndFound); - sqlite3_stmt *pTest = 0; - shellPrepare(pState->db, pRc, - "SELECT 1 FROM recovery.schema WHERE name=?", &pTest - ); - if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); - while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){ - shellReset(pRc, pTest); - sqlite3_free(zTab); - zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++); - sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); + int iTab = 0; + char *zTab = shellMPrintf(pRc, "%s", zLostAndFound); + sqlite3_stmt *pTest = 0; + shellPrepare(pState->db, pRc, + "SELECT 1 FROM recovery.schema WHERE name=?", &pTest + ); + if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); + while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){ + shellReset(pRc, pTest); + sqlite3_free(zTab); + zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++); + sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT); + } + shellFinalize(pRc, pTest); + + pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable)); + if( pTab ){ + pTab->zQuoted = shellMPrintf(pRc, "\"%w\"", zTab); + pTab->nCol = nCol; + pTab->iPk = -2; + if( nCol>0 ){ + pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1)); + if( pTab->azlCol ){ + pTab->azlCol[nCol] = shellMPrintf(pRc, ""); + for(i=nCol-1; i>=0; i--){ + pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]); + } } - shellFinalize(pRc, pTest); - - pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable)); - if( pTab ){ - pTab->zQuoted = shellMPrintf(pRc, "\"%w\"", zTab); - pTab->nCol = nCol; - pTab->iPk = -2; - if( nCol>0 ){ - pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1)); - if( pTab->azlCol ){ - pTab->azlCol[nCol] = shellMPrintf(pRc, ""); - for(i=nCol-1; i>=0; i--){ - pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]); - } - } - } + } - if( *pRc!=SQLITE_OK ){ - recoverFreeTable(pTab); - pTab = 0; - }else{ - raw_printf(pState->out, - "CREATE TABLE %s(rootpgno INTEGER, " - "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted - ); - for(i=0; iout, ", c%d", i); - } - raw_printf(pState->out, ");\n"); - } + if( *pRc!=SQLITE_OK ){ + recoverFreeTable(pTab); + pTab = 0; + }else{ + raw_printf(pState->out, + "CREATE TABLE %s(rootpgno INTEGER, " + "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted + ); + for(i=0; iout, ", c%d", i); } - sqlite3_free(zTab); + raw_printf(pState->out, ");\n"); + } } - return pTab; + sqlite3_free(zTab); + } + return pTab; } /* @@ -18289,317 +18289,317 @@ static RecoverTable *recoverOrphanTable( ** on stream pState->out. */ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ - int rc = SQLITE_OK; - sqlite3_stmt *pLoop = 0; /* Loop through all root pages */ - sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */ - sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */ - const char *zRecoveryDb = ""; /* Name of "recovery" database */ - const char *zLostAndFound = "lost_and_found"; - int i; - int nOrphan = -1; - RecoverTable *pOrphan = 0; - - int bFreelist = 1; /* 0 if --freelist-corrupt is specified */ - int bRowids = 1; /* 0 if --no-rowids */ - for(i=1; iout, azArg[0]); - return 1; - } + int rc = SQLITE_OK; + sqlite3_stmt *pLoop = 0; /* Loop through all root pages */ + sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */ + sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */ + const char *zRecoveryDb = ""; /* Name of "recovery" database */ + const char *zLostAndFound = "lost_and_found"; + int i; + int nOrphan = -1; + RecoverTable *pOrphan = 0; + + int bFreelist = 1; /* 0 if --freelist-corrupt is specified */ + int bRowids = 1; /* 0 if --no-rowids */ + for(i=1; idb, &rc, - /* Attach an in-memory database named 'recovery'. Create an indexed - ** cache of the sqlite_dbptr virtual table. */ - "PRAGMA writable_schema = on;" - "ATTACH %Q AS recovery;" - "DROP TABLE IF EXISTS recovery.dbptr;" - "DROP TABLE IF EXISTS recovery.freelist;" - "DROP TABLE IF EXISTS recovery.map;" - "DROP TABLE IF EXISTS recovery.schema;" - "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb - ); - - if( bFreelist ){ - shellExec(pState->db, &rc, - "WITH trunk(pgno) AS (" - " SELECT shell_int32(" - " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x " - " WHERE x>0" - " UNION" - " SELECT shell_int32(" - " (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x " - " FROM trunk WHERE x>0" - ")," - "freelist(data, n, freepgno) AS (" - " SELECT data, min(16384, shell_int32(data, 1)-1), t.pgno " - " FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno" - " UNION ALL" - " SELECT data, n-1, shell_int32(data, 2+n) " - " FROM freelist WHERE n>=0" - ")" - "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;" - ); + else{ + utf8_printf(stderr, "unexpected option: %s\n", azArg[i]); + showHelp(pState->out, azArg[0]); + return 1; } + } - /* If this is an auto-vacuum database, add all pointer-map pages to - ** the freelist table. Do this regardless of whether or not - ** --freelist-corrupt was specified. */ + shellExecPrintf(pState->db, &rc, + /* Attach an in-memory database named 'recovery'. Create an indexed + ** cache of the sqlite_dbptr virtual table. */ + "PRAGMA writable_schema = on;" + "ATTACH %Q AS recovery;" + "DROP TABLE IF EXISTS recovery.dbptr;" + "DROP TABLE IF EXISTS recovery.freelist;" + "DROP TABLE IF EXISTS recovery.map;" + "DROP TABLE IF EXISTS recovery.schema;" + "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb + ); + + if( bFreelist ){ shellExec(pState->db, &rc, - "WITH ptrmap(pgno) AS (" - " SELECT 2 WHERE shell_int32(" - " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 13" - " )" - " UNION ALL " - " SELECT pgno+1+(SELECT page_size FROM pragma_page_size)/5 AS pp " - " FROM ptrmap WHERE pp<=(SELECT page_count FROM pragma_page_count)" - ")" - "REPLACE INTO recovery.freelist SELECT pgno FROM ptrmap" + "WITH trunk(pgno) AS (" + " SELECT shell_int32(" + " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x " + " WHERE x>0" + " UNION" + " SELECT shell_int32(" + " (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x " + " FROM trunk WHERE x>0" + ")," + "freelist(data, n, freepgno) AS (" + " SELECT data, min(16384, shell_int32(data, 1)-1), t.pgno " + " FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno" + " UNION ALL" + " SELECT data, n-1, shell_int32(data, 2+n) " + " FROM freelist WHERE n>=0" + ")" + "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;" ); + } - shellExec(pState->db, &rc, - "CREATE TABLE recovery.dbptr(" - " pgno, child, PRIMARY KEY(child, pgno)" - ") WITHOUT ROWID;" - "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) " - " SELECT * FROM sqlite_dbptr" - " WHERE pgno NOT IN freelist AND child NOT IN freelist;" - - /* Delete any pointer to page 1. This ensures that page 1 is considered + /* If this is an auto-vacuum database, add all pointer-map pages to + ** the freelist table. Do this regardless of whether or not + ** --freelist-corrupt was specified. */ + shellExec(pState->db, &rc, + "WITH ptrmap(pgno) AS (" + " SELECT 2 WHERE shell_int32(" + " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 13" + " )" + " UNION ALL " + " SELECT pgno+1+(SELECT page_size FROM pragma_page_size)/5 AS pp " + " FROM ptrmap WHERE pp<=(SELECT page_count FROM pragma_page_count)" + ")" + "REPLACE INTO recovery.freelist SELECT pgno FROM ptrmap" + ); + + shellExec(pState->db, &rc, + "CREATE TABLE recovery.dbptr(" + " pgno, child, PRIMARY KEY(child, pgno)" + ") WITHOUT ROWID;" + "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) " + " SELECT * FROM sqlite_dbptr" + " WHERE pgno NOT IN freelist AND child NOT IN freelist;" + + /* Delete any pointer to page 1. This ensures that page 1 is considered ** a root page, regardless of how corrupt the db is. */ - "DELETE FROM recovery.dbptr WHERE child = 1;" + "DELETE FROM recovery.dbptr WHERE child = 1;" - /* Delete all pointers to any pages that have more than one pointer + /* Delete all pointers to any pages that have more than one pointer ** to them. Such pages will be treated as root pages when recovering ** data. */ - "DELETE FROM recovery.dbptr WHERE child IN (" - " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1" - ");" + "DELETE FROM recovery.dbptr WHERE child IN (" + " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1" + ");" - /* Create the "map" table that will (eventually) contain instructions - ** for dealing with each page in the db that contains one or more + /* Create the "map" table that will (eventually) contain instructions + ** for dealing with each page in the db that contains one or more ** records. */ - "CREATE TABLE recovery.map(" - "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT" - ");" + "CREATE TABLE recovery.map(" + "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT" + ");" - /* Populate table [map]. If there are circular loops of pages in the + /* Populate table [map]. If there are circular loops of pages in the ** database, the following adds all pages in such a loop to the map ** as individual root pages. This could be handled better. */ - "WITH pages(i, maxlen) AS (" - " SELECT page_count, (" - " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count" - " ) FROM pragma_page_count WHERE page_count>0" - " UNION ALL" - " SELECT i-1, (" - " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1" - " ) FROM pages WHERE i>=2" - ")" - "INSERT INTO recovery.map(pgno, maxlen, intkey, root) " - " SELECT i, maxlen, NULL, (" - " WITH p(orig, pgno, parent) AS (" - " SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)" - " UNION " - " SELECT i, p.parent, " - " (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p" - " )" - " SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)" - ") " - "FROM pages WHERE maxlen IS NOT NULL AND i NOT IN freelist;" - "UPDATE recovery.map AS o SET intkey = (" - " SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno" - ");" - - /* Extract data from page 1 and any linked pages into table + "WITH pages(i, maxlen) AS (" + " SELECT page_count, (" + " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count" + " ) FROM pragma_page_count WHERE page_count>0" + " UNION ALL" + " SELECT i-1, (" + " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1" + " ) FROM pages WHERE i>=2" + ")" + "INSERT INTO recovery.map(pgno, maxlen, intkey, root) " + " SELECT i, maxlen, NULL, (" + " WITH p(orig, pgno, parent) AS (" + " SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)" + " UNION " + " SELECT i, p.parent, " + " (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p" + " )" + " SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)" + ") " + "FROM pages WHERE maxlen IS NOT NULL AND i NOT IN freelist;" + "UPDATE recovery.map AS o SET intkey = (" + " SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno" + ");" + + /* Extract data from page 1 and any linked pages into table ** recovery.schema. With the same schema as an sqlite_schema table. */ - "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);" - "INSERT INTO recovery.schema SELECT " - " max(CASE WHEN field=0 THEN value ELSE NULL END)," - " max(CASE WHEN field=1 THEN value ELSE NULL END)," - " max(CASE WHEN field=2 THEN value ELSE NULL END)," - " max(CASE WHEN field=3 THEN value ELSE NULL END)," - " max(CASE WHEN field=4 THEN value ELSE NULL END)" - "FROM sqlite_dbdata WHERE pgno IN (" - " SELECT pgno FROM recovery.map WHERE root=1" - ")" - "GROUP BY pgno, cell;" - "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);" - ); - - /* Open a transaction, then print out all non-virtual, non-"sqlite_%" + "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);" + "INSERT INTO recovery.schema SELECT " + " max(CASE WHEN field=0 THEN value ELSE NULL END)," + " max(CASE WHEN field=1 THEN value ELSE NULL END)," + " max(CASE WHEN field=2 THEN value ELSE NULL END)," + " max(CASE WHEN field=3 THEN value ELSE NULL END)," + " max(CASE WHEN field=4 THEN value ELSE NULL END)" + "FROM sqlite_dbdata WHERE pgno IN (" + " SELECT pgno FROM recovery.map WHERE root=1" + ")" + "GROUP BY pgno, cell;" + "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);" + ); + + /* Open a transaction, then print out all non-virtual, non-"sqlite_%" ** CREATE TABLE statements that extracted from the existing schema. */ - if( rc==SQLITE_OK ){ - sqlite3_stmt *pStmt = 0; - /* ".recover" might output content in an order which causes immediate + if( rc==SQLITE_OK ){ + sqlite3_stmt *pStmt = 0; + /* ".recover" might output content in an order which causes immediate ** foreign key constraints to be violated. So disable foreign-key ** constraint enforcement to prevent problems when running the output ** script. */ - raw_printf(pState->out, "PRAGMA foreign_keys=OFF;\n"); - raw_printf(pState->out, "BEGIN;\n"); - raw_printf(pState->out, "PRAGMA writable_schema = on;\n"); - shellPrepare(pState->db, &rc, - "SELECT sql FROM recovery.schema " - "WHERE type='table' AND sql LIKE 'create table%'", &pStmt - ); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0); - raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n", - &zCreateTable[12] - ); - } - shellFinalize(&rc, pStmt); - } - - /* Figure out if an orphan table will be required. And if so, how many - ** user columns it should contain */ + raw_printf(pState->out, "PRAGMA foreign_keys=OFF;\n"); + raw_printf(pState->out, "BEGIN;\n"); + raw_printf(pState->out, "PRAGMA writable_schema = on;\n"); shellPrepare(pState->db, &rc, - "SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1" - , &pLoop + "SELECT sql FROM recovery.schema " + "WHERE type='table' AND sql LIKE 'create table%'", &pStmt ); - if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ - nOrphan = sqlite3_column_int(pLoop, 0); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0); + raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n", + &zCreateTable[12] + ); } - shellFinalize(&rc, pLoop); - pLoop = 0; - - shellPrepare(pState->db, &rc, - "SELECT pgno FROM recovery.map WHERE root=?", &pPages - ); - - shellPrepare(pState->db, &rc, - "SELECT max(field), group_concat(shell_escape_crnl(quote" - "(case when (? AND field<0) then NULL else value end)" - "), ', ')" - ", min(field) " - "FROM sqlite_dbdata WHERE pgno = ? AND field != ?" - "GROUP BY cell", &pCells - ); - - /* Loop through each root page. */ - shellPrepare(pState->db, &rc, - "SELECT root, intkey, max(maxlen) FROM recovery.map" - " WHERE root>1 GROUP BY root, intkey ORDER BY root=(" - " SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'" - ")", &pLoop - ); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ - int iRoot = sqlite3_column_int(pLoop, 0); - int bIntkey = sqlite3_column_int(pLoop, 1); - int nCol = sqlite3_column_int(pLoop, 2); - int bNoop = 0; - RecoverTable *pTab; - - assert( bIntkey==0 || bIntkey==1 ); - pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop); - if( bNoop || rc ) continue; - if( pTab==0 ){ - if( pOrphan==0 ){ - pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan); - } - pTab = pOrphan; - if( pTab==0 ) break; - } - - if( 0==sqlite3_stricmp(pTab->zQuoted, "\"sqlite_sequence\"") ){ - raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n"); - } - sqlite3_bind_int(pPages, 1, iRoot); - if( bRowids==0 && pTab->iPk<0 ){ - sqlite3_bind_int(pCells, 1, 1); - }else{ - sqlite3_bind_int(pCells, 1, 0); - } - sqlite3_bind_int(pCells, 3, pTab->iPk); - - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){ - int iPgno = sqlite3_column_int(pPages, 0); - sqlite3_bind_int(pCells, 2, iPgno); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){ - int nField = sqlite3_column_int(pCells, 0); - int iMin = sqlite3_column_int(pCells, 2); - const char *zVal = (const char*)sqlite3_column_text(pCells, 1); - - RecoverTable *pTab2 = pTab; - if( pTab!=pOrphan && (iMin<0)!=bIntkey ){ - if( pOrphan==0 ){ - pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan); - } - pTab2 = pOrphan; - if( pTab2==0 ) break; - } + shellFinalize(&rc, pStmt); + } - nField = nField+1; - if( pTab2==pOrphan ){ - raw_printf(pState->out, - "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n", - pTab2->zQuoted, iRoot, iPgno, nField, - iMin<0 ? "" : "NULL, ", zVal, pTab2->azlCol[nField] - ); - }else{ - raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n", - pTab2->zQuoted, pTab2->azlCol[nField], zVal - ); - } - } - shellReset(&rc, pCells); - } - shellReset(&rc, pPages); - if( pTab!=pOrphan ) recoverFreeTable(pTab); - } - shellFinalize(&rc, pLoop); - shellFinalize(&rc, pPages); - shellFinalize(&rc, pCells); - recoverFreeTable(pOrphan); + /* Figure out if an orphan table will be required. And if so, how many + ** user columns it should contain */ + shellPrepare(pState->db, &rc, + "SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1" + , &pLoop + ); + if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ + nOrphan = sqlite3_column_int(pLoop, 0); + } + shellFinalize(&rc, pLoop); + pLoop = 0; + + shellPrepare(pState->db, &rc, + "SELECT pgno FROM recovery.map WHERE root=?", &pPages + ); + + shellPrepare(pState->db, &rc, + "SELECT max(field), group_concat(shell_escape_crnl(quote" + "(case when (? AND field<0) then NULL else value end)" + "), ', ')" + ", min(field) " + "FROM sqlite_dbdata WHERE pgno = ? AND field != ?" + "GROUP BY cell", &pCells + ); + + /* Loop through each root page. */ + shellPrepare(pState->db, &rc, + "SELECT root, intkey, max(maxlen) FROM recovery.map" + " WHERE root>1 GROUP BY root, intkey ORDER BY root=(" + " SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'" + ")", &pLoop + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){ + int iRoot = sqlite3_column_int(pLoop, 0); + int bIntkey = sqlite3_column_int(pLoop, 1); + int nCol = sqlite3_column_int(pLoop, 2); + int bNoop = 0; + RecoverTable *pTab; - /* The rest of the schema */ - if( rc==SQLITE_OK ){ - sqlite3_stmt *pStmt = 0; - shellPrepare(pState->db, &rc, - "SELECT sql, name FROM recovery.schema " - "WHERE sql NOT LIKE 'create table%'", &pStmt - ); - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *zSql = (const char*)sqlite3_column_text(pStmt, 0); - if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){ - const char *zName = (const char*)sqlite3_column_text(pStmt, 1); - char *zPrint = shellMPrintf(&rc, - "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)", - zName, zName, zSql - ); - raw_printf(pState->out, "%s;\n", zPrint); - sqlite3_free(zPrint); - }else{ - raw_printf(pState->out, "%s;\n", zSql); - } - } - shellFinalize(&rc, pStmt); + assert( bIntkey==0 || bIntkey==1 ); + pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop); + if( bNoop || rc ) continue; + if( pTab==0 ){ + if( pOrphan==0 ){ + pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan); + } + pTab = pOrphan; + if( pTab==0 ) break; } - if( rc==SQLITE_OK ){ - raw_printf(pState->out, "PRAGMA writable_schema = off;\n"); - raw_printf(pState->out, "COMMIT;\n"); + if( 0==sqlite3_stricmp(pTab->zQuoted, "\"sqlite_sequence\"") ){ + raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n"); } - sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0); - return rc; + sqlite3_bind_int(pPages, 1, iRoot); + if( bRowids==0 && pTab->iPk<0 ){ + sqlite3_bind_int(pCells, 1, 1); + }else{ + sqlite3_bind_int(pCells, 1, 0); + } + sqlite3_bind_int(pCells, 3, pTab->iPk); + + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){ + int iPgno = sqlite3_column_int(pPages, 0); + sqlite3_bind_int(pCells, 2, iPgno); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){ + int nField = sqlite3_column_int(pCells, 0); + int iMin = sqlite3_column_int(pCells, 2); + const char *zVal = (const char*)sqlite3_column_text(pCells, 1); + + RecoverTable *pTab2 = pTab; + if( pTab!=pOrphan && (iMin<0)!=bIntkey ){ + if( pOrphan==0 ){ + pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan); + } + pTab2 = pOrphan; + if( pTab2==0 ) break; + } + + nField = nField+1; + if( pTab2==pOrphan ){ + raw_printf(pState->out, + "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n", + pTab2->zQuoted, iRoot, iPgno, nField, + iMin<0 ? "" : "NULL, ", zVal, pTab2->azlCol[nField] + ); + }else{ + raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n", + pTab2->zQuoted, pTab2->azlCol[nField], zVal + ); + } + } + shellReset(&rc, pCells); + } + shellReset(&rc, pPages); + if( pTab!=pOrphan ) recoverFreeTable(pTab); + } + shellFinalize(&rc, pLoop); + shellFinalize(&rc, pPages); + shellFinalize(&rc, pCells); + recoverFreeTable(pOrphan); + + /* The rest of the schema */ + if( rc==SQLITE_OK ){ + sqlite3_stmt *pStmt = 0; + shellPrepare(pState->db, &rc, + "SELECT sql, name FROM recovery.schema " + "WHERE sql NOT LIKE 'create table%'", &pStmt + ); + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zSql = (const char*)sqlite3_column_text(pStmt, 0); + if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){ + const char *zName = (const char*)sqlite3_column_text(pStmt, 1); + char *zPrint = shellMPrintf(&rc, + "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)", + zName, zName, zSql + ); + raw_printf(pState->out, "%s;\n", zPrint); + sqlite3_free(zPrint); + }else{ + raw_printf(pState->out, "%s;\n", zSql); + } + } + shellFinalize(&rc, pStmt); + } + + if( rc==SQLITE_OK ){ + raw_printf(pState->out, "PRAGMA writable_schema = off;\n"); + raw_printf(pState->out, "COMMIT;\n"); + } + sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0); + return rc; } #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ @@ -18610,3140 +18610,3140 @@ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){ ** Return 1 on error, 2 to exit, and 0 otherwise. */ static int do_meta_command(char *zLine, ShellState *p){ - int h = 1; - int nArg = 0; - int n, c; - int rc = 0; - char *azArg[52]; + int h = 1; + int nArg = 0; + int n, c; + int rc = 0; + char *azArg[52]; #ifndef SQLITE_OMIT_VIRTUALTABLE - if( p->expert.pExpert ){ - expertFinish(p, 1, 0); - } + if( p->expert.pExpert ){ + expertFinish(p, 1, 0); + } #endif - /* Parse the input line into tokens. + /* Parse the input line into tokens. */ - while( zLine[h] && nArgdb, shellAuth, p); - }else if( p->bSafeModePersist ){ - sqlite3_set_authorizer(p->db, safeModeAuth, p); - }else{ - sqlite3_set_authorizer(p->db, 0, 0); - } - }else + if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){ + if( nArg!=2 ){ + raw_printf(stderr, "Usage: .auth ON|OFF\n"); + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + if( booleanValue(azArg[1]) ){ + sqlite3_set_authorizer(p->db, shellAuth, p); + }else if( p->bSafeModePersist ){ + sqlite3_set_authorizer(p->db, safeModeAuth, p); + }else{ + sqlite3_set_authorizer(p->db, 0, 0); + } + }else #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) - if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ - open_db(p, 0); - failIfSafeMode(p, "cannot run .archive in safe mode"); - rc = arDotCommand(p, 0, azArg, nArg); - }else + if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ + open_db(p, 0); + failIfSafeMode(p, "cannot run .archive in safe mode"); + rc = arDotCommand(p, 0, azArg, nArg); + }else #endif - if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0) - || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0) - ){ - const char *zDestFile = 0; - const char *zDb = 0; - sqlite3 *pDest; - sqlite3_backup *pBackup; - int j; - int bAsync = 0; - const char *zVfs = 0; - failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); - for(j=1; jdb, zDb); - if( pBackup==0 ){ - utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); - close_db(pDest); - return 1; - } - while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} - sqlite3_backup_finish(pBackup); - if( rc==SQLITE_DONE ){ - rc = 0; - }else{ - utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); - rc = 1; - } - close_db(pDest); - }else - - if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){ - if( nArg==2 ){ - bail_on_error = booleanValue(azArg[1]); - }else{ - raw_printf(stderr, "Usage: .bail on|off\n"); - rc = 1; - } - }else + if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0) + || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0) + ){ + const char *zDestFile = 0; + const char *zDb = 0; + sqlite3 *pDest; + sqlite3_backup *pBackup; + int j; + int bAsync = 0; + const char *zVfs = 0; + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); + for(j=1; jdb, zDb); + if( pBackup==0 ){ + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); + close_db(pDest); + return 1; + } + while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} + sqlite3_backup_finish(pBackup); + if( rc==SQLITE_DONE ){ + rc = 0; + }else{ + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); + rc = 1; + } + close_db(pDest); + }else - if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){ - if( nArg==2 ){ - if( booleanValue(azArg[1]) ){ - setBinaryMode(p->out, 1); - }else{ - setTextMode(p->out, 1); - } - }else{ - raw_printf(stderr, "Usage: .binary on|off\n"); - rc = 1; - } - }else + if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){ + if( nArg==2 ){ + bail_on_error = booleanValue(azArg[1]); + }else{ + raw_printf(stderr, "Usage: .bail on|off\n"); + rc = 1; + } + }else + + if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){ + if( nArg==2 ){ + if( booleanValue(azArg[1]) ){ + setBinaryMode(p->out, 1); + }else{ + setTextMode(p->out, 1); + } + }else{ + raw_printf(stderr, "Usage: .binary on|off\n"); + rc = 1; + } + }else - /* The undocumented ".breakpoint" command causes a call to the no-op + /* The undocumented ".breakpoint" command causes a call to the no-op ** routine named test_breakpoint(). */ - if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ - test_breakpoint(); - }else + if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){ + test_breakpoint(); + }else - if( c=='c' && strcmp(azArg[0],"cd")==0 ){ - failIfSafeMode(p, "cannot run .cd in safe mode"); - if( nArg==2 ){ + if( c=='c' && strcmp(azArg[0],"cd")==0 ){ + failIfSafeMode(p, "cannot run .cd in safe mode"); + if( nArg==2 ){ #if defined(_WIN32) || defined(WIN32) - wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); - rc = !SetCurrentDirectoryW(z); - sqlite3_free(z); + wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]); + rc = !SetCurrentDirectoryW(z); + sqlite3_free(z); #else - rc = chdir(azArg[1]); + rc = chdir(azArg[1]); #endif - if( rc ){ - utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]); - rc = 1; - } - }else{ - raw_printf(stderr, "Usage: .cd DIRECTORY\n"); - rc = 1; - } - }else + if( rc ){ + utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]); + rc = 1; + } + }else{ + raw_printf(stderr, "Usage: .cd DIRECTORY\n"); + rc = 1; + } + }else - if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){ - if( nArg==2 ){ - setOrClearFlag(p, SHFLG_CountChanges, azArg[1]); - }else{ - raw_printf(stderr, "Usage: .changes on|off\n"); - rc = 1; - } - }else + if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){ + if( nArg==2 ){ + setOrClearFlag(p, SHFLG_CountChanges, azArg[1]); + }else{ + raw_printf(stderr, "Usage: .changes on|off\n"); + rc = 1; + } + }else - /* Cancel output redirection, if it is currently set (by .testcase) + /* Cancel output redirection, if it is currently set (by .testcase) ** Then read the content of the testcase-out.txt file and compare against ** azArg[1]. If there are differences, report an error and exit. */ - if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){ - char *zRes = 0; - output_reset(p); - if( nArg!=2 ){ - raw_printf(stderr, "Usage: .check GLOB-PATTERN\n"); - rc = 2; - }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){ - raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n"); - rc = 2; - }else if( testcase_glob(azArg[1],zRes)==0 ){ - utf8_printf(stderr, - "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", - p->zTestcase, azArg[1], zRes); - rc = 1; - }else{ - utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase); - p->nCheck++; - } - sqlite3_free(zRes); - }else - - if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ - failIfSafeMode(p, "cannot run .clone in safe mode"); - if( nArg==2 ){ - tryToClone(p, azArg[1]); - }else{ - raw_printf(stderr, "Usage: .clone FILENAME\n"); - rc = 1; - } - }else - - if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){ - if( nArg==1 ){ - /* List available connections */ - int i; - for(i=0; iaAuxDb); i++){ - const char *zFile = p->aAuxDb[i].zDbFilename; - if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){ - zFile = "(not open)"; - }else if( zFile==0 ){ - zFile = "(memory)"; - }else if( zFile[0]==0 ){ - zFile = "(temporary-file)"; - } - if( p->pAuxDb == &p->aAuxDb[i] ){ - utf8_printf(stdout, "ACTIVE %d: %s\n", i, zFile); - }else if( p->aAuxDb[i].db!=0 ){ - utf8_printf(stdout, " %d: %s\n", i, zFile); - } - } - }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){ - int i = azArg[1][0] - '0'; - if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && iaAuxDb) ){ - p->pAuxDb->db = p->db; - p->pAuxDb = &p->aAuxDb[i]; - globalDb = p->db = p->pAuxDb->db; - p->pAuxDb->db = 0; - } - }else if( nArg==3 && strcmp(azArg[1], "close")==0 - && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){ - int i = azArg[2][0] - '0'; - if( i<0 || i>=ArraySize(p->aAuxDb) ){ - /* No-op */ - }else if( p->pAuxDb == &p->aAuxDb[i] ){ - raw_printf(stderr, "cannot close the active database connection\n"); - rc = 1; - }else if( p->aAuxDb[i].db ){ - session_close_all(p, i); - close_db(p->aAuxDb[i].db); - p->aAuxDb[i].db = 0; - } - }else{ - raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n"); - rc = 1; - } - }else - - if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ - char **azName = 0; - int nName = 0; - sqlite3_stmt *pStmt; - int i; - open_db(p, 0); - rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); - if( rc ){ - utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); - rc = 1; - }else{ - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const char *zSchema = (const char *)sqlite3_column_text(pStmt,1); - const char *zFile = (const char*)sqlite3_column_text(pStmt,2); - azName = sqlite3_realloc(azName, (nName+1)*2*sizeof(char*)); - if( azName==0 ){ shell_out_of_memory(); /* Does not return */ } - azName[nName*2] = strdup(zSchema); - azName[nName*2+1] = strdup(zFile); - nName++; - } - } - sqlite3_finalize(pStmt); - for(i=0; idb, azName[i*2]); - int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]); - const char *z = azName[i*2+1]; - utf8_printf(p->out, "%s: %s %s%s\n", - azName[i*2], - z && z[0] ? z : "\"\"", - bRdonly ? "r/o" : "r/w", - eTxn==SQLITE_TXN_NONE ? "" : - eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn"); - free(azName[i*2]); - free(azName[i*2+1]); - } - sqlite3_free(azName); - }else - - if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){ - static const struct DbConfigChoices { - const char *zName; - int op; - } aDbConfig[] = { - { "defensive", SQLITE_DBCONFIG_DEFENSIVE }, - { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL }, - { "dqs_dml", SQLITE_DBCONFIG_DQS_DML }, - { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, - { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, - { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, - { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW }, - { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, - { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, - { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, - { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, - { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, - { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE }, - { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP }, - { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA }, - { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA }, - }; - int ii, v; - open_db(p, 0); - for(ii=0; ii1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue; - if( nArg>=3 ){ - sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); - } - sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); - utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off"); - if( nArg>1 ) break; - } - if( nArg>1 && ii==ArraySize(aDbConfig) ){ - utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]); - utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n"); - } - }else + if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){ + char *zRes = 0; + output_reset(p); + if( nArg!=2 ){ + raw_printf(stderr, "Usage: .check GLOB-PATTERN\n"); + rc = 2; + }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){ + raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n"); + rc = 2; + }else if( testcase_glob(azArg[1],zRes)==0 ){ + utf8_printf(stderr, + "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", + p->zTestcase, azArg[1], zRes); + rc = 1; + }else{ + utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase); + p->nCheck++; + } + sqlite3_free(zRes); + }else + + if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ + failIfSafeMode(p, "cannot run .clone in safe mode"); + if( nArg==2 ){ + tryToClone(p, azArg[1]); + }else{ + raw_printf(stderr, "Usage: .clone FILENAME\n"); + rc = 1; + } + }else + + if( c=='c' && strncmp(azArg[0], "connection", n)==0 ){ + if( nArg==1 ){ + /* List available connections */ + int i; + for(i=0; iaAuxDb); i++){ + const char *zFile = p->aAuxDb[i].zDbFilename; + if( p->aAuxDb[i].db==0 && p->pAuxDb!=&p->aAuxDb[i] ){ + zFile = "(not open)"; + }else if( zFile==0 ){ + zFile = "(memory)"; + }else if( zFile[0]==0 ){ + zFile = "(temporary-file)"; + } + if( p->pAuxDb == &p->aAuxDb[i] ){ + utf8_printf(stdout, "ACTIVE %d: %s\n", i, zFile); + }else if( p->aAuxDb[i].db!=0 ){ + utf8_printf(stdout, " %d: %s\n", i, zFile); + } + } + }else if( nArg==2 && IsDigit(azArg[1][0]) && azArg[1][1]==0 ){ + int i = azArg[1][0] - '0'; + if( p->pAuxDb != &p->aAuxDb[i] && i>=0 && iaAuxDb) ){ + p->pAuxDb->db = p->db; + p->pAuxDb = &p->aAuxDb[i]; + globalDb = p->db = p->pAuxDb->db; + p->pAuxDb->db = 0; + } + }else if( nArg==3 && strcmp(azArg[1], "close")==0 + && IsDigit(azArg[2][0]) && azArg[2][1]==0 ){ + int i = azArg[2][0] - '0'; + if( i<0 || i>=ArraySize(p->aAuxDb) ){ + /* No-op */ + }else if( p->pAuxDb == &p->aAuxDb[i] ){ + raw_printf(stderr, "cannot close the active database connection\n"); + rc = 1; + }else if( p->aAuxDb[i].db ){ + session_close_all(p, i); + close_db(p->aAuxDb[i].db); + p->aAuxDb[i].db = 0; + } + }else{ + raw_printf(stderr, "Usage: .connection [close] [CONNECTION-NUMBER]\n"); + rc = 1; + } + }else - if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){ - rc = shell_dbinfo_command(p, nArg, azArg); - }else + if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){ + char **azName = 0; + int nName = 0; + sqlite3_stmt *pStmt; + int i; + open_db(p, 0); + rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); + if( rc ){ + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); + rc = 1; + }else{ + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zSchema = (const char *)sqlite3_column_text(pStmt,1); + const char *zFile = (const char*)sqlite3_column_text(pStmt,2); + azName = sqlite3_realloc(azName, (nName+1)*2*sizeof(char*)); + if( azName==0 ){ shell_out_of_memory(); /* Does not return */ } + azName[nName*2] = strdup(zSchema); + azName[nName*2+1] = strdup(zFile); + nName++; + } + } + sqlite3_finalize(pStmt); + for(i=0; idb, azName[i*2]); + int bRdonly = sqlite3_db_readonly(p->db, azName[i*2]); + const char *z = azName[i*2+1]; + utf8_printf(p->out, "%s: %s %s%s\n", + azName[i*2], + z && z[0] ? z : "\"\"", + bRdonly ? "r/o" : "r/w", + eTxn==SQLITE_TXN_NONE ? "" : + eTxn==SQLITE_TXN_READ ? " read-txn" : " write-txn"); + free(azName[i*2]); + free(azName[i*2+1]); + } + sqlite3_free(azName); + }else + + if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){ + static const struct DbConfigChoices { + const char *zName; + int op; + } aDbConfig[] = { + { "defensive", SQLITE_DBCONFIG_DEFENSIVE }, + { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL }, + { "dqs_dml", SQLITE_DBCONFIG_DQS_DML }, + { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, + { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, + { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, + { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW }, + { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, + { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, + { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, + { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, + { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, + { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE }, + { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP }, + { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA }, + { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA }, + }; + int ii, v; + open_db(p, 0); + for(ii=0; ii1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue; + if( nArg>=3 ){ + sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); + } + sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); + utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off"); + if( nArg>1 ) break; + } + if( nArg>1 && ii==ArraySize(aDbConfig) ){ + utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]); + utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n"); + } + }else + + if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){ + rc = shell_dbinfo_command(p, nArg, azArg); + }else #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) - if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){ - open_db(p, 0); - rc = recoverDatabaseCmd(p, nArg, azArg); - }else + if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){ + open_db(p, 0); + rc = recoverDatabaseCmd(p, nArg, azArg); + }else #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */ - if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ - char *zLike = 0; - char *zSql; - int i; - int savedShowHeader = p->showHeader; - int savedShellFlags = p->shellFlgs; - ShellClearFlag(p, - SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo - |SHFLG_DumpDataOnly|SHFLG_DumpNoSys); - for(i=1; ishowHeader; + int savedShellFlags = p->shellFlgs; + ShellClearFlag(p, + SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo + |SHFLG_DumpDataOnly|SHFLG_DumpNoSys); + for(i=1; ishellFlgs & SHFLG_DumpDataOnly)==0 ){ - /* When playing back a "dump", the content might appear in an order + char *zExpr = sqlite3_mprintf( + "name LIKE %Q ESCAPE '\\' OR EXISTS (" + " SELECT 1 FROM sqlite_schema WHERE " + " name LIKE %Q ESCAPE '\\' AND" + " sql LIKE 'CREATE VIRTUAL TABLE%%' AND" + " substr(o.name, 1, length(name)+1) == (name||'_')" + ")", azArg[i], azArg[i] + ); + + if( zLike ){ + zLike = sqlite3_mprintf("%z OR %z", zLike, zExpr); + }else{ + zLike = zExpr; + } + } + } + + open_db(p, 0); + + if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ + /* When playing back a "dump", the content might appear in an order ** which causes immediate foreign key constraints to be violated. ** So disable foreign-key constraint enforcement to prevent problems. */ - raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n"); - raw_printf(p->out, "BEGIN TRANSACTION;\n"); - } - p->writableSchema = 0; - p->showHeader = 0; - /* Set writable_schema=ON since doing so forces SQLite to initialize + raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n"); + raw_printf(p->out, "BEGIN TRANSACTION;\n"); + } + p->writableSchema = 0; + p->showHeader = 0; + /* Set writable_schema=ON since doing so forces SQLite to initialize ** as much of the schema as it can even if the sqlite_schema table is ** corrupt. */ - sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); - p->nErr = 0; - if( zLike==0 ) zLike = sqlite3_mprintf("true"); - zSql = sqlite3_mprintf( - "SELECT name, type, sql FROM sqlite_schema AS o " - "WHERE (%s) AND type=='table'" - " AND sql NOT NULL" - " ORDER BY tbl_name='sqlite_sequence', rowid", - zLike - ); - run_schema_dump_query(p,zSql); - sqlite3_free(zSql); - if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ - zSql = sqlite3_mprintf( - "SELECT sql FROM sqlite_schema AS o " - "WHERE (%s) AND sql NOT NULL" - " AND type IN ('index','trigger','view')", - zLike - ); - run_table_dump_query(p, zSql); - sqlite3_free(zSql); - } - sqlite3_free(zLike); - if( p->writableSchema ){ - raw_printf(p->out, "PRAGMA writable_schema=OFF;\n"); - p->writableSchema = 0; - } - sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); - sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); - if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ - raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n"); - } - p->showHeader = savedShowHeader; - p->shellFlgs = savedShellFlags; - }else - - if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ - if( nArg==2 ){ - setOrClearFlag(p, SHFLG_Echo, azArg[1]); - }else{ - raw_printf(stderr, "Usage: .echo on|off\n"); - rc = 1; - } - }else - - if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ - if( nArg==2 ){ - p->autoEQPtest = 0; - if( p->autoEQPtrace ){ - if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0); - p->autoEQPtrace = 0; - } - if( strcmp(azArg[1],"full")==0 ){ - p->autoEQP = AUTOEQP_full; - }else if( strcmp(azArg[1],"trigger")==0 ){ - p->autoEQP = AUTOEQP_trigger; + sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); + p->nErr = 0; + if( zLike==0 ) zLike = sqlite3_mprintf("true"); + zSql = sqlite3_mprintf( + "SELECT name, type, sql FROM sqlite_schema AS o " + "WHERE (%s) AND type=='table'" + " AND sql NOT NULL" + " ORDER BY tbl_name='sqlite_sequence', rowid", + zLike + ); + run_schema_dump_query(p,zSql); + sqlite3_free(zSql); + if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ + zSql = sqlite3_mprintf( + "SELECT sql FROM sqlite_schema AS o " + "WHERE (%s) AND sql NOT NULL" + " AND type IN ('index','trigger','view')", + zLike + ); + run_table_dump_query(p, zSql); + sqlite3_free(zSql); + } + sqlite3_free(zLike); + if( p->writableSchema ){ + raw_printf(p->out, "PRAGMA writable_schema=OFF;\n"); + p->writableSchema = 0; + } + sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); + sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0); + if( (p->shellFlgs & SHFLG_DumpDataOnly)==0 ){ + raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n"); + } + p->showHeader = savedShowHeader; + p->shellFlgs = savedShellFlags; + }else + + if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){ + if( nArg==2 ){ + setOrClearFlag(p, SHFLG_Echo, azArg[1]); + }else{ + raw_printf(stderr, "Usage: .echo on|off\n"); + rc = 1; + } + }else + + if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ + if( nArg==2 ){ + p->autoEQPtest = 0; + if( p->autoEQPtrace ){ + if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0); + p->autoEQPtrace = 0; + } + if( strcmp(azArg[1],"full")==0 ){ + p->autoEQP = AUTOEQP_full; + }else if( strcmp(azArg[1],"trigger")==0 ){ + p->autoEQP = AUTOEQP_trigger; #ifdef SQLITE_DEBUG - }else if( strcmp(azArg[1],"test")==0 ){ - p->autoEQP = AUTOEQP_on; - p->autoEQPtest = 1; - }else if( strcmp(azArg[1],"trace")==0 ){ - p->autoEQP = AUTOEQP_full; - p->autoEQPtrace = 1; - open_db(p, 0); - sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0); - sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0); + }else if( strcmp(azArg[1],"test")==0 ){ + p->autoEQP = AUTOEQP_on; + p->autoEQPtest = 1; + }else if( strcmp(azArg[1],"trace")==0 ){ + p->autoEQP = AUTOEQP_full; + p->autoEQPtrace = 1; + open_db(p, 0); + sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0); + sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0); #endif - }else{ - p->autoEQP = (u8)booleanValue(azArg[1]); - } - }else{ - raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n"); - rc = 1; - } - }else - - if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ - if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); - rc = 2; - }else - - /* The ".explain" command is automatic now. It is largely pointless. It + }else{ + p->autoEQP = (u8)booleanValue(azArg[1]); + } + }else{ + raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n"); + rc = 1; + } + }else + + if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){ + if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc); + rc = 2; + }else + + /* The ".explain" command is automatic now. It is largely pointless. It ** retained purely for backwards compatibility */ - if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ - int val = 1; - if( nArg>=2 ){ - if( strcmp(azArg[1],"auto")==0 ){ - val = 99; - }else{ - val = booleanValue(azArg[1]); - } - } - if( val==1 && p->mode!=MODE_Explain ){ - p->normalMode = p->mode; - p->mode = MODE_Explain; - p->autoExplain = 0; - }else if( val==0 ){ - if( p->mode==MODE_Explain ) p->mode = p->normalMode; - p->autoExplain = 0; - }else if( val==99 ){ - if( p->mode==MODE_Explain ) p->mode = p->normalMode; - p->autoExplain = 1; - } - }else + if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ + int val = 1; + if( nArg>=2 ){ + if( strcmp(azArg[1],"auto")==0 ){ + val = 99; + }else{ + val = booleanValue(azArg[1]); + } + } + if( val==1 && p->mode!=MODE_Explain ){ + p->normalMode = p->mode; + p->mode = MODE_Explain; + p->autoExplain = 0; + }else if( val==0 ){ + if( p->mode==MODE_Explain ) p->mode = p->normalMode; + p->autoExplain = 0; + }else if( val==99 ){ + if( p->mode==MODE_Explain ) p->mode = p->normalMode; + p->autoExplain = 1; + } + }else #ifndef SQLITE_OMIT_VIRTUALTABLE - if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){ - open_db(p, 0); - expertDotCommand(p, azArg, nArg); - }else + if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){ + open_db(p, 0); + expertDotCommand(p, azArg, nArg); + }else #endif - if( c=='f' && strncmp(azArg[0], "filectrl", n)==0 ){ - static const struct { - const char *zCtrlName; /* Name of a test-control option */ - int ctrlCode; /* Integer code for that option */ - const char *zUsage; /* Usage notes */ - } aCtrl[] = { - { "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" }, - { "data_version", SQLITE_FCNTL_DATA_VERSION, "" }, - { "has_moved", SQLITE_FCNTL_HAS_MOVED, "" }, - { "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" }, - { "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" }, - /* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/ - { "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" }, - { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" }, - { "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" }, - { "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" }, - /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/ - }; - int filectrl = -1; - int iCtrl = -1; - sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */ - int isOk = 0; /* 0: usage 1: %lld 2: no-result */ - int n2, i; - const char *zCmd = 0; - const char *zSchema = 0; - - open_db(p, 0); - zCmd = nArg>=2 ? azArg[1] : "help"; - - if( zCmd[0]=='-' - && (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0) - && nArg>=4 - ){ - zSchema = azArg[2]; - for(i=3; iout, "Available file-controls:\n"); - for(i=0; iout, " .filectrl %s %s\n", - aCtrl[i].zCtrlName, aCtrl[i].zUsage); - } - rc = 1; - goto meta_command_exit; - } - - /* convert filectrl text option to value. allow any unique prefix + if( c=='f' && strncmp(azArg[0], "filectrl", n)==0 ){ + static const struct { + const char *zCtrlName; /* Name of a test-control option */ + int ctrlCode; /* Integer code for that option */ + const char *zUsage; /* Usage notes */ + } aCtrl[] = { + { "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" }, + { "data_version", SQLITE_FCNTL_DATA_VERSION, "" }, + { "has_moved", SQLITE_FCNTL_HAS_MOVED, "" }, + { "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" }, + { "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" }, + /* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/ + { "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" }, + { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" }, + { "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" }, + { "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" }, + /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/ + }; + int filectrl = -1; + int iCtrl = -1; + sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */ + int isOk = 0; /* 0: usage 1: %lld 2: no-result */ + int n2, i; + const char *zCmd = 0; + const char *zSchema = 0; + + open_db(p, 0); + zCmd = nArg>=2 ? azArg[1] : "help"; + + if( zCmd[0]=='-' + && (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0) + && nArg>=4 + ){ + zSchema = azArg[2]; + for(i=3; iout, "Available file-controls:\n"); + for(i=0; iout, " .filectrl %s %s\n", + aCtrl[i].zCtrlName, aCtrl[i].zUsage); + } + rc = 1; + goto meta_command_exit; + } + + /* convert filectrl text option to value. allow any unique prefix ** of the option name, or a numerical value. */ - n2 = strlen30(zCmd); - for(i=0; idb, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes); - isOk = 1; - break; - } - case SQLITE_FCNTL_LOCK_TIMEOUT: - case SQLITE_FCNTL_CHUNK_SIZE: { - int x; - if( nArg!=3 ) break; - x = (int)integerValue(azArg[2]); - sqlite3_file_control(p->db, zSchema, filectrl, &x); - isOk = 2; - break; - } - case SQLITE_FCNTL_PERSIST_WAL: - case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { - int x; - if( nArg!=2 && nArg!=3 ) break; - x = nArg==3 ? booleanValue(azArg[2]) : -1; - sqlite3_file_control(p->db, zSchema, filectrl, &x); - iRes = x; - isOk = 1; - break; - } - case SQLITE_FCNTL_DATA_VERSION: - case SQLITE_FCNTL_HAS_MOVED: { - int x; - if( nArg!=2 ) break; - sqlite3_file_control(p->db, zSchema, filectrl, &x); - iRes = x; - isOk = 1; - break; - } - case SQLITE_FCNTL_TEMPFILENAME: { - char *z = 0; - if( nArg!=2 ) break; - sqlite3_file_control(p->db, zSchema, filectrl, &z); - if( z ){ - utf8_printf(p->out, "%s\n", z); - sqlite3_free(z); - } - isOk = 2; - break; - } - case SQLITE_FCNTL_RESERVE_BYTES: { - int x; - if( nArg>=3 ){ - x = atoi(azArg[2]); - sqlite3_file_control(p->db, zSchema, filectrl, &x); - } - x = -1; - sqlite3_file_control(p->db, zSchema, filectrl, &x); - utf8_printf(p->out,"%d\n", x); - isOk = 2; - break; - } - } - } - if( isOk==0 && iCtrl>=0 ){ - utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); - rc = 1; - }else if( isOk==1 ){ - char zBuf[100]; - sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes); - raw_printf(p->out, "%s\n", zBuf); - } - }else - - if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ - ShellState data; - int doStats = 0; - memcpy(&data, p, sizeof(data)); - data.showHeader = 0; - data.cMode = data.mode = MODE_Semi; - if( nArg==2 && optionMatch(azArg[1], "indent") ){ - data.cMode = data.mode = MODE_Pretty; - nArg = 1; - } - if( nArg!=1 ){ - raw_printf(stderr, "Usage: .fullschema ?--indent?\n"); - rc = 1; - goto meta_command_exit; - } - open_db(p, 0); - rc = sqlite3_exec(p->db, - "SELECT sql FROM" - " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" - " FROM sqlite_schema UNION ALL" - " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) " - "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " - "ORDER BY x", - callback, &data, 0 - ); - if( rc==SQLITE_OK ){ - sqlite3_stmt *pStmt; - rc = sqlite3_prepare_v2(p->db, - "SELECT rowid FROM sqlite_schema" - " WHERE name GLOB 'sqlite_stat[134]'", - -1, &pStmt, 0); - doStats = sqlite3_step(pStmt)==SQLITE_ROW; - sqlite3_finalize(pStmt); - } - if( doStats==0 ){ - raw_printf(p->out, "/* No STAT tables available */\n"); - }else{ - raw_printf(p->out, "ANALYZE sqlite_schema;\n"); - data.cMode = data.mode = MODE_Insert; - data.zDestTable = "sqlite_stat1"; - shell_exec(&data, "SELECT * FROM sqlite_stat1", 0); - data.zDestTable = "sqlite_stat4"; - shell_exec(&data, "SELECT * FROM sqlite_stat4", 0); - raw_printf(p->out, "ANALYZE sqlite_schema;\n"); - } - }else - - if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){ - if( nArg==2 ){ - p->showHeader = booleanValue(azArg[1]); - p->shellFlgs |= SHFLG_HeaderSet; - }else{ - raw_printf(stderr, "Usage: .headers on|off\n"); - rc = 1; - } - }else - - if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ - if( nArg>=2 ){ - n = showHelp(p->out, azArg[1]); - if( n==0 ){ - utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); - } - }else{ - showHelp(p->out, 0); - } - }else - - if( c=='i' && strncmp(azArg[0], "import", n)==0 ){ - char *zTable = 0; /* Insert data into this table */ - char *zFile = 0; /* Name of file to extra content from */ - sqlite3_stmt *pStmt = NULL; /* A statement */ - int nCol; /* Number of columns in the table */ - int nByte; /* Number of bytes in an SQL string */ - int i, j; /* Loop counters */ - int needCommit; /* True to COMMIT or ROLLBACK at end */ - int nSep; /* Number of bytes in p->colSeparator[] */ - char *zSql; /* An SQL statement */ - ImportCtx sCtx; /* Reader context */ - char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */ - int eVerbose = 0; /* Larger for more console output */ - int nSkip = 0; /* Initial lines to skip */ - int useOutputMode = 1; /* Use output mode to determine separators */ - - failIfSafeMode(p, "cannot run .import in safe mode"); - memset(&sCtx, 0, sizeof(sCtx)); - sCtx.z = sqlite3_malloc64(120); - if( sCtx.z==0 ){ - import_cleanup(&sCtx); - shell_out_of_memory(); - } - if( p->mode==MODE_Ascii ){ - xRead = ascii_read_one_field; - }else{ - xRead = csv_read_one_field; - } - for(i=1; iout, "ERROR: extra argument: \"%s\". Usage:\n", z); - showHelp(p->out, "import"); - rc = 1; - goto meta_command_exit; - } - }else if( strcmp(z,"-v")==0 ){ - eVerbose++; - }else if( strcmp(z,"-skip")==0 && iout, "ERROR: unknown option: \"%s\". Usage:\n", z); - showHelp(p->out, "import"); - rc = 1; - goto meta_command_exit; - } - } - if( zTable==0 ){ - utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n", - zFile==0 ? "FILE" : "TABLE"); - showHelp(p->out, "import"); - rc = 1; - goto meta_command_exit; - } - seenInterrupt = 0; - open_db(p, 0); - if( useOutputMode ){ - /* If neither the --csv or --ascii options are specified, then set + n2 = strlen30(zCmd); + for(i=0; idb, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes); + isOk = 1; + break; + } + case SQLITE_FCNTL_LOCK_TIMEOUT: + case SQLITE_FCNTL_CHUNK_SIZE: { + int x; + if( nArg!=3 ) break; + x = (int)integerValue(azArg[2]); + sqlite3_file_control(p->db, zSchema, filectrl, &x); + isOk = 2; + break; + } + case SQLITE_FCNTL_PERSIST_WAL: + case SQLITE_FCNTL_POWERSAFE_OVERWRITE: { + int x; + if( nArg!=2 && nArg!=3 ) break; + x = nArg==3 ? booleanValue(azArg[2]) : -1; + sqlite3_file_control(p->db, zSchema, filectrl, &x); + iRes = x; + isOk = 1; + break; + } + case SQLITE_FCNTL_DATA_VERSION: + case SQLITE_FCNTL_HAS_MOVED: { + int x; + if( nArg!=2 ) break; + sqlite3_file_control(p->db, zSchema, filectrl, &x); + iRes = x; + isOk = 1; + break; + } + case SQLITE_FCNTL_TEMPFILENAME: { + char *z = 0; + if( nArg!=2 ) break; + sqlite3_file_control(p->db, zSchema, filectrl, &z); + if( z ){ + utf8_printf(p->out, "%s\n", z); + sqlite3_free(z); + } + isOk = 2; + break; + } + case SQLITE_FCNTL_RESERVE_BYTES: { + int x; + if( nArg>=3 ){ + x = atoi(azArg[2]); + sqlite3_file_control(p->db, zSchema, filectrl, &x); + } + x = -1; + sqlite3_file_control(p->db, zSchema, filectrl, &x); + utf8_printf(p->out,"%d\n", x); + isOk = 2; + break; + } + } + } + if( isOk==0 && iCtrl>=0 ){ + utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); + rc = 1; + }else if( isOk==1 ){ + char zBuf[100]; + sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes); + raw_printf(p->out, "%s\n", zBuf); + } + }else + + if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ + ShellState data; + int doStats = 0; + memcpy(&data, p, sizeof(data)); + data.showHeader = 0; + data.cMode = data.mode = MODE_Semi; + if( nArg==2 && optionMatch(azArg[1], "indent") ){ + data.cMode = data.mode = MODE_Pretty; + nArg = 1; + } + if( nArg!=1 ){ + raw_printf(stderr, "Usage: .fullschema ?--indent?\n"); + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + rc = sqlite3_exec(p->db, + "SELECT sql FROM" + " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x" + " FROM sqlite_schema UNION ALL" + " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) " + "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " + "ORDER BY x", + callback, &data, 0 + ); + if( rc==SQLITE_OK ){ + sqlite3_stmt *pStmt; + rc = sqlite3_prepare_v2(p->db, + "SELECT rowid FROM sqlite_schema" + " WHERE name GLOB 'sqlite_stat[134]'", + -1, &pStmt, 0); + doStats = sqlite3_step(pStmt)==SQLITE_ROW; + sqlite3_finalize(pStmt); + } + if( doStats==0 ){ + raw_printf(p->out, "/* No STAT tables available */\n"); + }else{ + raw_printf(p->out, "ANALYZE sqlite_schema;\n"); + data.cMode = data.mode = MODE_Insert; + data.zDestTable = "sqlite_stat1"; + shell_exec(&data, "SELECT * FROM sqlite_stat1", 0); + data.zDestTable = "sqlite_stat4"; + shell_exec(&data, "SELECT * FROM sqlite_stat4", 0); + raw_printf(p->out, "ANALYZE sqlite_schema;\n"); + } + }else + + if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){ + if( nArg==2 ){ + p->showHeader = booleanValue(azArg[1]); + p->shellFlgs |= SHFLG_HeaderSet; + }else{ + raw_printf(stderr, "Usage: .headers on|off\n"); + rc = 1; + } + }else + + if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ + if( nArg>=2 ){ + n = showHelp(p->out, azArg[1]); + if( n==0 ){ + utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); + } + }else{ + showHelp(p->out, 0); + } + }else + + if( c=='i' && strncmp(azArg[0], "import", n)==0 ){ + char *zTable = 0; /* Insert data into this table */ + char *zFile = 0; /* Name of file to extra content from */ + sqlite3_stmt *pStmt = NULL; /* A statement */ + int nCol; /* Number of columns in the table */ + int nByte; /* Number of bytes in an SQL string */ + int i, j; /* Loop counters */ + int needCommit; /* True to COMMIT or ROLLBACK at end */ + int nSep; /* Number of bytes in p->colSeparator[] */ + char *zSql; /* An SQL statement */ + ImportCtx sCtx; /* Reader context */ + char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */ + int eVerbose = 0; /* Larger for more console output */ + int nSkip = 0; /* Initial lines to skip */ + int useOutputMode = 1; /* Use output mode to determine separators */ + + failIfSafeMode(p, "cannot run .import in safe mode"); + memset(&sCtx, 0, sizeof(sCtx)); + sCtx.z = sqlite3_malloc64(120); + if( sCtx.z==0 ){ + import_cleanup(&sCtx); + shell_out_of_memory(); + } + if( p->mode==MODE_Ascii ){ + xRead = ascii_read_one_field; + }else{ + xRead = csv_read_one_field; + } + for(i=1; iout, "ERROR: extra argument: \"%s\". Usage:\n", z); + showHelp(p->out, "import"); + rc = 1; + goto meta_command_exit; + } + }else if( strcmp(z,"-v")==0 ){ + eVerbose++; + }else if( strcmp(z,"-skip")==0 && iout, "ERROR: unknown option: \"%s\". Usage:\n", z); + showHelp(p->out, "import"); + rc = 1; + goto meta_command_exit; + } + } + if( zTable==0 ){ + utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n", + zFile==0 ? "FILE" : "TABLE"); + showHelp(p->out, "import"); + rc = 1; + goto meta_command_exit; + } + seenInterrupt = 0; + open_db(p, 0); + if( useOutputMode ){ + /* If neither the --csv or --ascii options are specified, then set ** the column and row separator characters from the output mode. */ - nSep = strlen30(p->colSeparator); - if( nSep==0 ){ - raw_printf(stderr, - "Error: non-null column separator required for import\n"); - rc = 1; - goto meta_command_exit; - } - if( nSep>1 ){ - raw_printf(stderr, - "Error: multi-character column separators not allowed" - " for import\n"); - rc = 1; - goto meta_command_exit; - } - nSep = strlen30(p->rowSeparator); - if( nSep==0 ){ - raw_printf(stderr, - "Error: non-null row separator required for import\n"); - rc = 1; - goto meta_command_exit; - } - if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){ - /* When importing CSV (only), if the row separator is set to the + nSep = strlen30(p->colSeparator); + if( nSep==0 ){ + raw_printf(stderr, + "Error: non-null column separator required for import\n"); + rc = 1; + goto meta_command_exit; + } + if( nSep>1 ){ + raw_printf(stderr, + "Error: multi-character column separators not allowed" + " for import\n"); + rc = 1; + goto meta_command_exit; + } + nSep = strlen30(p->rowSeparator); + if( nSep==0 ){ + raw_printf(stderr, + "Error: non-null row separator required for import\n"); + rc = 1; + goto meta_command_exit; + } + if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){ + /* When importing CSV (only), if the row separator is set to the ** default output row separator, change it to the default input ** row separator. This avoids having to maintain different input ** and output row separators. */ - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); - nSep = strlen30(p->rowSeparator); - } - if( nSep>1 ){ - raw_printf(stderr, "Error: multi-character row separators not allowed" - " for import\n"); - rc = 1; - goto meta_command_exit; - } - sCtx.cColSep = p->colSeparator[0]; - sCtx.cRowSep = p->rowSeparator[0]; - } - sCtx.zFile = zFile; - sCtx.nLine = 1; - if( sCtx.zFile[0]=='|' ){ + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); + nSep = strlen30(p->rowSeparator); + } + if( nSep>1 ){ + raw_printf(stderr, "Error: multi-character row separators not allowed" + " for import\n"); + rc = 1; + goto meta_command_exit; + } + sCtx.cColSep = p->colSeparator[0]; + sCtx.cRowSep = p->rowSeparator[0]; + } + sCtx.zFile = zFile; + sCtx.nLine = 1; + if( sCtx.zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - raw_printf(stderr, "Error: pipes are not supported in this OS\n"); - rc = 1; - goto meta_command_exit; + raw_printf(stderr, "Error: pipes are not supported in this OS\n"); + rc = 1; + goto meta_command_exit; #else - sCtx.in = popen(sCtx.zFile+1, "r"); - sCtx.zFile = ""; - sCtx.xCloser = pclose; + sCtx.in = popen(sCtx.zFile+1, "r"); + sCtx.zFile = ""; + sCtx.xCloser = pclose; #endif - }else{ - sCtx.in = fopen(sCtx.zFile, "rb"); - sCtx.xCloser = fclose; - } - if( sCtx.in==0 ){ - utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); - rc = 1; - import_cleanup(&sCtx); - goto meta_command_exit; - } - if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){ - char zSep[2]; - zSep[1] = 0; - zSep[0] = sCtx.cColSep; - utf8_printf(p->out, "Column separator "); - output_c_string(p->out, zSep); - utf8_printf(p->out, ", row separator "); - zSep[0] = sCtx.cRowSep; - output_c_string(p->out, zSep); - utf8_printf(p->out, "\n"); - } - while( (nSkip--)>0 ){ - while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){} - } - zSql = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); - if( zSql==0 ){ - import_cleanup(&sCtx); - shell_out_of_memory(); - } - nByte = strlen30(zSql); - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ - if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ - char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\"", zTable); - char cSep = '('; - while( xRead(&sCtx) ){ - zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z); - cSep = ','; - if( sCtx.cTerm!=sCtx.cColSep ) break; - } - if( cSep=='(' ){ - sqlite3_free(zCreate); - import_cleanup(&sCtx); - utf8_printf(stderr,"%s: empty file\n", sCtx.zFile); - rc = 1; - goto meta_command_exit; - } - zCreate = sqlite3_mprintf("%z\n)", zCreate); - if( eVerbose>=1 ){ - utf8_printf(p->out, "%s\n", zCreate); - } - rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); - sqlite3_free(zCreate); - if( rc ){ - utf8_printf(stderr, "CREATE TABLE \"%s\"(...) failed: %s\n", zTable, - sqlite3_errmsg(p->db)); - import_cleanup(&sCtx); - rc = 1; - goto meta_command_exit; - } - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - } - sqlite3_free(zSql); - if( rc ){ - if (pStmt) sqlite3_finalize(pStmt); - utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db)); - import_cleanup(&sCtx); - rc = 1; - goto meta_command_exit; - } - nCol = sqlite3_column_count(pStmt); - sqlite3_finalize(pStmt); - pStmt = 0; - if( nCol==0 ) return 0; /* no columns, no error */ - zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 ); - if( zSql==0 ){ - import_cleanup(&sCtx); - shell_out_of_memory(); - } - sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); - j = strlen30(zSql); - for(i=1; i=2 ){ - utf8_printf(p->out, "Insert using: %s\n", zSql); - } - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - if( rc ){ - utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); - if (pStmt) sqlite3_finalize(pStmt); - import_cleanup(&sCtx); - rc = 1; - goto meta_command_exit; - } - needCommit = sqlite3_get_autocommit(p->db); - if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0); - do{ - int startLine = sCtx.nLine; - for(i=0; i=2 || (eVerbose>=1 && useOutputMode) ){ + char zSep[2]; + zSep[1] = 0; + zSep[0] = sCtx.cColSep; + utf8_printf(p->out, "Column separator "); + output_c_string(p->out, zSep); + utf8_printf(p->out, ", row separator "); + zSep[0] = sCtx.cRowSep; + output_c_string(p->out, zSep); + utf8_printf(p->out, "\n"); + } + while( (nSkip--)>0 ){ + while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){} + } + zSql = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); + if( zSql==0 ){ + import_cleanup(&sCtx); + shell_out_of_memory(); + } + nByte = strlen30(zSql); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + import_append_char(&sCtx, 0); /* To ensure sCtx.z is allocated */ + if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(p->db))==0 ){ + char *zCreate = sqlite3_mprintf("CREATE TABLE \"%w\"", zTable); + char cSep = '('; + while( xRead(&sCtx) ){ + zCreate = sqlite3_mprintf("%z%c\n \"%w\" TEXT", zCreate, cSep, sCtx.z); + cSep = ','; + if( sCtx.cTerm!=sCtx.cColSep ) break; + } + if( cSep=='(' ){ + sqlite3_free(zCreate); + import_cleanup(&sCtx); + utf8_printf(stderr,"%s: empty file\n", sCtx.zFile); + rc = 1; + goto meta_command_exit; + } + zCreate = sqlite3_mprintf("%z\n)", zCreate); + if( eVerbose>=1 ){ + utf8_printf(p->out, "%s\n", zCreate); + } + rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); + sqlite3_free(zCreate); + if( rc ){ + utf8_printf(stderr, "CREATE TABLE \"%s\"(...) failed: %s\n", zTable, + sqlite3_errmsg(p->db)); + import_cleanup(&sCtx); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + } + sqlite3_free(zSql); + if( rc ){ + if (pStmt) sqlite3_finalize(pStmt); + utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db)); + import_cleanup(&sCtx); + rc = 1; + goto meta_command_exit; + } + nCol = sqlite3_column_count(pStmt); + sqlite3_finalize(pStmt); + pStmt = 0; + if( nCol==0 ) return 0; /* no columns, no error */ + zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 ); + if( zSql==0 ){ + import_cleanup(&sCtx); + shell_out_of_memory(); + } + sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); + j = strlen30(zSql); + for(i=1; i=2 ){ + utf8_printf(p->out, "Insert using: %s\n", zSql); + } + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rc ){ + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); + if (pStmt) sqlite3_finalize(pStmt); + import_cleanup(&sCtx); + rc = 1; + goto meta_command_exit; + } + needCommit = sqlite3_get_autocommit(p->db); + if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0); + do{ + int startLine = sCtx.nLine; + for(i=0; imode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break; - sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); - if( i=nCol ){ - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); - if( rc!=SQLITE_OK ){ - utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, - startLine, sqlite3_errmsg(p->db)); - sCtx.nErr++; - }else{ - sCtx.nRow++; - } - } - }while( sCtx.cTerm!=EOF ); - - import_cleanup(&sCtx); - sqlite3_finalize(pStmt); - if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0); - if( eVerbose>0 ){ - utf8_printf(p->out, - "Added %d rows with %d errors using %d lines of input\n", - sCtx.nRow, sCtx.nErr, sCtx.nLine-1); - } - }else + if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break; + sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT); + if( i=nCol ){ + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ){ + utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, + startLine, sqlite3_errmsg(p->db)); + sCtx.nErr++; + }else{ + sCtx.nRow++; + } + } + }while( sCtx.cTerm!=EOF ); + + import_cleanup(&sCtx); + sqlite3_finalize(pStmt); + if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0); + if( eVerbose>0 ){ + utf8_printf(p->out, + "Added %d rows with %d errors using %d lines of input\n", + sCtx.nRow, sCtx.nErr, sCtx.nLine-1); + } + }else #ifndef SQLITE_UNTESTABLE - if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){ - char *zSql; - char *zCollist = 0; - sqlite3_stmt *pStmt; - int tnum = 0; - int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */ - int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */ - int i; - if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){ - utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n" - " .imposter off\n"); - /* Also allowed, but not documented: + if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){ + char *zSql; + char *zCollist = 0; + sqlite3_stmt *pStmt; + int tnum = 0; + int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */ + int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */ + int i; + if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){ + utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n" + " .imposter off\n"); + /* Also allowed, but not documented: ** ** .imposter TABLE IMPOSTER ** ** where TABLE is a WITHOUT ROWID table. In that case, the ** imposter is another WITHOUT ROWID table with the columns in ** storage order. */ - rc = 1; - goto meta_command_exit; - } - open_db(p, 0); - if( nArg==2 ){ - sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1); - goto meta_command_exit; - } - zSql = sqlite3_mprintf( - "SELECT rootpage, 0 FROM sqlite_schema" - " WHERE name='%q' AND type='index'" - "UNION ALL " - "SELECT rootpage, 1 FROM sqlite_schema" - " WHERE name='%q' AND type='table'" - " AND sql LIKE '%%without%%rowid%%'", - azArg[1], azArg[1] - ); - sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - if( sqlite3_step(pStmt)==SQLITE_ROW ){ - tnum = sqlite3_column_int(pStmt, 0); - isWO = sqlite3_column_int(pStmt, 1); - } - sqlite3_finalize(pStmt); - zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]); - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - i = 0; - while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - char zLabel[20]; - const char *zCol = (const char*)sqlite3_column_text(pStmt,2); - i++; - if( zCol==0 ){ - if( sqlite3_column_int(pStmt,1)==-1 ){ - zCol = "_ROWID_"; - }else{ - sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i); - zCol = zLabel; - } - } - if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){ - lenPK = (int)strlen(zCollist); - } - if( zCollist==0 ){ - zCollist = sqlite3_mprintf("\"%w\"", zCol); - }else{ - zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol); - } - } - sqlite3_finalize(pStmt); - if( i==0 || tnum==0 ){ - utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]); - rc = 1; - sqlite3_free(zCollist); - goto meta_command_exit; - } - if( lenPK==0 ) lenPK = 100000; - zSql = sqlite3_mprintf( - "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID", - azArg[2], zCollist, lenPK, zCollist); - sqlite3_free(zCollist); - rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum); - if( rc==SQLITE_OK ){ - rc = sqlite3_exec(p->db, zSql, 0, 0, 0); - sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); - if( rc ){ - utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db)); - }else{ - utf8_printf(stdout, "%s;\n", zSql); - raw_printf(stdout, - "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n", - azArg[1], isWO ? "table" : "index" - ); - } - }else{ - raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); - rc = 1; - } - sqlite3_free(zSql); - }else + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + if( nArg==2 ){ + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1); + goto meta_command_exit; + } + zSql = sqlite3_mprintf( + "SELECT rootpage, 0 FROM sqlite_schema" + " WHERE name='%q' AND type='index'" + "UNION ALL " + "SELECT rootpage, 1 FROM sqlite_schema" + " WHERE name='%q' AND type='table'" + " AND sql LIKE '%%without%%rowid%%'", + azArg[1], azArg[1] + ); + sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + tnum = sqlite3_column_int(pStmt, 0); + isWO = sqlite3_column_int(pStmt, 1); + } + sqlite3_finalize(pStmt); + zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]); + rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + i = 0; + while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ + char zLabel[20]; + const char *zCol = (const char*)sqlite3_column_text(pStmt,2); + i++; + if( zCol==0 ){ + if( sqlite3_column_int(pStmt,1)==-1 ){ + zCol = "_ROWID_"; + }else{ + sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i); + zCol = zLabel; + } + } + if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){ + lenPK = (int)strlen(zCollist); + } + if( zCollist==0 ){ + zCollist = sqlite3_mprintf("\"%w\"", zCol); + }else{ + zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol); + } + } + sqlite3_finalize(pStmt); + if( i==0 || tnum==0 ){ + utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]); + rc = 1; + sqlite3_free(zCollist); + goto meta_command_exit; + } + if( lenPK==0 ) lenPK = 100000; + zSql = sqlite3_mprintf( + "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID", + azArg[2], zCollist, lenPK, zCollist); + sqlite3_free(zCollist); + rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum); + if( rc==SQLITE_OK ){ + rc = sqlite3_exec(p->db, zSql, 0, 0, 0); + sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); + if( rc ){ + utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db)); + }else{ + utf8_printf(stdout, "%s;\n", zSql); + raw_printf(stdout, + "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n", + azArg[1], isWO ? "table" : "index" + ); + } + }else{ + raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); + rc = 1; + } + sqlite3_free(zSql); + }else #endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */ #ifdef SQLITE_ENABLE_IOTRACE - if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ - SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...); - if( iotrace && iotrace!=stdout ) fclose(iotrace); - iotrace = 0; - if( nArg<2 ){ - sqlite3IoTrace = 0; - }else if( strcmp(azArg[1], "-")==0 ){ - sqlite3IoTrace = iotracePrintf; - iotrace = stdout; - }else{ - iotrace = fopen(azArg[1], "w"); - if( iotrace==0 ){ - utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); - sqlite3IoTrace = 0; - rc = 1; - }else{ - sqlite3IoTrace = iotracePrintf; - } - } - }else + if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ + SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...); + if( iotrace && iotrace!=stdout ) fclose(iotrace); + iotrace = 0; + if( nArg<2 ){ + sqlite3IoTrace = 0; + }else if( strcmp(azArg[1], "-")==0 ){ + sqlite3IoTrace = iotracePrintf; + iotrace = stdout; + }else{ + iotrace = fopen(azArg[1], "w"); + if( iotrace==0 ){ + utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); + sqlite3IoTrace = 0; + rc = 1; + }else{ + sqlite3IoTrace = iotracePrintf; + } + } + }else #endif - if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){ - static const struct { - const char *zLimitName; /* Name of a limit */ - int limitCode; /* Integer code for that limit */ - } aLimit[] = { - { "length", SQLITE_LIMIT_LENGTH }, - { "sql_length", SQLITE_LIMIT_SQL_LENGTH }, - { "column", SQLITE_LIMIT_COLUMN }, - { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH }, - { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT }, - { "vdbe_op", SQLITE_LIMIT_VDBE_OP }, - { "function_arg", SQLITE_LIMIT_FUNCTION_ARG }, - { "attached", SQLITE_LIMIT_ATTACHED }, - { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, - { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, - { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, - { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, - }; - int i, n2; - open_db(p, 0); - if( nArg==1 ){ - for(i=0; idb, aLimit[i].limitCode, -1)); - } - }else if( nArg>3 ){ - raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n"); - rc = 1; - goto meta_command_exit; - }else{ - int iLimit = -1; - n2 = strlen30(azArg[1]); - for(i=0; idb, aLimit[iLimit].limitCode, - (int)integerValue(azArg[2])); - } - printf("%20s %d\n", aLimit[iLimit].zLimitName, - sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); - } - }else - - if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){ - open_db(p, 0); - lintDotCommand(p, azArg, nArg); - }else + if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){ + static const struct { + const char *zLimitName; /* Name of a limit */ + int limitCode; /* Integer code for that limit */ + } aLimit[] = { + { "length", SQLITE_LIMIT_LENGTH }, + { "sql_length", SQLITE_LIMIT_SQL_LENGTH }, + { "column", SQLITE_LIMIT_COLUMN }, + { "expr_depth", SQLITE_LIMIT_EXPR_DEPTH }, + { "compound_select", SQLITE_LIMIT_COMPOUND_SELECT }, + { "vdbe_op", SQLITE_LIMIT_VDBE_OP }, + { "function_arg", SQLITE_LIMIT_FUNCTION_ARG }, + { "attached", SQLITE_LIMIT_ATTACHED }, + { "like_pattern_length", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, + { "variable_number", SQLITE_LIMIT_VARIABLE_NUMBER }, + { "trigger_depth", SQLITE_LIMIT_TRIGGER_DEPTH }, + { "worker_threads", SQLITE_LIMIT_WORKER_THREADS }, + }; + int i, n2; + open_db(p, 0); + if( nArg==1 ){ + for(i=0; idb, aLimit[i].limitCode, -1)); + } + }else if( nArg>3 ){ + raw_printf(stderr, "Usage: .limit NAME ?NEW-VALUE?\n"); + rc = 1; + goto meta_command_exit; + }else{ + int iLimit = -1; + n2 = strlen30(azArg[1]); + for(i=0; idb, aLimit[iLimit].limitCode, + (int)integerValue(azArg[2])); + } + printf("%20s %d\n", aLimit[iLimit].zLimitName, + sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); + } + }else + + if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){ + open_db(p, 0); + lintDotCommand(p, azArg, nArg); + }else #ifndef SQLITE_OMIT_LOAD_EXTENSION - if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ - const char *zFile, *zProc; - char *zErrMsg = 0; - failIfSafeMode(p, "cannot run .load in safe mode"); - if( nArg<2 ){ - raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); - rc = 1; - goto meta_command_exit; - } - zFile = azArg[1]; - zProc = nArg>=3 ? azArg[2] : 0; - open_db(p, 0); - rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); - if( rc!=SQLITE_OK ){ - utf8_printf(stderr, "Error: %s\n", zErrMsg); - sqlite3_free(zErrMsg); - rc = 1; - } - }else + if( c=='l' && strncmp(azArg[0], "load", n)==0 ){ + const char *zFile, *zProc; + char *zErrMsg = 0; + failIfSafeMode(p, "cannot run .load in safe mode"); + if( nArg<2 ){ + raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n"); + rc = 1; + goto meta_command_exit; + } + zFile = azArg[1]; + zProc = nArg>=3 ? azArg[2] : 0; + open_db(p, 0); + rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); + if( rc!=SQLITE_OK ){ + utf8_printf(stderr, "Error: %s\n", zErrMsg); + sqlite3_free(zErrMsg); + rc = 1; + } + }else #endif - if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ - failIfSafeMode(p, "cannot run .log in safe mode"); - if( nArg!=2 ){ - raw_printf(stderr, "Usage: .log FILENAME\n"); - rc = 1; - }else{ - const char *zFile = azArg[1]; - output_file_close(p->pLog); - p->pLog = output_file_open(zFile, 0); - } - }else - - if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ - const char *zMode = nArg>=2 ? azArg[1] : ""; - int n2 = strlen30(zMode); - int c2 = zMode[0]; - if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ - p->mode = MODE_Line; - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); - }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){ - p->mode = MODE_Column; - if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){ - p->showHeader = 1; - } - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); - }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){ - p->mode = MODE_List; - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column); - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); - }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){ - p->mode = MODE_Html; - }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){ - p->mode = MODE_Tcl; - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space); - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); - }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){ - p->mode = MODE_Csv; - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); - }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){ - p->mode = MODE_List; - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab); - }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ - p->mode = MODE_Insert; - set_table_name(p, nArg>=3 ? azArg[2] : "table"); - }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){ - p->mode = MODE_Quote; - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); - }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){ - p->mode = MODE_Ascii; - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit); - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record); - }else if( c2=='m' && strncmp(azArg[1],"markdown",n2)==0 ){ - p->mode = MODE_Markdown; - }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){ - p->mode = MODE_Table; - }else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){ - p->mode = MODE_Box; - }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){ - p->mode = MODE_Json; - }else if( nArg==1 ){ - raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]); - }else{ - raw_printf(stderr, "Error: mode should be one of: " - "ascii box column csv html insert json line list markdown " - "quote table tabs tcl\n"); - rc = 1; - } - p->cMode = p->mode; - }else - - if( c=='n' && strcmp(azArg[0], "nonce")==0 ){ - if( nArg!=2 ){ - raw_printf(stderr, "Usage: .nonce NONCE\n"); - rc = 1; - }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){ - raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", p->lineno, azArg[1]); - exit(1); - }else{ - p->bSafeMode = 0; - return 0; /* Return immediately to bypass the safe mode reset + if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ + failIfSafeMode(p, "cannot run .log in safe mode"); + if( nArg!=2 ){ + raw_printf(stderr, "Usage: .log FILENAME\n"); + rc = 1; + }else{ + const char *zFile = azArg[1]; + output_file_close(p->pLog); + p->pLog = output_file_open(zFile, 0); + } + }else + + if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ + const char *zMode = nArg>=2 ? azArg[1] : ""; + int n2 = strlen30(zMode); + int c2 = zMode[0]; + if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){ + p->mode = MODE_Line; + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); + }else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){ + p->mode = MODE_Column; + if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){ + p->showHeader = 1; + } + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); + }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){ + p->mode = MODE_List; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); + }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){ + p->mode = MODE_Html; + }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){ + p->mode = MODE_Tcl; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); + }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){ + p->mode = MODE_Csv; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); + }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){ + p->mode = MODE_List; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab); + }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){ + p->mode = MODE_Insert; + set_table_name(p, nArg>=3 ? azArg[2] : "table"); + }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){ + p->mode = MODE_Quote; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); + }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){ + p->mode = MODE_Ascii; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record); + }else if( c2=='m' && strncmp(azArg[1],"markdown",n2)==0 ){ + p->mode = MODE_Markdown; + }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){ + p->mode = MODE_Table; + }else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){ + p->mode = MODE_Box; + }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){ + p->mode = MODE_Json; + }else if( nArg==1 ){ + raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]); + }else{ + raw_printf(stderr, "Error: mode should be one of: " + "ascii box column csv html insert json line list markdown " + "quote table tabs tcl\n"); + rc = 1; + } + p->cMode = p->mode; + }else + + if( c=='n' && strcmp(azArg[0], "nonce")==0 ){ + if( nArg!=2 ){ + raw_printf(stderr, "Usage: .nonce NONCE\n"); + rc = 1; + }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){ + raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", p->lineno, azArg[1]); + exit(1); + }else{ + p->bSafeMode = 0; + return 0; /* Return immediately to bypass the safe mode reset ** at the end of this procedure */ - } - }else - - if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){ - if( nArg==2 ){ - sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, - "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]); - }else{ - raw_printf(stderr, "Usage: .nullvalue STRING\n"); - rc = 1; - } - }else + } + }else + + if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){ + if( nArg==2 ){ + sqlite3_snprintf(sizeof(p->nullValue), p->nullValue, + "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]); + }else{ + raw_printf(stderr, "Usage: .nullvalue STRING\n"); + rc = 1; + } + }else #ifdef SQLITE_DEBUG - if( c=='o' && strcmp(azArg[0],"oom")==0 ){ - int i; - for(i=1; iout, "missing argument on \"%s\"\n", azArg[i]); - rc = 1; - }else{ - oomRepeat = (int)integerValue(azArg[++i]); - } - }else if( IsDigit(z[0]) ){ - oomCounter = (int)integerValue(azArg[i]); - }else{ - raw_printf(p->out, "unknown argument: \"%s\"\n", azArg[i]); - raw_printf(p->out, "Usage: .oom [--repeat N] [M]\n"); - rc = 1; - } - } - if( rc==0 ){ - raw_printf(p->out, "oomCounter = %d\n", oomCounter); - raw_printf(p->out, "oomRepeat = %d\n", oomRepeat); - } - }else + if( c=='o' && strcmp(azArg[0],"oom")==0 ){ + int i; + for(i=1; iout, "missing argument on \"%s\"\n", azArg[i]); + rc = 1; + }else{ + oomRepeat = (int)integerValue(azArg[++i]); + } + }else if( IsDigit(z[0]) ){ + oomCounter = (int)integerValue(azArg[i]); + }else{ + raw_printf(p->out, "unknown argument: \"%s\"\n", azArg[i]); + raw_printf(p->out, "Usage: .oom [--repeat N] [M]\n"); + rc = 1; + } + } + if( rc==0 ){ + raw_printf(p->out, "oomCounter = %d\n", oomCounter); + raw_printf(p->out, "oomRepeat = %d\n", oomRepeat); + } + }else #endif /* SQLITE_DEBUG */ - if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){ - char *zNewFilename = 0; /* Name of the database file to open */ - int iName = 1; /* Index in azArg[] of the filename */ - int newFlag = 0; /* True to delete file before opening */ - int openMode = SHELL_OPEN_UNSPEC; - - /* Check for command-line arguments */ - for(iName=1; iName=2 ){ + char *zNewFilename = 0; /* Name of the database file to open */ + int iName = 1; /* Index in azArg[] of the filename */ + int newFlag = 0; /* True to delete file before opening */ + int openMode = SHELL_OPEN_UNSPEC; + + /* Check for command-line arguments */ + for(iName=1; iNameopenFlags |= SQLITE_OPEN_NOFOLLOW; + }else if( optionMatch(z, "append") ){ + openMode = SHELL_OPEN_APPENDVFS; + }else if( optionMatch(z, "readonly") ){ + openMode = SHELL_OPEN_READONLY; + }else if( optionMatch(z, "nofollow") ){ + p->openFlags |= SQLITE_OPEN_NOFOLLOW; #ifndef SQLITE_OMIT_DESERIALIZE - }else if( optionMatch(z, "deserialize") ){ - openMode = SHELL_OPEN_DESERIALIZE; - }else if( optionMatch(z, "hexdb") ){ - openMode = SHELL_OPEN_HEXDB; - }else if( optionMatch(z, "maxsize") && iName+1szMax = integerValue(azArg[++iName]); + }else if( optionMatch(z, "deserialize") ){ + openMode = SHELL_OPEN_DESERIALIZE; + }else if( optionMatch(z, "hexdb") ){ + openMode = SHELL_OPEN_HEXDB; + }else if( optionMatch(z, "maxsize") && iName+1szMax = integerValue(azArg[++iName]); #endif /* SQLITE_OMIT_DESERIALIZE */ - }else if( z[0]=='-' ){ - utf8_printf(stderr, "unknown option: %s\n", z); - rc = 1; - goto meta_command_exit; - }else if( zNewFilename ){ - utf8_printf(stderr, "extra argument: \"%s\"\n", z); - rc = 1; - goto meta_command_exit; - }else{ - zNewFilename = sqlite3_mprintf("%s", z); - } - } - - /* Close the existing database */ - session_close_all(p, -1); - close_db(p->db); - p->db = 0; - p->pAuxDb->zDbFilename = 0; - sqlite3_free(p->pAuxDb->zFreeOnClose); - p->pAuxDb->zFreeOnClose = 0; - p->openMode = openMode; - p->openFlags = 0; - p->szMax = 0; - - /* If a filename is specified, try to open it first */ - if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){ - if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename); - if( p->bSafeMode - && p->openMode!=SHELL_OPEN_HEXDB - && zNewFilename - && strcmp(zNewFilename,":memory:")!=0 - ){ - failIfSafeMode(p, "cannot open disk-based database files in safe mode"); - } - p->pAuxDb->zDbFilename = zNewFilename; - open_db(p, OPEN_DB_KEEPALIVE); - if( p->db==0 ){ - utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename); - sqlite3_free(zNewFilename); - }else{ - p->pAuxDb->zFreeOnClose = zNewFilename; - } - } - if( p->db==0 ){ - /* As a fall-back open a TEMP database */ - p->pAuxDb->zDbFilename = 0; - open_db(p, 0); - } - }else - - if( (c=='o' - && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0)) - || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0) - ){ - char *zFile = 0; - int bTxtMode = 0; - int i; - int eMode = 0; - int bBOM = 0; - int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */ - - failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); - if( c=='e' ){ - eMode = 'x'; - bOnce = 2; - }else if( strncmp(azArg[0],"once",n)==0 ){ - bOnce = 1; - } - for(i=1; iout, "ERROR: unknown option: \"%s\". Usage:\n", - azArg[i]); - showHelp(p->out, azArg[0]); - rc = 1; - goto meta_command_exit; - } - }else if( zFile==0 && eMode!='e' && eMode!='x' ){ - zFile = sqlite3_mprintf("%s", z); - if( zFile[0]=='|' ){ - while( i+1out,"ERROR: extra parameter: \"%s\". Usage:\n", - azArg[i]); - showHelp(p->out, azArg[0]); - rc = 1; - sqlite3_free(zFile); - goto meta_command_exit; - } - } - if( zFile==0 ) zFile = sqlite3_mprintf("stdout"); - if( bOnce ){ - p->outCount = 2; - }else{ - p->outCount = 0; - } - output_reset(p); + }else if( z[0]=='-' ){ + utf8_printf(stderr, "unknown option: %s\n", z); + rc = 1; + goto meta_command_exit; + }else if( zNewFilename ){ + utf8_printf(stderr, "extra argument: \"%s\"\n", z); + rc = 1; + goto meta_command_exit; + }else{ + zNewFilename = sqlite3_mprintf("%s", z); + } + } + + /* Close the existing database */ + session_close_all(p, -1); + close_db(p->db); + p->db = 0; + p->pAuxDb->zDbFilename = 0; + sqlite3_free(p->pAuxDb->zFreeOnClose); + p->pAuxDb->zFreeOnClose = 0; + p->openMode = openMode; + p->openFlags = 0; + p->szMax = 0; + + /* If a filename is specified, try to open it first */ + if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){ + if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename); + if( p->bSafeMode + && p->openMode!=SHELL_OPEN_HEXDB + && zNewFilename + && strcmp(zNewFilename,":memory:")!=0 + ){ + failIfSafeMode(p, "cannot open disk-based database files in safe mode"); + } + p->pAuxDb->zDbFilename = zNewFilename; + open_db(p, OPEN_DB_KEEPALIVE); + if( p->db==0 ){ + utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename); + sqlite3_free(zNewFilename); + }else{ + p->pAuxDb->zFreeOnClose = zNewFilename; + } + } + if( p->db==0 ){ + /* As a fall-back open a TEMP database */ + p->pAuxDb->zDbFilename = 0; + open_db(p, 0); + } + }else + + if( (c=='o' + && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0)) + || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0) + ){ + char *zFile = 0; + int bTxtMode = 0; + int i; + int eMode = 0; + int bBOM = 0; + int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */ + + failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); + if( c=='e' ){ + eMode = 'x'; + bOnce = 2; + }else if( strncmp(azArg[0],"once",n)==0 ){ + bOnce = 1; + } + for(i=1; iout, "ERROR: unknown option: \"%s\". Usage:\n", + azArg[i]); + showHelp(p->out, azArg[0]); + rc = 1; + goto meta_command_exit; + } + }else if( zFile==0 && eMode!='e' && eMode!='x' ){ + zFile = sqlite3_mprintf("%s", z); + if( zFile[0]=='|' ){ + while( i+1out,"ERROR: extra parameter: \"%s\". Usage:\n", + azArg[i]); + showHelp(p->out, azArg[0]); + rc = 1; + sqlite3_free(zFile); + goto meta_command_exit; + } + } + if( zFile==0 ) zFile = sqlite3_mprintf("stdout"); + if( bOnce ){ + p->outCount = 2; + }else{ + p->outCount = 0; + } + output_reset(p); #ifndef SQLITE_NOHAVE_SYSTEM - if( eMode=='e' || eMode=='x' ){ - p->doXdgOpen = 1; - outputModePush(p); - if( eMode=='x' ){ - /* spreadsheet mode. Output as CSV. */ - newTempFile(p, "csv"); - ShellClearFlag(p, SHFLG_Echo); - p->mode = MODE_Csv; - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); - }else{ - /* text editor mode */ - newTempFile(p, "txt"); - bTxtMode = 1; - } - sqlite3_free(zFile); - zFile = sqlite3_mprintf("%s", p->zTempFile); - } + if( eMode=='e' || eMode=='x' ){ + p->doXdgOpen = 1; + outputModePush(p); + if( eMode=='x' ){ + /* spreadsheet mode. Output as CSV. */ + newTempFile(p, "csv"); + ShellClearFlag(p, SHFLG_Echo); + p->mode = MODE_Csv; + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); + }else{ + /* text editor mode */ + newTempFile(p, "txt"); + bTxtMode = 1; + } + sqlite3_free(zFile); + zFile = sqlite3_mprintf("%s", p->zTempFile); + } #endif /* SQLITE_NOHAVE_SYSTEM */ - if( zFile[0]=='|' ){ + if( zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - raw_printf(stderr, "Error: pipes are not supported in this OS\n"); - rc = 1; - p->out = stdout; + raw_printf(stderr, "Error: pipes are not supported in this OS\n"); + rc = 1; + p->out = stdout; #else - p->out = popen(zFile + 1, "w"); - if( p->out==0 ){ - utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); - p->out = stdout; - rc = 1; - }else{ - if( bBOM ) fprintf(p->out,"\357\273\277"); - sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); - } + p->out = popen(zFile + 1, "w"); + if( p->out==0 ){ + utf8_printf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1); + p->out = stdout; + rc = 1; + }else{ + if( bBOM ) fprintf(p->out,"\357\273\277"); + sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); + } #endif - }else{ - p->out = output_file_open(zFile, bTxtMode); - if( p->out==0 ){ - if( strcmp(zFile,"off")!=0 ){ - utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile); - } - p->out = stdout; - rc = 1; - } else { - if( bBOM ) fprintf(p->out,"\357\273\277"); - sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); - } - } - sqlite3_free(zFile); - }else - - if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){ - open_db(p,0); - if( nArg<=1 ) goto parameter_syntax_error; - - /* .parameter clear + }else{ + p->out = output_file_open(zFile, bTxtMode); + if( p->out==0 ){ + if( strcmp(zFile,"off")!=0 ){ + utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile); + } + p->out = stdout; + rc = 1; + } else { + if( bBOM ) fprintf(p->out,"\357\273\277"); + sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); + } + } + sqlite3_free(zFile); + }else + + if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){ + open_db(p,0); + if( nArg<=1 ) goto parameter_syntax_error; + + /* .parameter clear ** Clear all bind parameters by dropping the TEMP table that holds them. */ - if( nArg==2 && strcmp(azArg[1],"clear")==0 ){ - sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;", - 0, 0, 0); - }else + if( nArg==2 && strcmp(azArg[1],"clear")==0 ){ + sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;", + 0, 0, 0); + }else - /* .parameter list + /* .parameter list ** List all bind parameters. */ - if( nArg==2 && strcmp(azArg[1],"list")==0 ){ - sqlite3_stmt *pStmt = 0; - int rx; - int len = 0; - rx = sqlite3_prepare_v2(p->db, - "SELECT max(length(key)) " - "FROM temp.sqlite_parameters;", -1, &pStmt, 0); - if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - len = sqlite3_column_int(pStmt, 0); - if( len>40 ) len = 40; - } - sqlite3_finalize(pStmt); - pStmt = 0; - if( len ){ - rx = sqlite3_prepare_v2(p->db, - "SELECT key, quote(value) " - "FROM temp.sqlite_parameters;", -1, &pStmt, 0); - while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ - utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0), - sqlite3_column_text(pStmt,1)); - } - sqlite3_finalize(pStmt); - } - }else - - /* .parameter init + if( nArg==2 && strcmp(azArg[1],"list")==0 ){ + sqlite3_stmt *pStmt = 0; + int rx; + int len = 0; + rx = sqlite3_prepare_v2(p->db, + "SELECT max(length(key)) " + "FROM temp.sqlite_parameters;", -1, &pStmt, 0); + if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ + len = sqlite3_column_int(pStmt, 0); + if( len>40 ) len = 40; + } + sqlite3_finalize(pStmt); + pStmt = 0; + if( len ){ + rx = sqlite3_prepare_v2(p->db, + "SELECT key, quote(value) " + "FROM temp.sqlite_parameters;", -1, &pStmt, 0); + while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){ + utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0), + sqlite3_column_text(pStmt,1)); + } + sqlite3_finalize(pStmt); + } + }else + + /* .parameter init ** Make sure the TEMP table used to hold bind parameters exists. ** Create it if necessary. */ - if( nArg==2 && strcmp(azArg[1],"init")==0 ){ - bind_table_init(p); - }else + if( nArg==2 && strcmp(azArg[1],"init")==0 ){ + bind_table_init(p); + }else - /* .parameter set NAME VALUE + /* .parameter set NAME VALUE ** Set or reset a bind parameter. NAME should be the full parameter ** name exactly as it appears in the query. (ex: $abc, @def). The ** VALUE can be in either SQL literal notation, or if not it will be ** understood to be a text string. */ - if( nArg==4 && strcmp(azArg[1],"set")==0 ){ - int rx; - char *zSql; - sqlite3_stmt *pStmt; - const char *zKey = azArg[2]; - const char *zValue = azArg[3]; - bind_table_init(p); - zSql = sqlite3_mprintf( - "REPLACE INTO temp.sqlite_parameters(key,value)" - "VALUES(%Q,%s);", zKey, zValue); - if( zSql==0 ) shell_out_of_memory(); - pStmt = 0; - rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - if( rx!=SQLITE_OK ){ - sqlite3_finalize(pStmt); - pStmt = 0; - zSql = sqlite3_mprintf( - "REPLACE INTO temp.sqlite_parameters(key,value)" - "VALUES(%Q,%Q);", zKey, zValue); - if( zSql==0 ) shell_out_of_memory(); - rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - sqlite3_free(zSql); - if( rx!=SQLITE_OK ){ - utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db)); - sqlite3_finalize(pStmt); - pStmt = 0; - rc = 1; - } - } - sqlite3_step(pStmt); - sqlite3_finalize(pStmt); - }else - - /* .parameter unset NAME + if( nArg==4 && strcmp(azArg[1],"set")==0 ){ + int rx; + char *zSql; + sqlite3_stmt *pStmt; + const char *zKey = azArg[2]; + const char *zValue = azArg[3]; + bind_table_init(p); + zSql = sqlite3_mprintf( + "REPLACE INTO temp.sqlite_parameters(key,value)" + "VALUES(%Q,%s);", zKey, zValue); + if( zSql==0 ) shell_out_of_memory(); + pStmt = 0; + rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rx!=SQLITE_OK ){ + sqlite3_finalize(pStmt); + pStmt = 0; + zSql = sqlite3_mprintf( + "REPLACE INTO temp.sqlite_parameters(key,value)" + "VALUES(%Q,%Q);", zKey, zValue); + if( zSql==0 ) shell_out_of_memory(); + rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + sqlite3_free(zSql); + if( rx!=SQLITE_OK ){ + utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db)); + sqlite3_finalize(pStmt); + pStmt = 0; + rc = 1; + } + } + sqlite3_step(pStmt); + sqlite3_finalize(pStmt); + }else + + /* .parameter unset NAME ** Remove the NAME binding from the parameter binding table, if it ** exists. */ - if( nArg==3 && strcmp(azArg[1],"unset")==0 ){ - char *zSql = sqlite3_mprintf( - "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]); - if( zSql==0 ) shell_out_of_memory(); - sqlite3_exec(p->db, zSql, 0, 0, 0); - sqlite3_free(zSql); - }else - /* If no command name matches, show a syntax error */ - parameter_syntax_error: - showHelp(p->out, "parameter"); - }else - - if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){ - int i; - for(i=1; i1 ) raw_printf(p->out, " "); - utf8_printf(p->out, "%s", azArg[i]); - } - raw_printf(p->out, "\n"); - }else + if( nArg==3 && strcmp(azArg[1],"unset")==0 ){ + char *zSql = sqlite3_mprintf( + "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]); + if( zSql==0 ) shell_out_of_memory(); + sqlite3_exec(p->db, zSql, 0, 0, 0); + sqlite3_free(zSql); + }else + /* If no command name matches, show a syntax error */ + parameter_syntax_error: + showHelp(p->out, "parameter"); + }else + + if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){ + int i; + for(i=1; i1 ) raw_printf(p->out, " "); + utf8_printf(p->out, "%s", azArg[i]); + } + raw_printf(p->out, "\n"); + }else #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - if( c=='p' && n>=3 && strncmp(azArg[0], "progress", n)==0 ){ - int i; - int nn = 0; - p->flgProgress = 0; - p->mxProgress = 0; - p->nProgress = 0; - for(i=1; iflgProgress |= SHELL_PROGRESS_QUIET; - continue; - } - if( strcmp(z,"reset")==0 ){ - p->flgProgress |= SHELL_PROGRESS_RESET; - continue; - } - if( strcmp(z,"once")==0 ){ - p->flgProgress |= SHELL_PROGRESS_ONCE; - continue; - } - if( strcmp(z,"limit")==0 ){ - if( i+1>=nArg ){ - utf8_printf(stderr, "Error: missing argument on --limit\n"); - rc = 1; - goto meta_command_exit; - }else{ - p->mxProgress = (int)integerValue(azArg[++i]); - } - continue; - } - utf8_printf(stderr, "Error: unknown option: \"%s\"\n", azArg[i]); - rc = 1; - goto meta_command_exit; - }else{ - nn = (int)integerValue(z); - } - } - open_db(p, 0); - sqlite3_progress_handler(p->db, nn, progress_handler, p); - }else + if( c=='p' && n>=3 && strncmp(azArg[0], "progress", n)==0 ){ + int i; + int nn = 0; + p->flgProgress = 0; + p->mxProgress = 0; + p->nProgress = 0; + for(i=1; iflgProgress |= SHELL_PROGRESS_QUIET; + continue; + } + if( strcmp(z,"reset")==0 ){ + p->flgProgress |= SHELL_PROGRESS_RESET; + continue; + } + if( strcmp(z,"once")==0 ){ + p->flgProgress |= SHELL_PROGRESS_ONCE; + continue; + } + if( strcmp(z,"limit")==0 ){ + if( i+1>=nArg ){ + utf8_printf(stderr, "Error: missing argument on --limit\n"); + rc = 1; + goto meta_command_exit; + }else{ + p->mxProgress = (int)integerValue(azArg[++i]); + } + continue; + } + utf8_printf(stderr, "Error: unknown option: \"%s\"\n", azArg[i]); + rc = 1; + goto meta_command_exit; + }else{ + nn = (int)integerValue(z); + } + } + open_db(p, 0); + sqlite3_progress_handler(p->db, nn, progress_handler, p); + }else #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ - if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){ - if( nArg >= 2) { - strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); - } - if( nArg >= 3) { - strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1); - } - }else - - if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){ - rc = 2; - }else - - if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){ - FILE *inSaved = p->in; - int savedLineno = p->lineno; - failIfSafeMode(p, "cannot run .read in safe mode"); - if( nArg!=2 ){ - raw_printf(stderr, "Usage: .read FILE\n"); - rc = 1; - goto meta_command_exit; - } - if( azArg[1][0]=='|' ){ + if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){ + if( nArg >= 2) { + strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1); + } + if( nArg >= 3) { + strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1); + } + }else + + if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){ + rc = 2; + }else + + if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){ + FILE *inSaved = p->in; + int savedLineno = p->lineno; + failIfSafeMode(p, "cannot run .read in safe mode"); + if( nArg!=2 ){ + raw_printf(stderr, "Usage: .read FILE\n"); + rc = 1; + goto meta_command_exit; + } + if( azArg[1][0]=='|' ){ #ifdef SQLITE_OMIT_POPEN - raw_printf(stderr, "Error: pipes are not supported in this OS\n"); - rc = 1; - p->out = stdout; + raw_printf(stderr, "Error: pipes are not supported in this OS\n"); + rc = 1; + p->out = stdout; #else - p->in = popen(azArg[1]+1, "r"); - if( p->in==0 ){ - utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); - rc = 1; - }else{ - rc = process_input(p); - pclose(p->in); - } + p->in = popen(azArg[1]+1, "r"); + if( p->in==0 ){ + utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); + rc = 1; + }else{ + rc = process_input(p); + pclose(p->in); + } #endif - }else if( (p->in = openChrSource(azArg[1]))==0 ){ - utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); - rc = 1; - }else{ - rc = process_input(p); - fclose(p->in); - } - p->in = inSaved; - p->lineno = savedLineno; - }else - - if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){ - const char *zSrcFile; - const char *zDb; - sqlite3 *pSrc; - sqlite3_backup *pBackup; - int nTimeout = 0; - - failIfSafeMode(p, "cannot run .restore in safe mode"); - if( nArg==2 ){ - zSrcFile = azArg[1]; - zDb = "main"; - }else if( nArg==3 ){ - zSrcFile = azArg[2]; - zDb = azArg[1]; - }else{ - raw_printf(stderr, "Usage: .restore ?DB? FILE\n"); - rc = 1; - goto meta_command_exit; - } - rc = sqlite3_open(zSrcFile, &pSrc); - if( rc!=SQLITE_OK ){ - utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); - close_db(pSrc); - return 1; - } - open_db(p, 0); - pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); - if( pBackup==0 ){ - utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); - close_db(pSrc); - return 1; - } - while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK - || rc==SQLITE_BUSY ){ - if( rc==SQLITE_BUSY ){ - if( nTimeout++ >= 3 ) break; - sqlite3_sleep(100); - } - } - sqlite3_backup_finish(pBackup); - if( rc==SQLITE_DONE ){ - rc = 0; - }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ - raw_printf(stderr, "Error: source database is busy\n"); - rc = 1; - }else{ - utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); - rc = 1; - } - close_db(pSrc); - }else - - if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ - if( nArg==2 ){ - p->scanstatsOn = (u8)booleanValue(azArg[1]); + }else if( (p->in = openChrSource(azArg[1]))==0 ){ + utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); + rc = 1; + }else{ + rc = process_input(p); + fclose(p->in); + } + p->in = inSaved; + p->lineno = savedLineno; + }else + + if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){ + const char *zSrcFile; + const char *zDb; + sqlite3 *pSrc; + sqlite3_backup *pBackup; + int nTimeout = 0; + + failIfSafeMode(p, "cannot run .restore in safe mode"); + if( nArg==2 ){ + zSrcFile = azArg[1]; + zDb = "main"; + }else if( nArg==3 ){ + zSrcFile = azArg[2]; + zDb = azArg[1]; + }else{ + raw_printf(stderr, "Usage: .restore ?DB? FILE\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_open(zSrcFile, &pSrc); + if( rc!=SQLITE_OK ){ + utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); + close_db(pSrc); + return 1; + } + open_db(p, 0); + pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); + if( pBackup==0 ){ + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); + close_db(pSrc); + return 1; + } + while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK + || rc==SQLITE_BUSY ){ + if( rc==SQLITE_BUSY ){ + if( nTimeout++ >= 3 ) break; + sqlite3_sleep(100); + } + } + sqlite3_backup_finish(pBackup); + if( rc==SQLITE_DONE ){ + rc = 0; + }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ + raw_printf(stderr, "Error: source database is busy\n"); + rc = 1; + }else{ + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); + rc = 1; + } + close_db(pSrc); + }else + + if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ + if( nArg==2 ){ + p->scanstatsOn = (u8)booleanValue(azArg[1]); #ifndef SQLITE_ENABLE_STMT_SCANSTATUS - raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); + raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); #endif - }else{ - raw_printf(stderr, "Usage: .scanstats on|off\n"); - rc = 1; - } - }else - - if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ - ShellText sSelect; - ShellState data; - char *zErrMsg = 0; - const char *zDiv = "("; - const char *zName = 0; - int iSchema = 0; - int bDebug = 0; - int bNoSystemTabs = 0; - int ii; - - open_db(p, 0); - memcpy(&data, p, sizeof(data)); - data.showHeader = 0; - data.cMode = data.mode = MODE_Semi; - initText(&sSelect); - for(ii=1; iidb, "SELECT name FROM pragma_database_list", - -1, &pStmt, 0); - if( rc ){ - utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); - sqlite3_finalize(pStmt); - rc = 1; - goto meta_command_exit; - } - appendText(&sSelect, "SELECT sql FROM", 0); - iSchema = 0; - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - const char *zDb = (const char*)sqlite3_column_text(pStmt, 0); - char zScNum[30]; - sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema); - appendText(&sSelect, zDiv, 0); - zDiv = " UNION ALL "; - appendText(&sSelect, "SELECT shell_add_schema(sql,", 0); - if( sqlite3_stricmp(zDb, "main")!=0 ){ - appendText(&sSelect, zDb, '\''); - }else{ - appendText(&sSelect, "NULL", 0); - } - appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0); - appendText(&sSelect, zScNum, 0); - appendText(&sSelect, " AS snum, ", 0); - appendText(&sSelect, zDb, '\''); - appendText(&sSelect, " AS sname FROM ", 0); - appendText(&sSelect, zDb, quoteChar(zDb)); - appendText(&sSelect, ".sqlite_schema", 0); - } - sqlite3_finalize(pStmt); + }else{ + raw_printf(stderr, "Usage: .scanstats on|off\n"); + rc = 1; + } + }else + + if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ + ShellText sSelect; + ShellState data; + char *zErrMsg = 0; + const char *zDiv = "("; + const char *zName = 0; + int iSchema = 0; + int bDebug = 0; + int bNoSystemTabs = 0; + int ii; + + open_db(p, 0); + memcpy(&data, p, sizeof(data)); + data.showHeader = 0; + data.cMode = data.mode = MODE_Semi; + initText(&sSelect); + for(ii=1; iidb, "SELECT name FROM pragma_database_list", + -1, &pStmt, 0); + if( rc ){ + utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); + sqlite3_finalize(pStmt); + rc = 1; + goto meta_command_exit; + } + appendText(&sSelect, "SELECT sql FROM", 0); + iSchema = 0; + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zDb = (const char*)sqlite3_column_text(pStmt, 0); + char zScNum[30]; + sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema); + appendText(&sSelect, zDiv, 0); + zDiv = " UNION ALL "; + appendText(&sSelect, "SELECT shell_add_schema(sql,", 0); + if( sqlite3_stricmp(zDb, "main")!=0 ){ + appendText(&sSelect, zDb, '\''); + }else{ + appendText(&sSelect, "NULL", 0); + } + appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0); + appendText(&sSelect, zScNum, 0); + appendText(&sSelect, " AS snum, ", 0); + appendText(&sSelect, zDb, '\''); + appendText(&sSelect, " AS sname FROM ", 0); + appendText(&sSelect, zDb, quoteChar(zDb)); + appendText(&sSelect, ".sqlite_schema", 0); + } + sqlite3_finalize(pStmt); #ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS - if( zName ){ - appendText(&sSelect, - " UNION ALL SELECT shell_module_schema(name)," - " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", - 0); - } + if( zName ){ + appendText(&sSelect, + " UNION ALL SELECT shell_module_schema(name)," + " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list", + 0); + } #endif - appendText(&sSelect, ") WHERE ", 0); - if( zName ){ - char *zQarg = sqlite3_mprintf("%Q", zName); - int bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 || - strchr(zName, '[') != 0; - if( strchr(zName, '.') ){ - appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0); - }else{ - appendText(&sSelect, "lower(tbl_name)", 0); - } - appendText(&sSelect, bGlob ? " GLOB " : " LIKE ", 0); - appendText(&sSelect, zQarg, 0); - if( !bGlob ){ - appendText(&sSelect, " ESCAPE '\\' ", 0); - } - appendText(&sSelect, " AND ", 0); - sqlite3_free(zQarg); - } - if( bNoSystemTabs ){ - appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0); - } - appendText(&sSelect, "sql IS NOT NULL" - " ORDER BY snum, rowid", 0); - if( bDebug ){ - utf8_printf(p->out, "SQL: %s;\n", sSelect.z); - }else{ - rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg); - } - freeText(&sSelect); - } - if( zErrMsg ){ - utf8_printf(stderr,"Error: %s\n", zErrMsg); - sqlite3_free(zErrMsg); - rc = 1; - }else if( rc != SQLITE_OK ){ - raw_printf(stderr,"Error: querying schema information\n"); - rc = 1; - }else{ - rc = 0; - } - }else - - if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ - unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff; - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x); - }else + appendText(&sSelect, ") WHERE ", 0); + if( zName ){ + char *zQarg = sqlite3_mprintf("%Q", zName); + int bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 || + strchr(zName, '[') != 0; + if( strchr(zName, '.') ){ + appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0); + }else{ + appendText(&sSelect, "lower(tbl_name)", 0); + } + appendText(&sSelect, bGlob ? " GLOB " : " LIKE ", 0); + appendText(&sSelect, zQarg, 0); + if( !bGlob ){ + appendText(&sSelect, " ESCAPE '\\' ", 0); + } + appendText(&sSelect, " AND ", 0); + sqlite3_free(zQarg); + } + if( bNoSystemTabs ){ + appendText(&sSelect, "name NOT LIKE 'sqlite_%%' AND ", 0); + } + appendText(&sSelect, "sql IS NOT NULL" + " ORDER BY snum, rowid", 0); + if( bDebug ){ + utf8_printf(p->out, "SQL: %s;\n", sSelect.z); + }else{ + rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg); + } + freeText(&sSelect); + } + if( zErrMsg ){ + utf8_printf(stderr,"Error: %s\n", zErrMsg); + sqlite3_free(zErrMsg); + rc = 1; + }else if( rc != SQLITE_OK ){ + raw_printf(stderr,"Error: querying schema information\n"); + rc = 1; + }else{ + rc = 0; + } + }else + + if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ + unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff; + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 1, &x); + }else #if defined(SQLITE_ENABLE_SESSION) - if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){ - struct AuxDb *pAuxDb = p->pAuxDb; - OpenSession *pSession = &pAuxDb->aSession[0]; - char **azCmd = &azArg[1]; - int iSes = 0; - int nCmd = nArg - 1; - int i; - if( nArg<=1 ) goto session_syntax_error; - open_db(p, 0); - if( nArg>=3 ){ - for(iSes=0; iSesnSession; iSes++){ - if( strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break; - } - if( iSesnSession ){ - pSession = &pAuxDb->aSession[iSes]; - azCmd++; - nCmd--; - }else{ - pSession = &pAuxDb->aSession[0]; - iSes = 0; - } - } - - /* .session attach TABLE + if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){ + struct AuxDb *pAuxDb = p->pAuxDb; + OpenSession *pSession = &pAuxDb->aSession[0]; + char **azCmd = &azArg[1]; + int iSes = 0; + int nCmd = nArg - 1; + int i; + if( nArg<=1 ) goto session_syntax_error; + open_db(p, 0); + if( nArg>=3 ){ + for(iSes=0; iSesnSession; iSes++){ + if( strcmp(pAuxDb->aSession[iSes].zName, azArg[1])==0 ) break; + } + if( iSesnSession ){ + pSession = &pAuxDb->aSession[iSes]; + azCmd++; + nCmd--; + }else{ + pSession = &pAuxDb->aSession[0]; + iSes = 0; + } + } + + /* .session attach TABLE ** Invoke the sqlite3session_attach() interface to attach a particular ** table so that it is never filtered. */ - if( strcmp(azCmd[0],"attach")==0 ){ - if( nCmd!=2 ) goto session_syntax_error; - if( pSession->p==0 ){ - session_not_open: - raw_printf(stderr, "ERROR: No sessions are open\n"); - }else{ - rc = sqlite3session_attach(pSession->p, azCmd[1]); - if( rc ){ - raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc); - rc = 0; - } - } - }else - - /* .session changeset FILE + if( strcmp(azCmd[0],"attach")==0 ){ + if( nCmd!=2 ) goto session_syntax_error; + if( pSession->p==0 ){ + session_not_open: + raw_printf(stderr, "ERROR: No sessions are open\n"); + }else{ + rc = sqlite3session_attach(pSession->p, azCmd[1]); + if( rc ){ + raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc); + rc = 0; + } + } + }else + + /* .session changeset FILE ** .session patchset FILE ** Write a changeset or patchset into a file. The file is overwritten. */ - if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){ - FILE *out = 0; - failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]); - if( nCmd!=2 ) goto session_syntax_error; - if( pSession->p==0 ) goto session_not_open; - out = fopen(azCmd[1], "wb"); - if( out==0 ){ - utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", - azCmd[1]); - }else{ - int szChng; - void *pChng; - if( azCmd[0][0]=='c' ){ - rc = sqlite3session_changeset(pSession->p, &szChng, &pChng); - }else{ - rc = sqlite3session_patchset(pSession->p, &szChng, &pChng); - } - if( rc ){ - printf("Error: error code %d\n", rc); - rc = 0; - } - if( pChng - && fwrite(pChng, szChng, 1, out)!=1 ){ - raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n", - szChng); - } - sqlite3_free(pChng); - fclose(out); - } - }else - - /* .session close + if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){ + FILE *out = 0; + failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]); + if( nCmd!=2 ) goto session_syntax_error; + if( pSession->p==0 ) goto session_not_open; + out = fopen(azCmd[1], "wb"); + if( out==0 ){ + utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", + azCmd[1]); + }else{ + int szChng; + void *pChng; + if( azCmd[0][0]=='c' ){ + rc = sqlite3session_changeset(pSession->p, &szChng, &pChng); + }else{ + rc = sqlite3session_patchset(pSession->p, &szChng, &pChng); + } + if( rc ){ + printf("Error: error code %d\n", rc); + rc = 0; + } + if( pChng + && fwrite(pChng, szChng, 1, out)!=1 ){ + raw_printf(stderr, "ERROR: Failed to write entire %d-byte output\n", + szChng); + } + sqlite3_free(pChng); + fclose(out); + } + }else + + /* .session close ** Close the identified session */ - if( strcmp(azCmd[0], "close")==0 ){ - if( nCmd!=1 ) goto session_syntax_error; - if( pAuxDb->nSession ){ - session_close(pSession); - pAuxDb->aSession[iSes] = pAuxDb->aSession[--pAuxDb->nSession]; - } - }else - - /* .session enable ?BOOLEAN? + if( strcmp(azCmd[0], "close")==0 ){ + if( nCmd!=1 ) goto session_syntax_error; + if( pAuxDb->nSession ){ + session_close(pSession); + pAuxDb->aSession[iSes] = pAuxDb->aSession[--pAuxDb->nSession]; + } + }else + + /* .session enable ?BOOLEAN? ** Query or set the enable flag */ - if( strcmp(azCmd[0], "enable")==0 ){ - int ii; - if( nCmd>2 ) goto session_syntax_error; - ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); - if( pAuxDb->nSession ){ - ii = sqlite3session_enable(pSession->p, ii); - utf8_printf(p->out, "session %s enable flag = %d\n", - pSession->zName, ii); - } - }else - - /* .session filter GLOB .... + if( strcmp(azCmd[0], "enable")==0 ){ + int ii; + if( nCmd>2 ) goto session_syntax_error; + ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); + if( pAuxDb->nSession ){ + ii = sqlite3session_enable(pSession->p, ii); + utf8_printf(p->out, "session %s enable flag = %d\n", + pSession->zName, ii); + } + }else + + /* .session filter GLOB .... ** Set a list of GLOB patterns of table names to be excluded. */ - if( strcmp(azCmd[0], "filter")==0 ){ - int ii, nByte; - if( nCmd<2 ) goto session_syntax_error; - if( pAuxDb->nSession ){ - for(ii=0; iinFilter; ii++){ - sqlite3_free(pSession->azFilter[ii]); - } - sqlite3_free(pSession->azFilter); - nByte = sizeof(pSession->azFilter[0])*(nCmd-1); - pSession->azFilter = sqlite3_malloc( nByte ); - if( pSession->azFilter==0 ){ - raw_printf(stderr, "Error: out or memory\n"); - exit(1); - } - for(ii=1; iiazFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]); - } - pSession->nFilter = ii-1; - } - }else - - /* .session indirect ?BOOLEAN? + if( strcmp(azCmd[0], "filter")==0 ){ + int ii, nByte; + if( nCmd<2 ) goto session_syntax_error; + if( pAuxDb->nSession ){ + for(ii=0; iinFilter; ii++){ + sqlite3_free(pSession->azFilter[ii]); + } + sqlite3_free(pSession->azFilter); + nByte = sizeof(pSession->azFilter[0])*(nCmd-1); + pSession->azFilter = sqlite3_malloc( nByte ); + if( pSession->azFilter==0 ){ + raw_printf(stderr, "Error: out or memory\n"); + exit(1); + } + for(ii=1; iiazFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]); + } + pSession->nFilter = ii-1; + } + }else + + /* .session indirect ?BOOLEAN? ** Query or set the indirect flag */ - if( strcmp(azCmd[0], "indirect")==0 ){ - int ii; - if( nCmd>2 ) goto session_syntax_error; - ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); - if( pAuxDb->nSession ){ - ii = sqlite3session_indirect(pSession->p, ii); - utf8_printf(p->out, "session %s indirect flag = %d\n", - pSession->zName, ii); - } - }else - - /* .session isempty + if( strcmp(azCmd[0], "indirect")==0 ){ + int ii; + if( nCmd>2 ) goto session_syntax_error; + ii = nCmd==1 ? -1 : booleanValue(azCmd[1]); + if( pAuxDb->nSession ){ + ii = sqlite3session_indirect(pSession->p, ii); + utf8_printf(p->out, "session %s indirect flag = %d\n", + pSession->zName, ii); + } + }else + + /* .session isempty ** Determine if the session is empty */ - if( strcmp(azCmd[0], "isempty")==0 ){ - int ii; - if( nCmd!=1 ) goto session_syntax_error; - if( pAuxDb->nSession ){ - ii = sqlite3session_isempty(pSession->p); - utf8_printf(p->out, "session %s isempty flag = %d\n", - pSession->zName, ii); - } - }else - - /* .session list + if( strcmp(azCmd[0], "isempty")==0 ){ + int ii; + if( nCmd!=1 ) goto session_syntax_error; + if( pAuxDb->nSession ){ + ii = sqlite3session_isempty(pSession->p); + utf8_printf(p->out, "session %s isempty flag = %d\n", + pSession->zName, ii); + } + }else + + /* .session list ** List all currently open sessions */ - if( strcmp(azCmd[0],"list")==0 ){ - for(i=0; inSession; i++){ - utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName); - } - }else + if( strcmp(azCmd[0],"list")==0 ){ + for(i=0; inSession; i++){ + utf8_printf(p->out, "%d %s\n", i, pAuxDb->aSession[i].zName); + } + }else - /* .session open DB NAME + /* .session open DB NAME ** Open a new session called NAME on the attached database DB. ** DB is normally "main". */ - if( strcmp(azCmd[0],"open")==0 ){ - char *zName; - if( nCmd!=3 ) goto session_syntax_error; - zName = azCmd[2]; - if( zName[0]==0 ) goto session_syntax_error; - for(i=0; inSession; i++){ - if( strcmp(pAuxDb->aSession[i].zName,zName)==0 ){ - utf8_printf(stderr, "Session \"%s\" already exists\n", zName); - goto meta_command_exit; - } - } - if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ - raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession)); - goto meta_command_exit; - } - pSession = &pAuxDb->aSession[pAuxDb->nSession]; - rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); - if( rc ){ - raw_printf(stderr, "Cannot open session: error code=%d\n", rc); - rc = 0; - goto meta_command_exit; - } - pSession->nFilter = 0; - sqlite3session_table_filter(pSession->p, session_filter, pSession); - pAuxDb->nSession++; - pSession->zName = sqlite3_mprintf("%s", zName); - }else - /* If no command name matches, show a syntax error */ - session_syntax_error: - showHelp(p->out, "session"); - }else + if( strcmp(azCmd[0],"open")==0 ){ + char *zName; + if( nCmd!=3 ) goto session_syntax_error; + zName = azCmd[2]; + if( zName[0]==0 ) goto session_syntax_error; + for(i=0; inSession; i++){ + if( strcmp(pAuxDb->aSession[i].zName,zName)==0 ){ + utf8_printf(stderr, "Session \"%s\" already exists\n", zName); + goto meta_command_exit; + } + } + if( pAuxDb->nSession>=ArraySize(pAuxDb->aSession) ){ + raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(pAuxDb->aSession)); + goto meta_command_exit; + } + pSession = &pAuxDb->aSession[pAuxDb->nSession]; + rc = sqlite3session_create(p->db, azCmd[1], &pSession->p); + if( rc ){ + raw_printf(stderr, "Cannot open session: error code=%d\n", rc); + rc = 0; + goto meta_command_exit; + } + pSession->nFilter = 0; + sqlite3session_table_filter(pSession->p, session_filter, pSession); + pAuxDb->nSession++; + pSession->zName = sqlite3_mprintf("%s", zName); + }else + /* If no command name matches, show a syntax error */ + session_syntax_error: + showHelp(p->out, "session"); + }else #endif #ifdef SQLITE_DEBUG - /* Undocumented commands for internal testing. Subject to change + /* Undocumented commands for internal testing. Subject to change ** without notice. */ - if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ - if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ - int i, v; - for(i=1; iout, "%s: %d 0x%x\n", azArg[i], v, v); - } - } - if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ - int i; sqlite3_int64 v; - for(i=1; iout, "%s", zBuf); - } - } - }else + if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ + if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ + int i, v; + for(i=1; iout, "%s: %d 0x%x\n", azArg[i], v, v); + } + } + if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ + int i; sqlite3_int64 v; + for(i=1; iout, "%s", zBuf); + } + } + }else #endif - if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){ - int bIsInit = 0; /* True to initialize the SELFTEST table */ - int bVerbose = 0; /* Verbose output */ - int bSelftestExists; /* True if SELFTEST already exists */ - int i, k; /* Loop counters */ - int nTest = 0; /* Number of tests runs */ - int nErr = 0; /* Number of errors seen */ - ShellText str; /* Answer for a query */ - sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */ - - open_db(p,0); - for(i=1; idb,"main","selftest",0,0,0,0,0,0) - != SQLITE_OK ){ - bSelftestExists = 0; - }else{ - bSelftestExists = 1; - } - if( bIsInit ){ - createSelftestTable(p); - bSelftestExists = 1; - } - initText(&str); - appendText(&str, "x", 0); - for(k=bSelftestExists; k>=0; k--){ - if( k==1 ){ - rc = sqlite3_prepare_v2(p->db, - "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno", - -1, &pStmt, 0); - }else{ - rc = sqlite3_prepare_v2(p->db, - "VALUES(0,'memo','Missing SELFTEST table - default checks only','')," - " (1,'run','PRAGMA integrity_check','ok')", - -1, &pStmt, 0); - } - if( rc ){ - raw_printf(stderr, "Error querying the selftest table\n"); - rc = 1; - sqlite3_finalize(pStmt); - goto meta_command_exit; - } - for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){ - int tno = sqlite3_column_int(pStmt, 0); - const char *zOp = (const char*)sqlite3_column_text(pStmt, 1); - const char *zSql = (const char*)sqlite3_column_text(pStmt, 2); - const char *zAns = (const char*)sqlite3_column_text(pStmt, 3); - - k = 0; - if( bVerbose>0 ){ - char *zQuote = sqlite3_mprintf("%q", zSql); - printf("%d: %s %s\n", tno, zOp, zSql); - sqlite3_free(zQuote); - } - if( strcmp(zOp,"memo")==0 ){ - utf8_printf(p->out, "%s\n", zSql); - }else - if( strcmp(zOp,"run")==0 ){ - char *zErrMsg = 0; - str.n = 0; - str.z[0] = 0; - rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg); - nTest++; - if( bVerbose ){ - utf8_printf(p->out, "Result: %s\n", str.z); - } - if( rc || zErrMsg ){ - nErr++; - rc = 1; - utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg); - sqlite3_free(zErrMsg); - }else if( strcmp(zAns,str.z)!=0 ){ - nErr++; - rc = 1; - utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns); - utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z); - } - }else - { - utf8_printf(stderr, - "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); - rc = 1; - break; - } - } /* End loop over rows of content from SELFTEST */ - sqlite3_finalize(pStmt); - } /* End loop over k */ - freeText(&str); - utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest); - }else - - if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){ - if( nArg<2 || nArg>3 ){ - raw_printf(stderr, "Usage: .separator COL ?ROW?\n"); - rc = 1; - } - if( nArg>=2 ){ - sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, - "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]); - } - if( nArg>=3 ){ - sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, - "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]); - } - }else - - if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){ - const char *zLike = 0; /* Which table to checksum. 0 means everything */ - int i; /* Loop counter */ - int bSchema = 0; /* Also hash the schema */ - int bSeparate = 0; /* Hash each table separately */ - int iSize = 224; /* Hash algorithm to use */ - int bDebug = 0; /* Only show the query that would have run */ - sqlite3_stmt *pStmt; /* For querying tables names */ - char *zSql; /* SQL to be run */ - char *zSep; /* Separator */ - ShellText sSql; /* Complete SQL for the query to run the hash */ - ShellText sQuery; /* Set of queries used to read all content */ - open_db(p, 0); - for(i=1; iout, azArg[0]); - rc = 1; - goto meta_command_exit; - } - }else if( zLike ){ - raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n"); - rc = 1; - goto meta_command_exit; - }else{ - zLike = z; - bSeparate = 1; - if( sqlite3_strlike("sqlite\\_%", zLike, '\\')==0 ) bSchema = 1; - } - } - if( bSchema ){ - zSql = "SELECT lower(name) FROM sqlite_schema" - " WHERE type='table' AND coalesce(rootpage,0)>1" - " UNION ALL SELECT 'sqlite_schema'" - " ORDER BY 1 collate nocase"; - }else{ - zSql = "SELECT lower(name) FROM sqlite_schema" - " WHERE type='table' AND coalesce(rootpage,0)>1" - " AND name NOT LIKE 'sqlite_%'" - " ORDER BY 1 collate nocase"; - } - sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); - initText(&sQuery); - initText(&sSql); - appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0); - zSep = "VALUES("; - while( SQLITE_ROW==sqlite3_step(pStmt) ){ - const char *zTab = (const char*)sqlite3_column_text(pStmt,0); - if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue; - if( strncmp(zTab, "sqlite_",7)!=0 ){ - appendText(&sQuery,"SELECT * FROM ", 0); - appendText(&sQuery,zTab,'"'); - appendText(&sQuery," NOT INDEXED;", 0); - }else if( strcmp(zTab, "sqlite_schema")==0 ){ - appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema" - " ORDER BY name;", 0); - }else if( strcmp(zTab, "sqlite_sequence")==0 ){ - appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence" - " ORDER BY name;", 0); - }else if( strcmp(zTab, "sqlite_stat1")==0 ){ - appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1" - " ORDER BY tbl,idx;", 0); - }else if( strcmp(zTab, "sqlite_stat4")==0 ){ - appendText(&sQuery, "SELECT * FROM ", 0); - appendText(&sQuery, zTab, 0); - appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0); - } - appendText(&sSql, zSep, 0); - appendText(&sSql, sQuery.z, '\''); - sQuery.n = 0; - appendText(&sSql, ",", 0); - appendText(&sSql, zTab, '\''); - zSep = "),("; - } - sqlite3_finalize(pStmt); - if( bSeparate ){ - zSql = sqlite3_mprintf( - "%s))" - " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label" - " FROM [sha3sum$query]", - sSql.z, iSize); - }else{ - zSql = sqlite3_mprintf( - "%s))" - " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash" - " FROM [sha3sum$query]", - sSql.z, iSize); - } - freeText(&sQuery); - freeText(&sSql); - if( bDebug ){ - utf8_printf(p->out, "%s\n", zSql); - }else{ - shell_exec(p, zSql, 0); - } - sqlite3_free(zSql); - }else + if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){ + int bIsInit = 0; /* True to initialize the SELFTEST table */ + int bVerbose = 0; /* Verbose output */ + int bSelftestExists; /* True if SELFTEST already exists */ + int i, k; /* Loop counters */ + int nTest = 0; /* Number of tests runs */ + int nErr = 0; /* Number of errors seen */ + ShellText str; /* Answer for a query */ + sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */ + + open_db(p,0); + for(i=1; idb,"main","selftest",0,0,0,0,0,0) + != SQLITE_OK ){ + bSelftestExists = 0; + }else{ + bSelftestExists = 1; + } + if( bIsInit ){ + createSelftestTable(p); + bSelftestExists = 1; + } + initText(&str); + appendText(&str, "x", 0); + for(k=bSelftestExists; k>=0; k--){ + if( k==1 ){ + rc = sqlite3_prepare_v2(p->db, + "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno", + -1, &pStmt, 0); + }else{ + rc = sqlite3_prepare_v2(p->db, + "VALUES(0,'memo','Missing SELFTEST table - default checks only','')," + " (1,'run','PRAGMA integrity_check','ok')", + -1, &pStmt, 0); + } + if( rc ){ + raw_printf(stderr, "Error querying the selftest table\n"); + rc = 1; + sqlite3_finalize(pStmt); + goto meta_command_exit; + } + for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){ + int tno = sqlite3_column_int(pStmt, 0); + const char *zOp = (const char*)sqlite3_column_text(pStmt, 1); + const char *zSql = (const char*)sqlite3_column_text(pStmt, 2); + const char *zAns = (const char*)sqlite3_column_text(pStmt, 3); + + k = 0; + if( bVerbose>0 ){ + char *zQuote = sqlite3_mprintf("%q", zSql); + printf("%d: %s %s\n", tno, zOp, zSql); + sqlite3_free(zQuote); + } + if( strcmp(zOp,"memo")==0 ){ + utf8_printf(p->out, "%s\n", zSql); + }else + if( strcmp(zOp,"run")==0 ){ + char *zErrMsg = 0; + str.n = 0; + str.z[0] = 0; + rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg); + nTest++; + if( bVerbose ){ + utf8_printf(p->out, "Result: %s\n", str.z); + } + if( rc || zErrMsg ){ + nErr++; + rc = 1; + utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg); + sqlite3_free(zErrMsg); + }else if( strcmp(zAns,str.z)!=0 ){ + nErr++; + rc = 1; + utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns); + utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z); + } + }else + { + utf8_printf(stderr, + "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); + rc = 1; + break; + } + } /* End loop over rows of content from SELFTEST */ + sqlite3_finalize(pStmt); + } /* End loop over k */ + freeText(&str); + utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest); + }else + + if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){ + if( nArg<2 || nArg>3 ){ + raw_printf(stderr, "Usage: .separator COL ?ROW?\n"); + rc = 1; + } + if( nArg>=2 ){ + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, + "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]); + } + if( nArg>=3 ){ + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, + "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]); + } + }else + + if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){ + const char *zLike = 0; /* Which table to checksum. 0 means everything */ + int i; /* Loop counter */ + int bSchema = 0; /* Also hash the schema */ + int bSeparate = 0; /* Hash each table separately */ + int iSize = 224; /* Hash algorithm to use */ + int bDebug = 0; /* Only show the query that would have run */ + sqlite3_stmt *pStmt; /* For querying tables names */ + char *zSql; /* SQL to be run */ + char *zSep; /* Separator */ + ShellText sSql; /* Complete SQL for the query to run the hash */ + ShellText sQuery; /* Set of queries used to read all content */ + open_db(p, 0); + for(i=1; iout, azArg[0]); + rc = 1; + goto meta_command_exit; + } + }else if( zLike ){ + raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n"); + rc = 1; + goto meta_command_exit; + }else{ + zLike = z; + bSeparate = 1; + if( sqlite3_strlike("sqlite\\_%", zLike, '\\')==0 ) bSchema = 1; + } + } + if( bSchema ){ + zSql = "SELECT lower(name) FROM sqlite_schema" + " WHERE type='table' AND coalesce(rootpage,0)>1" + " UNION ALL SELECT 'sqlite_schema'" + " ORDER BY 1 collate nocase"; + }else{ + zSql = "SELECT lower(name) FROM sqlite_schema" + " WHERE type='table' AND coalesce(rootpage,0)>1" + " AND name NOT LIKE 'sqlite_%'" + " ORDER BY 1 collate nocase"; + } + sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + initText(&sQuery); + initText(&sSql); + appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0); + zSep = "VALUES("; + while( SQLITE_ROW==sqlite3_step(pStmt) ){ + const char *zTab = (const char*)sqlite3_column_text(pStmt,0); + if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue; + if( strncmp(zTab, "sqlite_",7)!=0 ){ + appendText(&sQuery,"SELECT * FROM ", 0); + appendText(&sQuery,zTab,'"'); + appendText(&sQuery," NOT INDEXED;", 0); + }else if( strcmp(zTab, "sqlite_schema")==0 ){ + appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema" + " ORDER BY name;", 0); + }else if( strcmp(zTab, "sqlite_sequence")==0 ){ + appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence" + " ORDER BY name;", 0); + }else if( strcmp(zTab, "sqlite_stat1")==0 ){ + appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1" + " ORDER BY tbl,idx;", 0); + }else if( strcmp(zTab, "sqlite_stat4")==0 ){ + appendText(&sQuery, "SELECT * FROM ", 0); + appendText(&sQuery, zTab, 0); + appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0); + } + appendText(&sSql, zSep, 0); + appendText(&sSql, sQuery.z, '\''); + sQuery.n = 0; + appendText(&sSql, ",", 0); + appendText(&sSql, zTab, '\''); + zSep = "),("; + } + sqlite3_finalize(pStmt); + if( bSeparate ){ + zSql = sqlite3_mprintf( + "%s))" + " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label" + " FROM [sha3sum$query]", + sSql.z, iSize); + }else{ + zSql = sqlite3_mprintf( + "%s))" + " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash" + " FROM [sha3sum$query]", + sSql.z, iSize); + } + freeText(&sQuery); + freeText(&sSql); + if( bDebug ){ + utf8_printf(p->out, "%s\n", zSql); + }else{ + shell_exec(p, zSql, 0); + } + sqlite3_free(zSql); + }else #ifndef SQLITE_NOHAVE_SYSTEM - if( c=='s' - && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0) - ){ - char *zCmd; - int i, x; - failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]); - if( nArg<2 ){ - raw_printf(stderr, "Usage: .system COMMAND\n"); - rc = 1; - goto meta_command_exit; - } - zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]); - for(i=2; iout, "%12.12s: %s\n","echo", - azBool[ShellHasFlag(p, SHFLG_Echo)]); - utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]); - utf8_printf(p->out, "%12.12s: %s\n","explain", - p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); - utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]); - utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]); - utf8_printf(p->out, "%12.12s: ", "nullvalue"); - output_c_string(p->out, p->nullValue); - raw_printf(p->out, "\n"); - utf8_printf(p->out,"%12.12s: %s\n","output", - strlen30(p->outfile) ? p->outfile : "stdout"); - utf8_printf(p->out,"%12.12s: ", "colseparator"); - output_c_string(p->out, p->colSeparator); - raw_printf(p->out, "\n"); - utf8_printf(p->out,"%12.12s: ", "rowseparator"); - output_c_string(p->out, p->rowSeparator); - raw_printf(p->out, "\n"); - switch( p->statsOn ){ - case 0: zOut = "off"; break; - default: zOut = "on"; break; - case 2: zOut = "stmt"; break; - case 3: zOut = "vmstep"; break; - } - utf8_printf(p->out, "%12.12s: %s\n","stats", zOut); - utf8_printf(p->out, "%12.12s: ", "width"); - for (i=0;inWidth;i++) { - raw_printf(p->out, "%d ", p->colWidth[i]); - } - raw_printf(p->out, "\n"); - utf8_printf(p->out, "%12.12s: %s\n", "filename", - p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : ""); - }else - - if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){ - if( nArg==2 ){ - if( strcmp(azArg[1],"stmt")==0 ){ - p->statsOn = 2; - }else if( strcmp(azArg[1],"vmstep")==0 ){ - p->statsOn = 3; - }else{ - p->statsOn = (u8)booleanValue(azArg[1]); - } - }else if( nArg==1 ){ - display_stats(p->db, p, 0); - }else{ - raw_printf(stderr, "Usage: .stats ?on|off|stmt|vmstep?\n"); - rc = 1; - } - }else - - if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0) - || (c=='i' && (strncmp(azArg[0], "indices", n)==0 - || strncmp(azArg[0], "indexes", n)==0) ) - ){ - sqlite3_stmt *pStmt; - char **azResult; - int nRow, nAlloc; - int ii; - ShellText s; - initText(&s); - open_db(p, 0); - rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); - if( rc ){ - sqlite3_finalize(pStmt); - return shellDatabaseError(p->db); - } - - if( nArg>2 && c=='i' ){ - /* It is an historical accident that the .indexes command shows an error + if( c=='s' && strncmp(azArg[0], "show", n)==0 ){ + static const char *azBool[] = { "off", "on", "trigger", "full"}; + const char *zOut; + int i; + if( nArg!=1 ){ + raw_printf(stderr, "Usage: .show\n"); + rc = 1; + goto meta_command_exit; + } + utf8_printf(p->out, "%12.12s: %s\n","echo", + azBool[ShellHasFlag(p, SHFLG_Echo)]); + utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]); + utf8_printf(p->out, "%12.12s: %s\n","explain", + p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); + utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]); + utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]); + utf8_printf(p->out, "%12.12s: ", "nullvalue"); + output_c_string(p->out, p->nullValue); + raw_printf(p->out, "\n"); + utf8_printf(p->out,"%12.12s: %s\n","output", + strlen30(p->outfile) ? p->outfile : "stdout"); + utf8_printf(p->out,"%12.12s: ", "colseparator"); + output_c_string(p->out, p->colSeparator); + raw_printf(p->out, "\n"); + utf8_printf(p->out,"%12.12s: ", "rowseparator"); + output_c_string(p->out, p->rowSeparator); + raw_printf(p->out, "\n"); + switch( p->statsOn ){ + case 0: zOut = "off"; break; + default: zOut = "on"; break; + case 2: zOut = "stmt"; break; + case 3: zOut = "vmstep"; break; + } + utf8_printf(p->out, "%12.12s: %s\n","stats", zOut); + utf8_printf(p->out, "%12.12s: ", "width"); + for (i=0;inWidth;i++) { + raw_printf(p->out, "%d ", p->colWidth[i]); + } + raw_printf(p->out, "\n"); + utf8_printf(p->out, "%12.12s: %s\n", "filename", + p->pAuxDb->zDbFilename ? p->pAuxDb->zDbFilename : ""); + }else + + if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){ + if( nArg==2 ){ + if( strcmp(azArg[1],"stmt")==0 ){ + p->statsOn = 2; + }else if( strcmp(azArg[1],"vmstep")==0 ){ + p->statsOn = 3; + }else{ + p->statsOn = (u8)booleanValue(azArg[1]); + } + }else if( nArg==1 ){ + display_stats(p->db, p, 0); + }else{ + raw_printf(stderr, "Usage: .stats ?on|off|stmt|vmstep?\n"); + rc = 1; + } + }else + + if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0) + || (c=='i' && (strncmp(azArg[0], "indices", n)==0 + || strncmp(azArg[0], "indexes", n)==0) ) + ){ + sqlite3_stmt *pStmt; + char **azResult; + int nRow, nAlloc; + int ii; + ShellText s; + initText(&s); + open_db(p, 0); + rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); + if( rc ){ + sqlite3_finalize(pStmt); + return shellDatabaseError(p->db); + } + + if( nArg>2 && c=='i' ){ + /* It is an historical accident that the .indexes command shows an error ** when called with the wrong number of arguments whereas the .tables ** command does not. */ - raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); - rc = 1; - sqlite3_finalize(pStmt); - goto meta_command_exit; - } - for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ - const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); - if( zDbName==0 ) continue; - if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0); - if( sqlite3_stricmp(zDbName, "main")==0 ){ - appendText(&s, "SELECT name FROM ", 0); - }else{ - appendText(&s, "SELECT ", 0); - appendText(&s, zDbName, '\''); - appendText(&s, "||'.'||name FROM ", 0); - } - appendText(&s, zDbName, '"'); - appendText(&s, ".sqlite_schema ", 0); - if( c=='t' ){ - appendText(&s," WHERE type IN ('table','view')" - " AND name NOT LIKE 'sqlite_%'" - " AND name LIKE ?1", 0); - }else{ - appendText(&s," WHERE type='index'" - " AND tbl_name LIKE ?1", 0); - } - } - rc = sqlite3_finalize(pStmt); - if( rc==SQLITE_OK ){ - appendText(&s, " ORDER BY 1", 0); - rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0); - } - freeText(&s); - if( rc ) return shellDatabaseError(p->db); - - /* Run the SQL statement prepared by the above block. Store the results + raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); + rc = 1; + sqlite3_finalize(pStmt); + goto meta_command_exit; + } + for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ + const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); + if( zDbName==0 ) continue; + if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0); + if( sqlite3_stricmp(zDbName, "main")==0 ){ + appendText(&s, "SELECT name FROM ", 0); + }else{ + appendText(&s, "SELECT ", 0); + appendText(&s, zDbName, '\''); + appendText(&s, "||'.'||name FROM ", 0); + } + appendText(&s, zDbName, '"'); + appendText(&s, ".sqlite_schema ", 0); + if( c=='t' ){ + appendText(&s," WHERE type IN ('table','view')" + " AND name NOT LIKE 'sqlite_%'" + " AND name LIKE ?1", 0); + }else{ + appendText(&s," WHERE type='index'" + " AND tbl_name LIKE ?1", 0); + } + } + rc = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ){ + appendText(&s, " ORDER BY 1", 0); + rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0); + } + freeText(&s); + if( rc ) return shellDatabaseError(p->db); + + /* Run the SQL statement prepared by the above block. Store the results ** as an array of nul-terminated strings in azResult[]. */ - nRow = nAlloc = 0; - azResult = 0; - if( nArg>1 ){ - sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT); - }else{ - sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC); - } - while( sqlite3_step(pStmt)==SQLITE_ROW ){ - if( nRow>=nAlloc ){ - char **azNew; - int n2 = nAlloc*2 + 10; - azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2); - if( azNew==0 ) shell_out_of_memory(); - nAlloc = n2; - azResult = azNew; - } - azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); - if( 0==azResult[nRow] ) shell_out_of_memory(); - nRow++; - } - if( sqlite3_finalize(pStmt)!=SQLITE_OK ){ - rc = shellDatabaseError(p->db); - } - - /* Pretty-print the contents of array azResult[] to the output */ - if( rc==0 && nRow>0 ){ - int len, maxlen = 0; - int i, j; - int nPrintCol, nPrintRow; - for(i=0; imaxlen ) maxlen = len; - } - nPrintCol = 80/(maxlen+2); - if( nPrintCol<1 ) nPrintCol = 1; - nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; - for(i=0; iout, "%s%-*s", zSp, maxlen, - azResult[j] ? azResult[j]:""); - } - raw_printf(p->out, "\n"); - } - } - - for(ii=0; iiout = output_file_open("testcase-out.txt", 0); - if( p->out==0 ){ - raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n"); - } - if( nArg>=2 ){ - sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]); - }else{ - sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?"); - } - }else + nRow = nAlloc = 0; + azResult = 0; + if( nArg>1 ){ + sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT); + }else{ + sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC); + } + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + if( nRow>=nAlloc ){ + char **azNew; + int n2 = nAlloc*2 + 10; + azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2); + if( azNew==0 ) shell_out_of_memory(); + nAlloc = n2; + azResult = azNew; + } + azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); + if( 0==azResult[nRow] ) shell_out_of_memory(); + nRow++; + } + if( sqlite3_finalize(pStmt)!=SQLITE_OK ){ + rc = shellDatabaseError(p->db); + } + + /* Pretty-print the contents of array azResult[] to the output */ + if( rc==0 && nRow>0 ){ + int len, maxlen = 0; + int i, j; + int nPrintCol, nPrintRow; + for(i=0; imaxlen ) maxlen = len; + } + nPrintCol = 80/(maxlen+2); + if( nPrintCol<1 ) nPrintCol = 1; + nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; + for(i=0; iout, "%s%-*s", zSp, maxlen, + azResult[j] ? azResult[j]:""); + } + raw_printf(p->out, "\n"); + } + } + + for(ii=0; iiout = output_file_open("testcase-out.txt", 0); + if( p->out==0 ){ + raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n"); + } + if( nArg>=2 ){ + sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]); + }else{ + sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?"); + } + }else #ifndef SQLITE_UNTESTABLE - if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){ - static const struct { - const char *zCtrlName; /* Name of a test-control option */ - int ctrlCode; /* Integer code for that option */ - int unSafe; /* Not valid for --safe mode */ - const char *zUsage; /* Usage notes */ - } aCtrl[] = { - { "always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" }, - { "assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" }, - /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/ - /*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/ - { "byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" }, - { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" }, - /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/ - { "imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"}, - { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" }, - { "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" }, - { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" }, - { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" }, + if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){ + static const struct { + const char *zCtrlName; /* Name of a test-control option */ + int ctrlCode; /* Integer code for that option */ + int unSafe; /* Not valid for --safe mode */ + const char *zUsage; /* Usage notes */ + } aCtrl[] = { + { "always", SQLITE_TESTCTRL_ALWAYS, 1, "BOOLEAN" }, + { "assert", SQLITE_TESTCTRL_ASSERT, 1, "BOOLEAN" }, + /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,1, "" },*/ + /*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, 1, "" },*/ + { "byteorder", SQLITE_TESTCTRL_BYTEORDER, 0, "" }, + { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,0,"BOOLEAN" }, + /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, 1,"" },*/ + { "imposter", SQLITE_TESTCTRL_IMPOSTER,1,"SCHEMA ON/OFF ROOTPAGE"}, + { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS,0,"" }, + { "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,0,"BOOLEAN" }, + { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT,1, "BOOLEAN" }, + { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS,0,"DISABLE-MASK" }, #ifdef YYCOVERAGE - { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" }, + { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE,0,"" }, #endif - { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET " }, - { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" }, - { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" }, - { "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" }, - { "seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" }, - { "sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" }, - { "tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" }, - }; - int testctrl = -1; - int iCtrl = -1; - int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */ - int isOk = 0; - int i, n2; - const char *zCmd = 0; - - open_db(p, 0); - zCmd = nArg>=2 ? azArg[1] : "help"; - - /* The argument can optionally begin with "-" or "--" */ - if( zCmd[0]=='-' && zCmd[1] ){ - zCmd++; - if( zCmd[0]=='-' && zCmd[1] ) zCmd++; - } - - /* --help lists all test-controls */ - if( strcmp(zCmd,"help")==0 ){ - utf8_printf(p->out, "Available test-controls:\n"); - for(i=0; iout, " .testctrl %s %s\n", - aCtrl[i].zCtrlName, aCtrl[i].zUsage); - } - rc = 1; - goto meta_command_exit; - } - - /* convert testctrl text option to value. allow any unique prefix + { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE,0, "OFFSET " }, + { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE,0, "" }, + { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, 0, "" }, + { "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, 0, "SEED ?db?" }, + { "seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" }, + { "sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" }, + { "tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" }, + }; + int testctrl = -1; + int iCtrl = -1; + int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */ + int isOk = 0; + int i, n2; + const char *zCmd = 0; + + open_db(p, 0); + zCmd = nArg>=2 ? azArg[1] : "help"; + + /* The argument can optionally begin with "-" or "--" */ + if( zCmd[0]=='-' && zCmd[1] ){ + zCmd++; + if( zCmd[0]=='-' && zCmd[1] ) zCmd++; + } + + /* --help lists all test-controls */ + if( strcmp(zCmd,"help")==0 ){ + utf8_printf(p->out, "Available test-controls:\n"); + for(i=0; iout, " .testctrl %s %s\n", + aCtrl[i].zCtrlName, aCtrl[i].zUsage); + } + rc = 1; + goto meta_command_exit; + } + + /* convert testctrl text option to value. allow any unique prefix ** of the option name, or a numerical value. */ - n2 = strlen30(zCmd); - for(i=0; ibSafeMode ){ - utf8_printf(stderr, - "line %d: \".testctrl %s\" may not be used in safe mode\n", - p->lineno, aCtrl[iCtrl].zCtrlName); - exit(1); - }else{ - switch(testctrl){ - - /* sqlite3_test_control(int, db, int) */ - case SQLITE_TESTCTRL_OPTIMIZATIONS: - if( nArg==3 ){ - unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0); - rc2 = sqlite3_test_control(testctrl, p->db, opt); - isOk = 3; - } - break; - - /* sqlite3_test_control(int) */ - case SQLITE_TESTCTRL_PRNG_SAVE: - case SQLITE_TESTCTRL_PRNG_RESTORE: - case SQLITE_TESTCTRL_BYTEORDER: - if( nArg==2 ){ - rc2 = sqlite3_test_control(testctrl); - isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3; - } - break; - - /* sqlite3_test_control(int, uint) */ - case SQLITE_TESTCTRL_PENDING_BYTE: - if( nArg==3 ){ - unsigned int opt = (unsigned int)integerValue(azArg[2]); - rc2 = sqlite3_test_control(testctrl, opt); - isOk = 3; - } - break; - - /* sqlite3_test_control(int, int, sqlite3*) */ - case SQLITE_TESTCTRL_PRNG_SEED: - if( nArg==3 || nArg==4 ){ - int ii = (int)integerValue(azArg[2]); - sqlite3 *db; - if( ii==0 && strcmp(azArg[2],"random")==0 ){ - sqlite3_randomness(sizeof(ii),&ii); - printf("-- random seed: %d\n", ii); - } - if( nArg==3 ){ - db = 0; - }else{ - db = p->db; - /* Make sure the schema has been loaded */ - sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0); - } - rc2 = sqlite3_test_control(testctrl, ii, db); - isOk = 3; - } - break; - - /* sqlite3_test_control(int, int) */ - case SQLITE_TESTCTRL_ASSERT: - case SQLITE_TESTCTRL_ALWAYS: - if( nArg==3 ){ - int opt = booleanValue(azArg[2]); - rc2 = sqlite3_test_control(testctrl, opt); - isOk = 1; - } - break; - - /* sqlite3_test_control(int, int) */ - case SQLITE_TESTCTRL_LOCALTIME_FAULT: - case SQLITE_TESTCTRL_NEVER_CORRUPT: - if( nArg==3 ){ - int opt = booleanValue(azArg[2]); - rc2 = sqlite3_test_control(testctrl, opt); - isOk = 3; - } - break; - - /* sqlite3_test_control(sqlite3*) */ - case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: - rc2 = sqlite3_test_control(testctrl, p->db); - isOk = 3; - break; - - case SQLITE_TESTCTRL_IMPOSTER: - if( nArg==5 ){ - rc2 = sqlite3_test_control(testctrl, p->db, - azArg[2], - integerValue(azArg[3]), - integerValue(azArg[4])); - isOk = 3; - } - break; - - case SQLITE_TESTCTRL_SEEK_COUNT: { - u64 x = 0; - rc2 = sqlite3_test_control(testctrl, p->db, &x); - utf8_printf(p->out, "%llu\n", x); - isOk = 3; - break; - } + n2 = strlen30(zCmd); + for(i=0; ibSafeMode ){ + utf8_printf(stderr, + "line %d: \".testctrl %s\" may not be used in safe mode\n", + p->lineno, aCtrl[iCtrl].zCtrlName); + exit(1); + }else{ + switch(testctrl){ + + /* sqlite3_test_control(int, db, int) */ + case SQLITE_TESTCTRL_OPTIMIZATIONS: + if( nArg==3 ){ + unsigned int opt = (unsigned int)strtol(azArg[2], 0, 0); + rc2 = sqlite3_test_control(testctrl, p->db, opt); + isOk = 3; + } + break; + + /* sqlite3_test_control(int) */ + case SQLITE_TESTCTRL_PRNG_SAVE: + case SQLITE_TESTCTRL_PRNG_RESTORE: + case SQLITE_TESTCTRL_BYTEORDER: + if( nArg==2 ){ + rc2 = sqlite3_test_control(testctrl); + isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3; + } + break; + + /* sqlite3_test_control(int, uint) */ + case SQLITE_TESTCTRL_PENDING_BYTE: + if( nArg==3 ){ + unsigned int opt = (unsigned int)integerValue(azArg[2]); + rc2 = sqlite3_test_control(testctrl, opt); + isOk = 3; + } + break; + + /* sqlite3_test_control(int, int, sqlite3*) */ + case SQLITE_TESTCTRL_PRNG_SEED: + if( nArg==3 || nArg==4 ){ + int ii = (int)integerValue(azArg[2]); + sqlite3 *db; + if( ii==0 && strcmp(azArg[2],"random")==0 ){ + sqlite3_randomness(sizeof(ii),&ii); + printf("-- random seed: %d\n", ii); + } + if( nArg==3 ){ + db = 0; + }else{ + db = p->db; + /* Make sure the schema has been loaded */ + sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0); + } + rc2 = sqlite3_test_control(testctrl, ii, db); + isOk = 3; + } + break; + + /* sqlite3_test_control(int, int) */ + case SQLITE_TESTCTRL_ASSERT: + case SQLITE_TESTCTRL_ALWAYS: + if( nArg==3 ){ + int opt = booleanValue(azArg[2]); + rc2 = sqlite3_test_control(testctrl, opt); + isOk = 1; + } + break; + + /* sqlite3_test_control(int, int) */ + case SQLITE_TESTCTRL_LOCALTIME_FAULT: + case SQLITE_TESTCTRL_NEVER_CORRUPT: + if( nArg==3 ){ + int opt = booleanValue(azArg[2]); + rc2 = sqlite3_test_control(testctrl, opt); + isOk = 3; + } + break; + + /* sqlite3_test_control(sqlite3*) */ + case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: + rc2 = sqlite3_test_control(testctrl, p->db); + isOk = 3; + break; + + case SQLITE_TESTCTRL_IMPOSTER: + if( nArg==5 ){ + rc2 = sqlite3_test_control(testctrl, p->db, + azArg[2], + integerValue(azArg[3]), + integerValue(azArg[4])); + isOk = 3; + } + break; + + case SQLITE_TESTCTRL_SEEK_COUNT: { + u64 x = 0; + rc2 = sqlite3_test_control(testctrl, p->db, &x); + utf8_printf(p->out, "%llu\n", x); + isOk = 3; + break; + } #ifdef YYCOVERAGE - case SQLITE_TESTCTRL_PARSER_COVERAGE: { - if( nArg==2 ){ - sqlite3_test_control(testctrl, p->out); - isOk = 3; - } - break; - } + case SQLITE_TESTCTRL_PARSER_COVERAGE: { + if( nArg==2 ){ + sqlite3_test_control(testctrl, p->out); + isOk = 3; + } + break; + } #endif #ifdef SQLITE_DEBUG - case SQLITE_TESTCTRL_TUNE: { - if( nArg==4 ){ - int id = (int)integerValue(azArg[2]); - int val = (int)integerValue(azArg[3]); - sqlite3_test_control(testctrl, id, &val); - isOk = 3; - }else if( nArg==3 ){ - int id = (int)integerValue(azArg[2]); - sqlite3_test_control(testctrl, -id, &rc2); - isOk = 1; - }else if( nArg==2 ){ - int id = 1; - while(1){ - int val = 0; - rc2 = sqlite3_test_control(testctrl, -id, &val); - if( rc2!=SQLITE_OK ) break; - if( id>1 ) utf8_printf(p->out, " "); - utf8_printf(p->out, "%d: %d", id, val); - id++; - } - if( id>1 ) utf8_printf(p->out, "\n"); - isOk = 3; - } - break; - } + case SQLITE_TESTCTRL_TUNE: { + if( nArg==4 ){ + int id = (int)integerValue(azArg[2]); + int val = (int)integerValue(azArg[3]); + sqlite3_test_control(testctrl, id, &val); + isOk = 3; + }else if( nArg==3 ){ + int id = (int)integerValue(azArg[2]); + sqlite3_test_control(testctrl, -id, &rc2); + isOk = 1; + }else if( nArg==2 ){ + int id = 1; + while(1){ + int val = 0; + rc2 = sqlite3_test_control(testctrl, -id, &val); + if( rc2!=SQLITE_OK ) break; + if( id>1 ) utf8_printf(p->out, " "); + utf8_printf(p->out, "%d: %d", id, val); + id++; + } + if( id>1 ) utf8_printf(p->out, "\n"); + isOk = 3; + } + break; + } #endif - case SQLITE_TESTCTRL_SORTER_MMAP: - if( nArg==3 ){ - int opt = (unsigned int)integerValue(azArg[2]); - rc2 = sqlite3_test_control(testctrl, p->db, opt); - isOk = 3; - } - break; - } - } - if( isOk==0 && iCtrl>=0 ){ - utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); - rc = 1; - }else if( isOk==1 ){ - raw_printf(p->out, "%d\n", rc2); - }else if( isOk==2 ){ - raw_printf(p->out, "0x%08x\n", rc2); - } - }else + case SQLITE_TESTCTRL_SORTER_MMAP: + if( nArg==3 ){ + int opt = (unsigned int)integerValue(azArg[2]); + rc2 = sqlite3_test_control(testctrl, p->db, opt); + isOk = 3; + } + break; + } + } + if( isOk==0 && iCtrl>=0 ){ + utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage); + rc = 1; + }else if( isOk==1 ){ + raw_printf(p->out, "%d\n", rc2); + }else if( isOk==2 ){ + raw_printf(p->out, "0x%08x\n", rc2); + } + }else #endif /* !defined(SQLITE_UNTESTABLE) */ - if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){ - open_db(p, 0); - sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0); - }else - - if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){ - if( nArg==2 ){ - enableTimer = booleanValue(azArg[1]); - if( enableTimer && !HAS_TIMER ){ - raw_printf(stderr, "Error: timer not available on this system.\n"); - enableTimer = 0; - } - }else{ - raw_printf(stderr, "Usage: .timer on|off\n"); - rc = 1; - } - }else + if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){ + open_db(p, 0); + sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0); + }else + + if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){ + if( nArg==2 ){ + enableTimer = booleanValue(azArg[1]); + if( enableTimer && !HAS_TIMER ){ + raw_printf(stderr, "Error: timer not available on this system.\n"); + enableTimer = 0; + } + }else{ + raw_printf(stderr, "Usage: .timer on|off\n"); + rc = 1; + } + }else #ifndef SQLITE_OMIT_TRACE - if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){ - int mType = 0; - int jj; - open_db(p, 0); - for(jj=1; jjeTraceType = SHELL_TRACE_EXPANDED; - } + if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){ + int mType = 0; + int jj; + open_db(p, 0); + for(jj=1; jjeTraceType = SHELL_TRACE_EXPANDED; + } #ifdef SQLITE_ENABLE_NORMALIZE - else if( optionMatch(z, "normalized") ){ - p->eTraceType = SHELL_TRACE_NORMALIZED; - } + else if( optionMatch(z, "normalized") ){ + p->eTraceType = SHELL_TRACE_NORMALIZED; + } #endif - else if( optionMatch(z, "plain") ){ - p->eTraceType = SHELL_TRACE_PLAIN; - } - else if( optionMatch(z, "profile") ){ - mType |= SQLITE_TRACE_PROFILE; - } - else if( optionMatch(z, "row") ){ - mType |= SQLITE_TRACE_ROW; - } - else if( optionMatch(z, "stmt") ){ - mType |= SQLITE_TRACE_STMT; - } - else if( optionMatch(z, "close") ){ - mType |= SQLITE_TRACE_CLOSE; - } - else { - raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z); - rc = 1; - goto meta_command_exit; - } - }else{ - output_file_close(p->traceOut); - p->traceOut = output_file_open(azArg[1], 0); - } - } - if( p->traceOut==0 ){ - sqlite3_trace_v2(p->db, 0, 0, 0); - }else{ - if( mType==0 ) mType = SQLITE_TRACE_STMT; - sqlite3_trace_v2(p->db, mType, sql_trace_callback, p); - } - }else + else if( optionMatch(z, "plain") ){ + p->eTraceType = SHELL_TRACE_PLAIN; + } + else if( optionMatch(z, "profile") ){ + mType |= SQLITE_TRACE_PROFILE; + } + else if( optionMatch(z, "row") ){ + mType |= SQLITE_TRACE_ROW; + } + else if( optionMatch(z, "stmt") ){ + mType |= SQLITE_TRACE_STMT; + } + else if( optionMatch(z, "close") ){ + mType |= SQLITE_TRACE_CLOSE; + } + else { + raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z); + rc = 1; + goto meta_command_exit; + } + }else{ + output_file_close(p->traceOut); + p->traceOut = output_file_open(azArg[1], 0); + } + } + if( p->traceOut==0 ){ + sqlite3_trace_v2(p->db, 0, 0, 0); + }else{ + if( mType==0 ) mType = SQLITE_TRACE_STMT; + sqlite3_trace_v2(p->db, mType, sql_trace_callback, p); + } + }else #endif /* !defined(SQLITE_OMIT_TRACE) */ #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE) - if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){ - int ii; - int lenOpt; - char *zOpt; - if( nArg<2 ){ - raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n"); - rc = 1; - goto meta_command_exit; - } - open_db(p, 0); - zOpt = azArg[1]; - if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++; - lenOpt = (int)strlen(zOpt); - if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){ - assert( azArg[nArg]==0 ); - sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0); - }else{ - for(ii=1; iidb, azArg[ii], 0, 0); - } - } - }else + if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){ + int ii; + int lenOpt; + char *zOpt; + if( nArg<2 ){ + raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n"); + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + zOpt = azArg[1]; + if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++; + lenOpt = (int)strlen(zOpt); + if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){ + assert( azArg[nArg]==0 ); + sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0); + }else{ + for(ii=1; iidb, azArg[ii], 0, 0); + } + } + }else #endif #if SQLITE_USER_AUTHENTICATION - if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ - if( nArg<2 ){ - raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n"); - rc = 1; - goto meta_command_exit; - } - open_db(p, 0); - if( strcmp(azArg[1],"login")==0 ){ - if( nArg!=4 ){ - raw_printf(stderr, "Usage: .user login USER PASSWORD\n"); - rc = 1; - goto meta_command_exit; - } - rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], - strlen30(azArg[3])); - if( rc ){ - utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]); - rc = 1; - } - }else if( strcmp(azArg[1],"add")==0 ){ - if( nArg!=5 ){ - raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); - rc = 1; - goto meta_command_exit; - } - rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]), - booleanValue(azArg[4])); - if( rc ){ - raw_printf(stderr, "User-Add failed: %d\n", rc); - rc = 1; - } - }else if( strcmp(azArg[1],"edit")==0 ){ - if( nArg!=5 ){ - raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n"); - rc = 1; - goto meta_command_exit; - } - rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]), - booleanValue(azArg[4])); - if( rc ){ - raw_printf(stderr, "User-Edit failed: %d\n", rc); - rc = 1; - } - }else if( strcmp(azArg[1],"delete")==0 ){ - if( nArg!=3 ){ - raw_printf(stderr, "Usage: .user delete USER\n"); - rc = 1; - goto meta_command_exit; - } - rc = sqlite3_user_delete(p->db, azArg[2]); - if( rc ){ - raw_printf(stderr, "User-Delete failed: %d\n", rc); - rc = 1; - } - }else{ - raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n"); - rc = 1; - goto meta_command_exit; - } - }else + if( c=='u' && strncmp(azArg[0], "user", n)==0 ){ + if( nArg<2 ){ + raw_printf(stderr, "Usage: .user SUBCOMMAND ...\n"); + rc = 1; + goto meta_command_exit; + } + open_db(p, 0); + if( strcmp(azArg[1],"login")==0 ){ + if( nArg!=4 ){ + raw_printf(stderr, "Usage: .user login USER PASSWORD\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], + strlen30(azArg[3])); + if( rc ){ + utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]); + rc = 1; + } + }else if( strcmp(azArg[1],"add")==0 ){ + if( nArg!=5 ){ + raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]), + booleanValue(azArg[4])); + if( rc ){ + raw_printf(stderr, "User-Add failed: %d\n", rc); + rc = 1; + } + }else if( strcmp(azArg[1],"edit")==0 ){ + if( nArg!=5 ){ + raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]), + booleanValue(azArg[4])); + if( rc ){ + raw_printf(stderr, "User-Edit failed: %d\n", rc); + rc = 1; + } + }else if( strcmp(azArg[1],"delete")==0 ){ + if( nArg!=3 ){ + raw_printf(stderr, "Usage: .user delete USER\n"); + rc = 1; + goto meta_command_exit; + } + rc = sqlite3_user_delete(p->db, azArg[2]); + if( rc ){ + raw_printf(stderr, "User-Delete failed: %d\n", rc); + rc = 1; + } + }else{ + raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n"); + rc = 1; + goto meta_command_exit; + } + }else #endif /* SQLITE_USER_AUTHENTICATION */ - if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ - utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/, - sqlite3_libversion(), sqlite3_sourceid()); + if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ + utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/, + sqlite3_libversion(), sqlite3_sourceid()); #if SQLITE_HAVE_ZLIB - utf8_printf(p->out, "zlib version %s\n", zlibVersion()); + utf8_printf(p->out, "zlib version %s\n", zlibVersion()); #endif #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) #if defined(__clang__) && defined(__clang_major__) - utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "." - CTIMEOPT_VAL(__clang_minor__) "." - CTIMEOPT_VAL(__clang_patchlevel__) "\n"); + utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "." + CTIMEOPT_VAL(__clang_minor__) "." + CTIMEOPT_VAL(__clang_patchlevel__) "\n"); #elif defined(_MSC_VER) - utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n"); + utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n"); #elif defined(__GNUC__) && defined(__VERSION__) - utf8_printf(p->out, "gcc-" __VERSION__ "\n"); + utf8_printf(p->out, "gcc-" __VERSION__ "\n"); #endif - }else - - if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){ - const char *zDbName = nArg==2 ? azArg[1] : "main"; - sqlite3_vfs *pVfs = 0; - if( p->db ){ - sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs); - if( pVfs ){ - utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName); - raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); - raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); - raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); - } - } - }else - - if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){ - sqlite3_vfs *pVfs; - sqlite3_vfs *pCurrent = 0; - if( p->db ){ - sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent); - } - for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ - utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName, - pVfs==pCurrent ? " <--- CURRENT" : ""); - raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); - raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); - raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); - if( pVfs->pNext ){ - raw_printf(p->out, "-----------------------------------\n"); - } - } - }else - - if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){ - const char *zDbName = nArg==2 ? azArg[1] : "main"; - char *zVfsName = 0; - if( p->db ){ - sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName); - if( zVfsName ){ - utf8_printf(p->out, "%s\n", zVfsName); - sqlite3_free(zVfsName); - } - } - }else - - if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ - unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff; - sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x); - }else - - if( c=='w' && strncmp(azArg[0], "width", n)==0 ){ - int j; - assert( nArg<=ArraySize(azArg) ); - p->nWidth = nArg-1; - p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2); - if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory(); - if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth]; - for(j=1; jcolWidth[j-1] = (int)integerValue(azArg[j]); - } - }else - - { - utf8_printf(stderr, "Error: unknown command or invalid arguments: " - " \"%s\". Enter \".help\" for help\n", azArg[0]); - rc = 1; - } + }else -meta_command_exit: - if( p->outCount ){ - p->outCount--; - if( p->outCount==0 ) output_reset(p); + if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){ + const char *zDbName = nArg==2 ? azArg[1] : "main"; + sqlite3_vfs *pVfs = 0; + if( p->db ){ + sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs); + if( pVfs ){ + utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName); + raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); + raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); + raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); + } + } + }else + + if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){ + sqlite3_vfs *pVfs; + sqlite3_vfs *pCurrent = 0; + if( p->db ){ + sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent); + } + for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ + utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName, + pVfs==pCurrent ? " <--- CURRENT" : ""); + raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); + raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); + raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); + if( pVfs->pNext ){ + raw_printf(p->out, "-----------------------------------\n"); + } + } + }else + + if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){ + const char *zDbName = nArg==2 ? azArg[1] : "main"; + char *zVfsName = 0; + if( p->db ){ + sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName); + if( zVfsName ){ + utf8_printf(p->out, "%s\n", zVfsName); + sqlite3_free(zVfsName); + } } - p->bSafeMode = p->bSafeModePersist; - return rc; + }else + + if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ + unsigned int x = nArg>=2 ? (unsigned int)integerValue(azArg[1]) : 0xffffffff; + sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x); + }else + + if( c=='w' && strncmp(azArg[0], "width", n)==0 ){ + int j; + assert( nArg<=ArraySize(azArg) ); + p->nWidth = nArg-1; + p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2); + if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory(); + if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth]; + for(j=1; jcolWidth[j-1] = (int)integerValue(azArg[j]); + } + }else + + { + utf8_printf(stderr, "Error: unknown command or invalid arguments: " + " \"%s\". Enter \".help\" for help\n", azArg[0]); + rc = 1; + } + +meta_command_exit: + if( p->outCount ){ + p->outCount--; + if( p->outCount==0 ) output_reset(p); + } + p->bSafeMode = p->bSafeModePersist; + return rc; } /* Line scan result and intermediate states (supporting scan resumption) @@ -21752,9 +21752,9 @@ meta_command_exit: # define CHAR_BIT 8 #endif typedef enum { - QSS_HasDark = 1<flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0; - BEGIN_TIMER; - rc = shell_exec(p, zSql, &zErrMsg); - END_TIMER; - if( rc || zErrMsg ){ - char zPrefix[100]; - if( in!=0 || !stdin_is_interactive ){ - sqlite3_snprintf(sizeof(zPrefix), zPrefix, - "Error: near line %d:", startline); - }else{ - sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); - } - if( zErrMsg!=0 ){ - utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg); - sqlite3_free(zErrMsg); - zErrMsg = 0; - }else{ - utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); - } - return 1; - }else if( ShellHasFlag(p, SHFLG_CountChanges) ){ - char zLineBuf[2000]; - sqlite3_snprintf(sizeof(zLineBuf), zLineBuf, + int rc; + char *zErrMsg = 0; + + open_db(p, 0); + if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql); + if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0; + BEGIN_TIMER; + rc = shell_exec(p, zSql, &zErrMsg); + END_TIMER; + if( rc || zErrMsg ){ + char zPrefix[100]; + if( in!=0 || !stdin_is_interactive ){ + sqlite3_snprintf(sizeof(zPrefix), zPrefix, + "Error: near line %d:", startline); + }else{ + sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:"); + } + if( zErrMsg!=0 ){ + utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg); + sqlite3_free(zErrMsg); + zErrMsg = 0; + }else{ + utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); + } + return 1; + }else if( ShellHasFlag(p, SHFLG_CountChanges) ){ + char zLineBuf[2000]; + sqlite3_snprintf(sizeof(zLineBuf), zLineBuf, "changes: %lld total_changes: %lld", sqlite3_changes64(p->db), sqlite3_total_changes64(p->db)); - raw_printf(p->out, "%s\n", zLineBuf); - } - return 0; + raw_printf(p->out, "%s\n", zLineBuf); + } + return 0; } @@ -21927,99 +21927,99 @@ static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){ ** Return the number of errors. */ static int process_input(ShellState *p){ - char *zLine = 0; /* A single input line */ - char *zSql = 0; /* Accumulated SQL text */ - int nLine; /* Length of current line */ - int nSql = 0; /* Bytes of zSql[] used */ - int nAlloc = 0; /* Allocated zSql[] space */ - int rc; /* Error code */ - int errCnt = 0; /* Number of errors seen */ - int startline = 0; /* Line number for start of current input */ - QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */ - - p->lineno = 0; - while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){ - fflush(p->out); - zLine = one_input_line(p->in, zLine, nSql>0); - if( zLine==0 ){ - /* End of input */ - if( p->in==0 && stdin_is_interactive ) printf("\n"); - break; - } - if( seenInterrupt ){ - if( p->in!=0 ) break; - seenInterrupt = 0; - } - p->lineno++; - if( QSS_INPLAIN(qss) - && line_is_command_terminator(zLine) - && line_is_complete(zSql, nSql) ){ - memcpy(zLine,";",2); - } - qss = quickscan(zLine, qss); - if( QSS_PLAINWHITE(qss) && nSql==0 ){ - if( ShellHasFlag(p, SHFLG_Echo) ) - printf("%s\n", zLine); - /* Just swallow single-line whitespace */ - qss = QSS_Start; - continue; - } - if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){ - if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine); - if( zLine[0]=='.' ){ - rc = do_meta_command(zLine, p); - if( rc==2 ){ /* exit requested */ - break; - }else if( rc ){ - errCnt++; - } - } - qss = QSS_Start; - continue; - } - /* No single-line dispositions remain; accumulate line(s). */ - nLine = strlen30(zLine); - if( nSql+nLine+2>=nAlloc ){ - /* Grow buffer by half-again increments when big. */ - nAlloc = nSql+(nSql>>1)+nLine+100; - zSql = realloc(zSql, nAlloc); - if( zSql==0 ) shell_out_of_memory(); - } - if( nSql==0 ){ - int i; - for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} - assert( nAlloc>0 && zSql!=0 ); - memcpy(zSql, zLine+i, nLine+1-i); - startline = p->lineno; - nSql = nLine-i; - }else{ - zSql[nSql++] = '\n'; - memcpy(zSql+nSql, zLine, nLine+1); - nSql += nLine; - } - if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){ - errCnt += runOneSqlLine(p, zSql, p->in, startline); - nSql = 0; - if( p->outCount ){ - output_reset(p); - p->outCount = 0; - }else{ - clearTempFile(p); - } - p->bSafeMode = p->bSafeModePersist; - qss = QSS_Start; - }else if( nSql && QSS_PLAINWHITE(qss) ){ - if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql); - nSql = 0; - qss = QSS_Start; - } - } - if( nSql && QSS_PLAINDARK(qss) ){ - errCnt += runOneSqlLine(p, zSql, p->in, startline); + char *zLine = 0; /* A single input line */ + char *zSql = 0; /* Accumulated SQL text */ + int nLine; /* Length of current line */ + int nSql = 0; /* Bytes of zSql[] used */ + int nAlloc = 0; /* Allocated zSql[] space */ + int rc; /* Error code */ + int errCnt = 0; /* Number of errors seen */ + int startline = 0; /* Line number for start of current input */ + QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */ + + p->lineno = 0; + while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){ + fflush(p->out); + zLine = one_input_line(p->in, zLine, nSql>0); + if( zLine==0 ){ + /* End of input */ + if( p->in==0 && stdin_is_interactive ) printf("\n"); + break; } - free(zSql); - free(zLine); - return errCnt>0; + if( seenInterrupt ){ + if( p->in!=0 ) break; + seenInterrupt = 0; + } + p->lineno++; + if( QSS_INPLAIN(qss) + && line_is_command_terminator(zLine) + && line_is_complete(zSql, nSql) ){ + memcpy(zLine,";",2); + } + qss = quickscan(zLine, qss); + if( QSS_PLAINWHITE(qss) && nSql==0 ){ + if( ShellHasFlag(p, SHFLG_Echo) ) + printf("%s\n", zLine); + /* Just swallow single-line whitespace */ + qss = QSS_Start; + continue; + } + if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){ + if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine); + if( zLine[0]=='.' ){ + rc = do_meta_command(zLine, p); + if( rc==2 ){ /* exit requested */ + break; + }else if( rc ){ + errCnt++; + } + } + qss = QSS_Start; + continue; + } + /* No single-line dispositions remain; accumulate line(s). */ + nLine = strlen30(zLine); + if( nSql+nLine+2>=nAlloc ){ + /* Grow buffer by half-again increments when big. */ + nAlloc = nSql+(nSql>>1)+nLine+100; + zSql = realloc(zSql, nAlloc); + if( zSql==0 ) shell_out_of_memory(); + } + if( nSql==0 ){ + int i; + for(i=0; zLine[i] && IsSpace(zLine[i]); i++){} + assert( nAlloc>0 && zSql!=0 ); + memcpy(zSql, zLine+i, nLine+1-i); + startline = p->lineno; + nSql = nLine-i; + }else{ + zSql[nSql++] = '\n'; + memcpy(zSql+nSql, zLine, nLine+1); + nSql += nLine; + } + if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){ + errCnt += runOneSqlLine(p, zSql, p->in, startline); + nSql = 0; + if( p->outCount ){ + output_reset(p); + p->outCount = 0; + }else{ + clearTempFile(p); + } + p->bSafeMode = p->bSafeModePersist; + qss = QSS_Start; + }else if( nSql && QSS_PLAINWHITE(qss) ){ + if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql); + nSql = 0; + qss = QSS_Start; + } + } + if( nSql && QSS_PLAINDARK(qss) ){ + errCnt += runOneSqlLine(p, zSql, p->in, startline); + } + free(zSql); + free(zLine); + return errCnt>0; } /* @@ -22027,68 +22027,68 @@ static int process_input(ShellState *p){ ** 0 return indicates an error of some kind. */ static char *find_home_dir(int clearFlag){ - static char *home_dir = NULL; - if( clearFlag ){ - free(home_dir); - home_dir = 0; - return 0; - } - if( home_dir ) return home_dir; + static char *home_dir = NULL; + if( clearFlag ){ + free(home_dir); + home_dir = 0; + return 0; + } + if( home_dir ) return home_dir; #if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \ && !defined(__RTP__) && !defined(_WRS_KERNEL) - { - struct passwd *pwent; - uid_t uid = getuid(); - if( (pwent=getpwuid(uid)) != NULL) { - home_dir = pwent->pw_dir; - } + { + struct passwd *pwent; + uid_t uid = getuid(); + if( (pwent=getpwuid(uid)) != NULL) { + home_dir = pwent->pw_dir; } + } #endif #if defined(_WIN32_WCE) - /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() + /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv() */ - home_dir = "/"; + home_dir = "/"; #else #if defined(_WIN32) || defined(WIN32) - if (!home_dir) { - home_dir = getenv("USERPROFILE"); - } + if (!home_dir) { + home_dir = getenv("USERPROFILE"); + } #endif - if (!home_dir) { - home_dir = getenv("HOME"); - } + if (!home_dir) { + home_dir = getenv("HOME"); + } #if defined(_WIN32) || defined(WIN32) - if (!home_dir) { - char *zDrive, *zPath; - int n; - zDrive = getenv("HOMEDRIVE"); - zPath = getenv("HOMEPATH"); - if( zDrive && zPath ){ - n = strlen30(zDrive) + strlen30(zPath) + 1; - home_dir = malloc( n ); - if( home_dir==0 ) return 0; - sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath); - return home_dir; - } - home_dir = "c:\\"; - } + if (!home_dir) { + char *zDrive, *zPath; + int n; + zDrive = getenv("HOMEDRIVE"); + zPath = getenv("HOMEPATH"); + if( zDrive && zPath ){ + n = strlen30(zDrive) + strlen30(zPath) + 1; + home_dir = malloc( n ); + if( home_dir==0 ) return 0; + sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath); + return home_dir; + } + home_dir = "c:\\"; + } #endif #endif /* !_WIN32_WCE */ - if( home_dir ){ - int n = strlen30(home_dir) + 1; - char *z = malloc( n ); - if( z ) memcpy(z, home_dir, n); - home_dir = z; - } + if( home_dir ){ + int n = strlen30(home_dir) + 1; + char *z = malloc( n ); + if( z ) memcpy(z, home_dir, n); + home_dir = z; + } - return home_dir; + return home_dir; } /* @@ -22098,39 +22098,39 @@ static char *find_home_dir(int clearFlag){ ** Returns the number of errors. */ static void process_sqliterc( - ShellState *p, /* Configuration data */ - const char *sqliterc_override /* Name of config file. NULL to use default */ + ShellState *p, /* Configuration data */ + const char *sqliterc_override /* Name of config file. NULL to use default */ ){ - char *home_dir = NULL; - const char *sqliterc = sqliterc_override; - char *zBuf = 0; - FILE *inSaved = p->in; - int savedLineno = p->lineno; - - if (sqliterc == NULL) { - home_dir = find_home_dir(0); - if( home_dir==0 ){ - raw_printf(stderr, "-- warning: cannot find home directory;" - " cannot read ~/.sqliterc\n"); - return; - } - zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); - sqliterc = zBuf; - } - p->in = fopen(sqliterc,"rb"); - if( p->in ){ - if( stdin_is_interactive ){ - utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc); - } - if( process_input(p) && bail_on_error ) exit(1); - fclose(p->in); - }else if( sqliterc_override!=0 ){ - utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc); - if( bail_on_error ) exit(1); - } - p->in = inSaved; - p->lineno = savedLineno; - sqlite3_free(zBuf); + char *home_dir = NULL; + const char *sqliterc = sqliterc_override; + char *zBuf = 0; + FILE *inSaved = p->in; + int savedLineno = p->lineno; + + if (sqliterc == NULL) { + home_dir = find_home_dir(0); + if( home_dir==0 ){ + raw_printf(stderr, "-- warning: cannot find home directory;" + " cannot read ~/.sqliterc\n"); + return; + } + zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); + sqliterc = zBuf; + } + p->in = fopen(sqliterc,"rb"); + if( p->in ){ + if( stdin_is_interactive ){ + utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc); + } + if( process_input(p) && bail_on_error ) exit(1); + fclose(p->in); + }else if( sqliterc_override!=0 ){ + utf8_printf(stderr,"cannot open: \"%s\"\n", sqliterc); + if( bail_on_error ) exit(1); + } + p->in = inSaved; + p->lineno = savedLineno; + sqlite3_free(zBuf); } /* @@ -22138,76 +22138,76 @@ static void process_sqliterc( */ static const char zOptions[] = #if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE) - " -A ARGS... run \".archive ARGS\" and exit\n" + " -A ARGS... run \".archive ARGS\" and exit\n" #endif - " -append append the database to the end of the file\n" - " -ascii set output mode to 'ascii'\n" - " -bail stop after hitting an error\n" - " -batch force batch I/O\n" - " -box set output mode to 'box'\n" - " -column set output mode to 'column'\n" - " -cmd COMMAND run \"COMMAND\" before reading stdin\n" - " -csv set output mode to 'csv'\n" + " -append append the database to the end of the file\n" + " -ascii set output mode to 'ascii'\n" + " -bail stop after hitting an error\n" + " -batch force batch I/O\n" + " -box set output mode to 'box'\n" + " -column set output mode to 'column'\n" + " -cmd COMMAND run \"COMMAND\" before reading stdin\n" + " -csv set output mode to 'csv'\n" #if !defined(SQLITE_OMIT_DESERIALIZE) - " -deserialize open the database using sqlite3_deserialize()\n" + " -deserialize open the database using sqlite3_deserialize()\n" #endif - " -echo print commands before execution\n" - " -init FILENAME read/process named file\n" - " -[no]header turn headers on or off\n" + " -echo print commands before execution\n" + " -init FILENAME read/process named file\n" + " -[no]header turn headers on or off\n" #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) - " -heap SIZE Size of heap for memsys3 or memsys5\n" + " -heap SIZE Size of heap for memsys3 or memsys5\n" #endif - " -help show this message\n" - " -html set output mode to HTML\n" - " -interactive force interactive I/O\n" - " -json set output mode to 'json'\n" - " -line set output mode to 'line'\n" - " -list set output mode to 'list'\n" - " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" - " -markdown set output mode to 'markdown'\n" + " -help show this message\n" + " -html set output mode to HTML\n" + " -interactive force interactive I/O\n" + " -json set output mode to 'json'\n" + " -line set output mode to 'line'\n" + " -list set output mode to 'list'\n" + " -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n" + " -markdown set output mode to 'markdown'\n" #if !defined(SQLITE_OMIT_DESERIALIZE) - " -maxsize N maximum size for a --deserialize database\n" + " -maxsize N maximum size for a --deserialize database\n" #endif - " -memtrace trace all memory allocations and deallocations\n" - " -mmap N default mmap size set to N\n" + " -memtrace trace all memory allocations and deallocations\n" + " -mmap N default mmap size set to N\n" #ifdef SQLITE_ENABLE_MULTIPLEX - " -multiplex enable the multiplexor VFS\n" + " -multiplex enable the multiplexor VFS\n" #endif - " -newline SEP set output row separator. Default: '\\n'\n" - " -nofollow refuse to open symbolic links to database files\n" - " -nonce STRING set the safe-mode escape nonce\n" - " -nullvalue TEXT set text string for NULL values. Default ''\n" - " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" - " -quote set output mode to 'quote'\n" - " -readonly open the database read-only\n" - " -safe enable safe-mode\n" - " -separator SEP set output column separator. Default: '|'\n" + " -newline SEP set output row separator. Default: '\\n'\n" + " -nofollow refuse to open symbolic links to database files\n" + " -nonce STRING set the safe-mode escape nonce\n" + " -nullvalue TEXT set text string for NULL values. Default ''\n" + " -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n" + " -quote set output mode to 'quote'\n" + " -readonly open the database read-only\n" + " -safe enable safe-mode\n" + " -separator SEP set output column separator. Default: '|'\n" #ifdef SQLITE_ENABLE_SORTER_REFERENCES - " -sorterref SIZE sorter references threshold size\n" + " -sorterref SIZE sorter references threshold size\n" #endif - " -stats print memory stats before each finalize\n" - " -table set output mode to 'table'\n" - " -tabs set output mode to 'tabs'\n" - " -version show SQLite version\n" - " -vfs NAME use NAME as the default VFS\n" + " -stats print memory stats before each finalize\n" + " -table set output mode to 'table'\n" + " -tabs set output mode to 'tabs'\n" + " -version show SQLite version\n" + " -vfs NAME use NAME as the default VFS\n" #ifdef SQLITE_ENABLE_VFSTRACE - " -vfstrace enable tracing of all VFS calls\n" + " -vfstrace enable tracing of all VFS calls\n" #endif #ifdef SQLITE_HAVE_ZLIB - " -zip open the file as a ZIP Archive\n" + " -zip open the file as a ZIP Archive\n" #endif - ; +; static void usage(int showDetail){ - utf8_printf(stderr, - "Usage: %s [OPTIONS] FILENAME [SQL]\n" - "FILENAME is the name of an SQLite database. A new database is created\n" - "if the file does not previously exist.\n", Argv0); - if( showDetail ){ - utf8_printf(stderr, "OPTIONS include:\n%s", zOptions); - }else{ - raw_printf(stderr, "Use the -help option for additional information\n"); - } - exit(1); + utf8_printf(stderr, + "Usage: %s [OPTIONS] FILENAME [SQL]\n" + "FILENAME is the name of an SQLite database. A new database is created\n" + "if the file does not previously exist.\n", Argv0); + if( showDetail ){ + utf8_printf(stderr, "OPTIONS include:\n%s", zOptions); + }else{ + raw_printf(stderr, "Use the -help option for additional information\n"); + } + exit(1); } /* @@ -22215,30 +22215,30 @@ static void usage(int showDetail){ ** error message if it is initialized. */ static void verify_uninitialized(void){ - if( sqlite3_config(-1)==SQLITE_MISUSE ){ - utf8_printf(stdout, "WARNING: attempt to configure SQLite after" - " initialization.\n"); - } + if( sqlite3_config(-1)==SQLITE_MISUSE ){ + utf8_printf(stdout, "WARNING: attempt to configure SQLite after" + " initialization.\n"); + } } /* ** Initialize the state information in data */ static void main_init(ShellState *data) { - memset(data, 0, sizeof(*data)); - data->normalMode = data->cMode = data->mode = MODE_List; - data->autoExplain = 1; - data->pAuxDb = &data->aAuxDb[0]; - memcpy(data->colSeparator,SEP_Column, 2); - memcpy(data->rowSeparator,SEP_Row, 2); - data->showHeader = 0; - data->shellFlgs = SHFLG_Lookaside; - verify_uninitialized(); - sqlite3_config(SQLITE_CONFIG_URI, 1); - sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); - sqlite3_config(SQLITE_CONFIG_MULTITHREAD); - sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); - sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); + memset(data, 0, sizeof(*data)); + data->normalMode = data->cMode = data->mode = MODE_List; + data->autoExplain = 1; + data->pAuxDb = &data->aAuxDb[0]; + memcpy(data->colSeparator,SEP_Column, 2); + memcpy(data->rowSeparator,SEP_Row, 2); + data->showHeader = 0; + data->shellFlgs = SHFLG_Lookaside; + verify_uninitialized(); + sqlite3_config(SQLITE_CONFIG_URI, 1); + sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); + sqlite3_config(SQLITE_CONFIG_MULTITHREAD); + sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); + sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); } /* @@ -22247,21 +22247,21 @@ static void main_init(ShellState *data) { #ifdef _WIN32 static void printBold(const char *zText){ #if !SQLITE_OS_WINRT - HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; - GetConsoleScreenBufferInfo(out, &defaultScreenInfo); - SetConsoleTextAttribute(out, - FOREGROUND_RED|FOREGROUND_INTENSITY - ); + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo; + GetConsoleScreenBufferInfo(out, &defaultScreenInfo); + SetConsoleTextAttribute(out, + FOREGROUND_RED|FOREGROUND_INTENSITY + ); #endif - printf("%s", zText); + printf("%s", zText); #if !SQLITE_OS_WINRT - SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); + SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes); #endif } #else static void printBold(const char *zText){ - printf("\033[1m%s\033[0m", zText); + printf("\033[1m%s\033[0m", zText); } #endif @@ -22270,12 +22270,12 @@ static void printBold(const char *zText){ ** is available. */ static char *cmdline_option_value(int argc, char **argv, int i){ - if( i==argc ){ - utf8_printf(stderr, "%s: Error: missing argument to %s\n", + if( i==argc ){ + utf8_printf(stderr, "%s: Error: missing argument to %s\n", argv[0], argv[argc-1]); - exit(1); - } - return argv[i]; + exit(1); + } + return argv[i]; } #ifndef SQLITE_SHELL_IS_UTF8 @@ -22291,577 +22291,577 @@ static char *cmdline_option_value(int argc, char **argv, int i){ int SQLITE_CDECL main(int argc, char **argv){ #else int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ - char **argv; + char **argv; #endif - char *zErrMsg = 0; - ShellState data; - const char *zInitFile = 0; - int i; - int rc = 0; - int warnInmemoryDb = 0; - int readStdin = 1; - int nCmd = 0; - char **azCmd = 0; - const char *zVfs = 0; /* Value of -vfs command-line option */ + char *zErrMsg = 0; + ShellState data; + const char *zInitFile = 0; + int i; + int rc = 0; + int warnInmemoryDb = 0; + int readStdin = 1; + int nCmd = 0; + char **azCmd = 0; + const char *zVfs = 0; /* Value of -vfs command-line option */ #if !SQLITE_SHELL_IS_UTF8 - char **argvToFree = 0; - int argcToFree = 0; + char **argvToFree = 0; + int argcToFree = 0; #endif - setBinaryMode(stdin, 0); - setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ - stdin_is_interactive = isatty(0); - stdout_is_console = isatty(1); + setBinaryMode(stdin, 0); + setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ + stdin_is_interactive = isatty(0); + stdout_is_console = isatty(1); #ifdef SQLITE_DEBUG - registerOomSimulator(); + registerOomSimulator(); #endif #if !defined(_WIN32_WCE) - if( getenv("SQLITE_DEBUG_BREAK") ){ - if( isatty(0) && isatty(2) ){ - fprintf(stderr, - "attach debugger to process %d and press any key to continue.\n", - GETPID()); - fgetc(stdin); - }else{ + if( getenv("SQLITE_DEBUG_BREAK") ){ + if( isatty(0) && isatty(2) ){ + fprintf(stderr, + "attach debugger to process %d and press any key to continue.\n", + GETPID()); + fgetc(stdin); + }else{ #if defined(_WIN32) || defined(WIN32) #if SQLITE_OS_WINRT - __debugbreak(); + __debugbreak(); #else - DebugBreak(); + DebugBreak(); #endif #elif defined(SIGTRAP) - raise(SIGTRAP); + raise(SIGTRAP); #endif - } } + } #endif #if USE_SYSTEM_SQLITE+0!=1 - if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){ - utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", + if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){ + utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", sqlite3_sourceid(), SQLITE_SOURCE_ID); - exit(1); - } + exit(1); + } #endif - main_init(&data); + main_init(&data); - /* On Windows, we must translate command-line arguments into UTF-8. + /* On Windows, we must translate command-line arguments into UTF-8. ** The SQLite memory allocator subsystem has to be enabled in order to ** do this. But we want to run an sqlite3_shutdown() afterwards so that ** subsequent sqlite3_config() calls will work. So copy all results into ** memory that does not come from the SQLite memory allocator. */ #if !SQLITE_SHELL_IS_UTF8 - sqlite3_initialize(); - argvToFree = malloc(sizeof(argv[0])*argc*2); - argcToFree = argc; - argv = argvToFree + argc; - if( argv==0 ) shell_out_of_memory(); - for(i=0; i=1 && argv && argv[0] ); - Argv0 = argv[0]; + assert( argc>=1 && argv && argv[0] ); + Argv0 = argv[0]; - /* Make sure we have a valid signal handler early, before anything + /* Make sure we have a valid signal handler early, before anything ** else is done. */ #ifdef SIGINT - signal(SIGINT, interrupt_handler); + signal(SIGINT, interrupt_handler); #elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE) - SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); + SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); #endif #ifdef SQLITE_SHELL_DBNAME_PROC - { - /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name + { + /* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name ** of a C-function that will provide the name of the database file. Use ** this compile-time option to embed this shell program in larger ** applications. */ - extern void SQLITE_SHELL_DBNAME_PROC(const char**); - SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename); - warnInmemoryDb = 0; - } + extern void SQLITE_SHELL_DBNAME_PROC(const char**); + SQLITE_SHELL_DBNAME_PROC(&data.pAuxDb->zDbFilename); + warnInmemoryDb = 0; + } #endif - /* Do an initial pass through the command-line argument to locate + /* Do an initial pass through the command-line argument to locate ** the name of the database file, the name of the initialization file, ** the size of the alternative malloc heap, ** and the first command to execute. */ - verify_uninitialized(); - for(i=1; izDbFilename==0 ){ - data.aAuxDb->zDbFilename = z; - }else{ - /* Excesss arguments are interpreted as SQL (or dot-commands) and + verify_uninitialized(); + for(i=1; izDbFilename==0 ){ + data.aAuxDb->zDbFilename = z; + }else{ + /* Excesss arguments are interpreted as SQL (or dot-commands) and ** mean that nothing is read from stdin */ - readStdin = 0; - nCmd++; - azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); - if( azCmd==0 ) shell_out_of_memory(); - azCmd[nCmd-1] = z; - } - } - if( z[1]=='-' ) z++; - if( strcmp(z,"-separator")==0 - || strcmp(z,"-nullvalue")==0 - || strcmp(z,"-newline")==0 - || strcmp(z,"-cmd")==0 - ){ - (void)cmdline_option_value(argc, argv, ++i); - }else if( strcmp(z,"-init")==0 ){ - zInitFile = cmdline_option_value(argc, argv, ++i); - }else if( strcmp(z,"-batch")==0 ){ - /* Need to check for batch mode here to so we can avoid printing + readStdin = 0; + nCmd++; + azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd); + if( azCmd==0 ) shell_out_of_memory(); + azCmd[nCmd-1] = z; + } + } + if( z[1]=='-' ) z++; + if( strcmp(z,"-separator")==0 + || strcmp(z,"-nullvalue")==0 + || strcmp(z,"-newline")==0 + || strcmp(z,"-cmd")==0 + ){ + (void)cmdline_option_value(argc, argv, ++i); + }else if( strcmp(z,"-init")==0 ){ + zInitFile = cmdline_option_value(argc, argv, ++i); + }else if( strcmp(z,"-batch")==0 ){ + /* Need to check for batch mode here to so we can avoid printing ** informational messages (like from process_sqliterc) before ** we do the actual processing of arguments later in a second pass. */ - stdin_is_interactive = 0; - }else if( strcmp(z,"-heap")==0 ){ + stdin_is_interactive = 0; + }else if( strcmp(z,"-heap")==0 ){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) - const char *zSize; - sqlite3_int64 szHeap; + const char *zSize; + sqlite3_int64 szHeap; - zSize = cmdline_option_value(argc, argv, ++i); - szHeap = integerValue(zSize); - if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; - sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); + zSize = cmdline_option_value(argc, argv, ++i); + szHeap = integerValue(zSize); + if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; + sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #else - (void)cmdline_option_value(argc, argv, ++i); + (void)cmdline_option_value(argc, argv, ++i); #endif - }else if( strcmp(z,"-pagecache")==0 ){ - sqlite3_int64 n, sz; - sz = integerValue(cmdline_option_value(argc,argv,++i)); - if( sz>70000 ) sz = 70000; - if( sz<0 ) sz = 0; - n = integerValue(cmdline_option_value(argc,argv,++i)); - if( sz>0 && n>0 && 0xffffffffffffLL/sz0 && sz>0) ? malloc(n*sz) : 0, sz, n); - data.shellFlgs |= SHFLG_Pagecache; - }else if( strcmp(z,"-lookaside")==0 ){ - int n, sz; - sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); - if( sz<0 ) sz = 0; - n = (int)integerValue(cmdline_option_value(argc,argv,++i)); - if( n<0 ) n = 0; - sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n); - if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside; - }else if( strcmp(z,"-threadsafe")==0 ){ - int n; - n = (int)integerValue(cmdline_option_value(argc,argv,++i)); - switch( n ){ - case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break; - case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break; - default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break; - } + }else if( strcmp(z,"-pagecache")==0 ){ + sqlite3_int64 n, sz; + sz = integerValue(cmdline_option_value(argc,argv,++i)); + if( sz>70000 ) sz = 70000; + if( sz<0 ) sz = 0; + n = integerValue(cmdline_option_value(argc,argv,++i)); + if( sz>0 && n>0 && 0xffffffffffffLL/sz0 && sz>0) ? malloc(n*sz) : 0, sz, n); + data.shellFlgs |= SHFLG_Pagecache; + }else if( strcmp(z,"-lookaside")==0 ){ + int n, sz; + sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( sz<0 ) sz = 0; + n = (int)integerValue(cmdline_option_value(argc,argv,++i)); + if( n<0 ) n = 0; + sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n); + if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside; + }else if( strcmp(z,"-threadsafe")==0 ){ + int n; + n = (int)integerValue(cmdline_option_value(argc,argv,++i)); + switch( n ){ + case 0: sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); break; + case 2: sqlite3_config(SQLITE_CONFIG_MULTITHREAD); break; + default: sqlite3_config(SQLITE_CONFIG_SERIALIZED); break; + } #ifdef SQLITE_ENABLE_VFSTRACE - }else if( strcmp(z,"-vfstrace")==0 ){ - extern int vfstrace_register( - const char *zTraceName, - const char *zOldVfsName, - int (*xOut)(const char*,void*), - void *pOutArg, - int makeDefault - ); - vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); + }else if( strcmp(z,"-vfstrace")==0 ){ + extern int vfstrace_register( + const char *zTraceName, + const char *zOldVfsName, + int (*xOut)(const char*,void*), + void *pOutArg, + int makeDefault + ); + vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); #endif #ifdef SQLITE_ENABLE_MULTIPLEX - }else if( strcmp(z,"-multiplex")==0 ){ - extern int sqlite3_multiple_initialize(const char*,int); - sqlite3_multiplex_initialize(0, 1); + }else if( strcmp(z,"-multiplex")==0 ){ + extern int sqlite3_multiple_initialize(const char*,int); + sqlite3_multiplex_initialize(0, 1); #endif - }else if( strcmp(z,"-mmap")==0 ){ - sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); - sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz); + }else if( strcmp(z,"-mmap")==0 ){ + sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); + sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz); #ifdef SQLITE_ENABLE_SORTER_REFERENCES - }else if( strcmp(z,"-sorterref")==0 ){ - sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); - sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz); + }else if( strcmp(z,"-sorterref")==0 ){ + sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); + sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz); #endif - }else if( strcmp(z,"-vfs")==0 ){ - zVfs = cmdline_option_value(argc, argv, ++i); + }else if( strcmp(z,"-vfs")==0 ){ + zVfs = cmdline_option_value(argc, argv, ++i); #ifdef SQLITE_HAVE_ZLIB - }else if( strcmp(z,"-zip")==0 ){ - data.openMode = SHELL_OPEN_ZIPFILE; + }else if( strcmp(z,"-zip")==0 ){ + data.openMode = SHELL_OPEN_ZIPFILE; #endif - }else if( strcmp(z,"-append")==0 ){ - data.openMode = SHELL_OPEN_APPENDVFS; + }else if( strcmp(z,"-append")==0 ){ + data.openMode = SHELL_OPEN_APPENDVFS; #ifndef SQLITE_OMIT_DESERIALIZE - }else if( strcmp(z,"-deserialize")==0 ){ - data.openMode = SHELL_OPEN_DESERIALIZE; - }else if( strcmp(z,"-maxsize")==0 && i+1zDbFilename==0 ){ + if( data.pAuxDb->zDbFilename==0 ){ #ifndef SQLITE_OMIT_MEMORYDB - data.pAuxDb->zDbFilename = ":memory:"; - warnInmemoryDb = argc==1; + data.pAuxDb->zDbFilename = ":memory:"; + warnInmemoryDb = argc==1; #else - utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0); - return 1; + utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0); + return 1; #endif - } - data.out = stdout; - sqlite3_appendvfs_init(0,0,0); + } + data.out = stdout; + sqlite3_appendvfs_init(0,0,0); - /* Go ahead and open the database file if it already exists. If the + /* Go ahead and open the database file if it already exists. If the ** file does not exist, delay opening it. This prevents empty database ** files from being created if a user mistypes the database name argument ** to the sqlite command-line tool. */ - if( access(data.pAuxDb->zDbFilename, 0)==0 ){ - open_db(&data, 0); - } + if( access(data.pAuxDb->zDbFilename, 0)==0 ){ + open_db(&data, 0); + } - /* Process the initialization file if there is one. If no -init option + /* Process the initialization file if there is one. If no -init option ** is given on the command line, look for a file named ~/.sqliterc and ** try to process it. */ - process_sqliterc(&data,zInitFile); + process_sqliterc(&data,zInitFile); - /* Make a second pass through the command-line argument and set + /* Make a second pass through the command-line argument and set ** options. This second pass is delayed until after the initialization ** file is processed so that the command-line arguments will override ** settings in the initialization file. */ - for(i=1; i0 ){ - utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands" - " with \"%s\"\n", z); - return 1; - } - open_db(&data, OPEN_DB_ZIPFILE); - if( z[2] ){ - argv[i] = &z[2]; - arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); - }else{ - arDotCommand(&data, 1, argv+i, argc-i); - } - readStdin = 0; - break; + }else if( strncmp(z, "-A", 2)==0 ){ + if( nCmd>0 ){ + utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands" + " with \"%s\"\n", z); + return 1; + } + open_db(&data, OPEN_DB_ZIPFILE); + if( z[2] ){ + argv[i] = &z[2]; + arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); + }else{ + arDotCommand(&data, 1, argv+i, argc-i); + } + readStdin = 0; + break; #endif - }else if( strcmp(z,"-safe")==0 ){ - data.bSafeMode = data.bSafeModePersist = 1; - }else{ - utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); - raw_printf(stderr,"Use -help for a list of options.\n"); - return 1; - } - data.cMode = data.mode; + }else if( strcmp(z,"-safe")==0 ){ + data.bSafeMode = data.bSafeModePersist = 1; + }else{ + utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); + raw_printf(stderr,"Use -help for a list of options.\n"); + return 1; } + data.cMode = data.mode; + } - if( !readStdin ){ - /* Run all arguments that do not begin with '-' as if they were separate + if( !readStdin ){ + /* Run all arguments that do not begin with '-' as if they were separate ** command-line inputs, except for the argToSkip argument which contains ** the database filename. */ - for(i=0; iflags; - int mDbFlagsBackup = db->mDbFlags; + u64 flagsBackup = db->flags; + u32 mDbFlagsBackup = db->mDbFlags; int nChangeBackup = db->nChange; int nTotalChangeBackup = db->nTotalChange; int (*xTraceBackup)(u32,void*,void*,void*) = db->trace.xV2; @@ -239678,4 +239678,4 @@ static const sqlite3_api_routines_hw sqlite3HwApis = { EXPORT_SYMBOLS const sqlite3_api_routines *sqlite3_export_symbols = &sqlite3Apis; EXPORT_SYMBOLS const sqlite3_api_routines_hw *sqlite3_export_hw_symbols = &sqlite3HwApis; -#endif +#endif \ No newline at end of file diff --git a/mock/src/mock_device_manager.cpp b/mock/src/mock_device_manager.cpp index 8fa4058d92226a4b7bec7f4e32cf2f5dd900726c..4296e63a11f50fd6fb5ef248c799c6541882b534 100644 --- a/mock/src/mock_device_manager.cpp +++ b/mock/src/mock_device_manager.cpp @@ -90,23 +90,11 @@ int32_t DeviceManagerImpl::VerifyAuthentication(const std::string &pkgName, cons { return 0; } -int32_t DeviceManagerImpl::RegisterDeviceManagerFaCallback(const std::string &packageName, - std::shared_ptr callback) -{ - return 0; -} -int32_t DeviceManagerImpl::UnRegisterDeviceManagerFaCallback(const std::string &pkgName) -{ - return 0; -} + int32_t DeviceManagerImpl::GetFaParam(const std::string &pkgName, DmAuthParam &faParam) { return 0; } -int32_t DeviceManagerImpl::SetUserOperation(const std::string &pkgName, int32_t action) -{ - return 0; -} int32_t DeviceManagerImpl::GetUdidByNetworkId(const std::string &pkgName, const std::string &netWorkId, std::string &udid) { @@ -170,4 +158,33 @@ int32_t DeviceManagerImpl::NotifyEvent(const std::string &pkgName, const int32_t { return 0; } +int32_t DeviceManagerImpl::GetDeviceInfo(const std::string &pkgName, const std::string networkId, + DmDeviceInfo &deviceInfo) +{ + return 0; +} +int32_t DeviceManagerImpl::SetUserOperation(const std::string &pkgName, int32_t action, const std::string ¶ms) +{ + return 0; +} + +int32_t DeviceManagerImpl::GetEncryptedUuidByNetworkId(const std::string &pkgName, const std::string &networkId, std::string &uuid) +{ + if (pkgName.empty() || networkId.empty() || networkId == std::string("no_exist_device_id") || + networkId.find("invalid_device") != std::string::npos || networkId == std::string("1234567890")) { + return -1; + } + uuid = networkId; + return 0; +} + +int32_t DeviceManagerImpl::GenerateEncryptedUuid(const std::string &pkgName, const std::string &uuid, const std::string &appId, + std::string &encryptedUuid) +{ + if (pkgName.empty() || uuid.empty()) { + return -1; + } + encryptedUuid = uuid; + return 0; +} } \ No newline at end of file diff --git a/mock/src/mock_huks.cpp b/mock/src/mock_huks.cpp index 7b3abc8d03ca68595fd890fc4f7a4af43525faae..3d1fb2350be446e6dd5695a655148736b368182e 100644 --- a/mock/src/mock_huks.cpp +++ b/mock/src/mock_huks.cpp @@ -13,24 +13,489 @@ * limitations under the License. */ #include +#include +#include #include #include #include +#include +#include +#include #include "securec.h" -int32_t HksInitParamSet(struct HksParamSet **paramSet) { return HKS_SUCCESS; } -int32_t HksAddParams(struct HksParamSet *paramSet, const struct HksParam *params, uint32_t paramCnt) +static std::set KEYS; + +void *HksMalloc(size_t size) +{ + return malloc(size); +} + +int32_t HksMemCmp(const void *ptr1, const void *ptr2, uint32_t size) +{ + return memcmp(ptr1, ptr2, size); +} +static uint32_t g_validTags[] = { + HKS_TAG_ALGORITHM, + HKS_TAG_PURPOSE, + HKS_TAG_KEY_SIZE, + HKS_TAG_DIGEST, + HKS_TAG_PADDING, + HKS_TAG_BLOCK_MODE, + HKS_TAG_KEY_TYPE, + HKS_TAG_ASSOCIATED_DATA, + HKS_TAG_NONCE, + HKS_TAG_IV, + + HKS_TAG_SALT, + HKS_TAG_PWD, + HKS_TAG_INFO, + HKS_TAG_ITERATION, + + HKS_TAG_KEY_GENERATE_TYPE, + HKS_TAG_DERIVE_MAIN_KEY, + HKS_TAG_DERIVE_FACTOR, + HKS_TAG_DERIVE_ALG, + HKS_TAG_AGREE_ALG, + HKS_TAG_AGREE_PUBLIC_KEY_IS_KEY_ALIAS, + HKS_TAG_AGREE_PRIVATE_KEY_ALIAS, + HKS_TAG_AGREE_PUBLIC_KEY, + HKS_TAG_KEY_ALIAS, + HKS_TAG_DERIVE_KEY_SIZE, + HKS_TAG_IMPORT_KEY_TYPE, + HKS_TAG_UNWRAP_ALGORITHM_SUITE, + HKS_TAG_DERIVE_AGREE_KEY_STORAGE_FLAG, + HKS_TAG_RSA_PSS_SALT_LEN_TYPE, + + HKS_TAG_ACTIVE_DATETIME, + HKS_TAG_ORIGINATION_EXPIRE_DATETIME, + HKS_TAG_USAGE_EXPIRE_DATETIME, + HKS_TAG_CREATION_DATETIME, + + HKS_TAG_ALL_USERS, + HKS_TAG_USER_ID, + HKS_TAG_NO_AUTH_REQUIRED, + HKS_TAG_USER_AUTH_TYPE, + HKS_TAG_AUTH_TIMEOUT, + HKS_TAG_AUTH_TOKEN, + + HKS_TAG_OS_VERSION, + HKS_TAG_OS_PATCHLEVEL, + + HKS_TAG_ATTESTATION_CHALLENGE, + HKS_TAG_ATTESTATION_APPLICATION_ID, + HKS_TAG_ATTESTATION_ID_BRAND, + HKS_TAG_ATTESTATION_ID_DEVICE, + HKS_TAG_ATTESTATION_ID_PRODUCT, + HKS_TAG_ATTESTATION_ID_SERIAL, + HKS_TAG_ATTESTATION_ID_IMEI, + HKS_TAG_ATTESTATION_ID_MEID, + HKS_TAG_ATTESTATION_ID_MANUFACTURER, + HKS_TAG_ATTESTATION_ID_MODEL, + HKS_TAG_ATTESTATION_ID_ALIAS, + HKS_TAG_ATTESTATION_ID_SOCID, + HKS_TAG_ATTESTATION_ID_UDID, + HKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO, + HKS_TAG_ATTESTATION_ID_VERSION_INFO, + HKS_TAG_ATTESTATION_BASE64, + + HKS_TAG_IS_KEY_ALIAS, + HKS_TAG_KEY_STORAGE_FLAG, + HKS_TAG_IS_ALLOWED_WRAP, + HKS_TAG_KEY_WRAP_TYPE, + HKS_TAG_KEY_AUTH_ID, + HKS_TAG_KEY_ROLE, + HKS_TAG_KEY_FLAG, + HKS_TAG_KEY_DOMAIN, + + HKS_TAG_KEY_AUTH_ACCESS_TYPE, + HKS_TAG_KEY_SECURE_SIGN_TYPE, + HKS_TAG_CHALLENGE_TYPE, + HKS_TAG_CHALLENGE_POS, + HKS_TAG_KEY_AUTH_PURPOSE, + + HKS_TAG_KEY_INIT_CHALLENGE, + HKS_TAG_IS_USER_AUTH_ACCESS, + HKS_TAG_USER_AUTH_CHALLENGE, + HKS_TAG_USER_AUTH_ENROLL_ID_INFO, + HKS_TAG_USER_AUTH_SECURE_UID, + HKS_TAG_KEY_AUTH_RESULT, + HKS_TAG_IF_NEED_APPEND_AUTH_INFO, + HKS_TAG_VERIFIED_AUTH_TOKEN, + HKS_TAG_IS_APPEND_UPDATE_DATA, + + HKS_TAG_PROCESS_NAME, + HKS_TAG_PACKAGE_NAME, + HKS_TAG_PAYLOAD_LEN, + HKS_TAG_AE_TAG, + HKS_TAG_CRYPTO_CTX, + HKS_TAG_KEY, + HKS_TAG_KEY_VERSION, + HKS_TAG_IS_KEY_HANDLE, + HKS_TAG_SYMMETRIC_KEY_DATA, + HKS_TAG_ASYMMETRIC_PUBLIC_KEY_DATA, + HKS_TAG_ASYMMETRIC_PRIVATE_KEY_DATA, + HKS_TAG_KEY_ACCESS_TIME, + +}; + +HKS_API_EXPORT enum HksTagType GetTagType(enum HksTag tag) +{ + return (enum HksTagType)((uint32_t)tag & (uint32_t)HKS_TAG_TYPE_MASK); +} + +static bool IsValidTag(uint32_t tag) +{ + uint32_t tagSize = (sizeof(g_validTags)) / (sizeof((g_validTags)[0])); + for (uint32_t i = 0; i < tagSize; ++i) { + if (tag == g_validTags[i]) { + return true; + } + } + return false; +} + +HKS_API_EXPORT int32_t HksCheckParamSetTag(const struct HksParamSet *paramSet) +{ + HKS_IF_NULL_RETURN(paramSet, HKS_ERROR_NULL_POINTER) + + for (uint32_t i = 0; i < paramSet->paramsCnt; ++i) { + uint32_t curTag = paramSet->params[i].tag; + if (!IsValidTag(curTag)) { + HKS_LOG_E("paramSet contains invalid tag! 0x%" LOG_PUBLIC "x", curTag); + return HKS_ERROR_INVALID_ARGUMENT; + } + + for (uint32_t j = i + 1; j < paramSet->paramsCnt; ++j) { + if (curTag == paramSet->params[j].tag) { + HKS_LOG_E("paramSet contains multi-tags! 0x%" LOG_PUBLIC "x", curTag); + return HKS_ERROR_INVALID_ARGUMENT; + } + } + } + + return HKS_SUCCESS; +} + +static int32_t CheckBeforeAddParams(const struct HksParamSet *paramSet, const struct HksParam *params, + uint32_t paramCnt) +{ + if ((params == NULL) || (paramSet == NULL) || (paramSet->paramSetSize > HKS_PARAM_SET_MAX_SIZE) || + (paramCnt > HKS_DEFAULT_PARAM_CNT) || (paramSet->paramsCnt > (HKS_DEFAULT_PARAM_CNT - paramCnt))) { + HKS_LOG_E("invalid params or paramset!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + + for (uint32_t i = 0; i < paramCnt; i++) { + if ((GetTagType((enum HksTag)(params[i].tag)) == HKS_TAG_TYPE_BYTES) && + (params[i].blob.data == NULL)) { + HKS_LOG_E("invalid blob param!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + } + return HKS_SUCCESS; +} + +static int32_t BuildParamSet(struct HksParamSet **paramSet) +{ + struct HksParamSet *freshParamSet = *paramSet; + uint32_t size = freshParamSet->paramSetSize; + uint32_t offset = sizeof(struct HksParamSet) + sizeof(struct HksParam) * freshParamSet->paramsCnt; + + if (size > HKS_DEFAULT_PARAM_SET_SIZE) { + freshParamSet = (struct HksParamSet *)HksMalloc(size); + HKS_IF_NULL_LOGE_RETURN(freshParamSet, HKS_ERROR_MALLOC_FAIL, "malloc params failed!") + + if (memcpy_s(freshParamSet, size, *paramSet, offset) != EOK) { + HKS_FREE_PTR(freshParamSet); + HKS_LOG_E("copy params failed!"); + return HKS_ERROR_INSUFFICIENT_MEMORY; + } + HKS_FREE_PTR(*paramSet); + *paramSet = freshParamSet; + } + + return HksFreshParamSet(freshParamSet, true); +} + +HKS_API_EXPORT int32_t HksFreshParamSet(struct HksParamSet *paramSet, bool isCopy) +{ + HKS_IF_NULL_LOGE_RETURN(paramSet, HKS_ERROR_NULL_POINTER, "invalid NULL paramSet") + + int32_t ret = HksCheckParamSet(paramSet, paramSet->paramSetSize); + HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "invalid fresh paramSet") + + uint32_t size = paramSet->paramSetSize; + uint32_t offset = sizeof(struct HksParamSet) + sizeof(struct HksParam) * paramSet->paramsCnt; + + for (uint32_t i = 0; i < paramSet->paramsCnt; i++) { + if (offset > size) { + HKS_LOG_E("invalid param set offset!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + if (GetTagType((enum HksTag)(paramSet->params[i].tag)) == HKS_TAG_TYPE_BYTES) { + if (IsAdditionOverflow(offset, paramSet->params[i].blob.size)) { + HKS_LOG_E("blob size overflow!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + + if (isCopy && (memcpy_s((uint8_t *)paramSet + offset, size - offset, + paramSet->params[i].blob.data, paramSet->params[i].blob.size) != EOK)) { + HKS_LOG_E("copy param blob failed!"); + return HKS_ERROR_INSUFFICIENT_MEMORY; + } + paramSet->params[i].blob.data = (uint8_t *)paramSet + offset; + offset += paramSet->params[i].blob.size; + } + } + + if (paramSet->paramSetSize != offset) { + HKS_LOG_E("invalid param set size!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + return HKS_SUCCESS; +} + +HKS_API_EXPORT int32_t HksCheckParamSet(const struct HksParamSet *paramSet, uint32_t size) +{ + HKS_IF_NULL_RETURN(paramSet, HKS_ERROR_NULL_POINTER) + + if ((size < sizeof(struct HksParamSet)) || (size > HKS_PARAM_SET_MAX_SIZE) || + (paramSet->paramSetSize != size) || + (paramSet->paramsCnt > ((size - sizeof(struct HksParamSet)) / sizeof(struct HksParam)))) { + HKS_LOG_E("invalid param set!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + return HKS_SUCCESS; +} + +HKS_API_EXPORT int32_t HksInitParamSet(struct HksParamSet **paramSet) +{ + HKS_IF_NULL_LOGE_RETURN(paramSet, HKS_ERROR_NULL_POINTER, "invalid init params!") + + *paramSet = (struct HksParamSet *)HksMalloc(HKS_DEFAULT_PARAM_SET_SIZE); + HKS_IF_NULL_LOGE_RETURN(*paramSet, HKS_ERROR_MALLOC_FAIL, "malloc init param set failed!") + + (*paramSet)->paramsCnt = 0; + (*paramSet)->paramSetSize = sizeof(struct HksParamSet); + return HKS_SUCCESS; +} + +HKS_API_EXPORT int32_t HksAddParams(struct HksParamSet *paramSet, + const struct HksParam *params, uint32_t paramCnt) +{ + int32_t ret = CheckBeforeAddParams(paramSet, params, paramCnt); + HKS_IF_NOT_SUCC_RETURN(ret, ret) + + for (uint32_t i = 0; i < paramCnt; i++) { + paramSet->paramSetSize += sizeof(struct HksParam); + if (GetTagType((enum HksTag)(params[i].tag)) == HKS_TAG_TYPE_BYTES) { + if (IsAdditionOverflow(paramSet->paramSetSize, params[i].blob.size)) { + HKS_LOG_E("params size overflow!"); + paramSet->paramSetSize -= sizeof(struct HksParam); + return HKS_ERROR_INVALID_ARGUMENT; + } + paramSet->paramSetSize += params[i].blob.size; + } + (void)memcpy_s(¶mSet->params[paramSet->paramsCnt++], sizeof(struct HksParam), ¶ms[i], + sizeof(struct HksParam)); + } + return HKS_SUCCESS; +} + +HKS_API_EXPORT int32_t HksBuildParamSet(struct HksParamSet **paramSet) +{ + if ((paramSet == NULL) || (*paramSet == NULL)) { + return HKS_ERROR_NULL_POINTER; + } + + int ret = HksCheckParamSet(*paramSet, (*paramSet)->paramSetSize); + HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "invalid build params!") + + return BuildParamSet(paramSet); +} + +HKS_API_EXPORT void HksFreeParamSet(struct HksParamSet **paramSet) +{ + if (paramSet == NULL) { + HKS_LOG_E("invalid free paramset!"); + return; + } + HKS_FREE_PTR(*paramSet); +} + +static int32_t FreshParamSet(struct HksParamSet *paramSet, bool isCopy) { + uint32_t size = paramSet->paramSetSize; + uint32_t offset = sizeof(struct HksParamSet) + sizeof(struct HksParam) * paramSet->paramsCnt; + + for (uint32_t i = 0; i < paramSet->paramsCnt; i++) { + if (offset > size) { + HKS_LOG_E("invalid param set offset!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + if (GetTagType((enum HksTag)(paramSet->params[i].tag)) == HKS_TAG_TYPE_BYTES) { + if (IsAdditionOverflow(offset, paramSet->params[i].blob.size)) { + HKS_LOG_E("blob size overflow!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + if (isCopy && memcpy_s((uint8_t *)paramSet + offset, size - offset, + paramSet->params[i].blob.data, paramSet->params[i].blob.size) != EOK) { + HKS_LOG_E("copy param blob failed!"); + return HKS_ERROR_INSUFFICIENT_MEMORY; + } + paramSet->params[i].blob.data = (uint8_t *)paramSet + offset; + offset += paramSet->params[i].blob.size; + } + } + + if (paramSet->paramSetSize != offset) { + HKS_LOG_E("invalid param set size!"); + return HKS_ERROR_INVALID_ARGUMENT; + } return HKS_SUCCESS; } -int32_t HksBuildParamSet(struct HksParamSet **paramSet) + +HKS_API_EXPORT int32_t HksGetParam(const struct HksParamSet *paramSet, uint32_t tag, struct HksParam **param) +{ + if ((paramSet == NULL) || (param == NULL)) { + HKS_LOG_E("invalid params!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + + HKS_IF_NOT_SUCC_LOGE_RETURN(HksCheckParamSet(paramSet, paramSet->paramSetSize), + HKS_ERROR_INVALID_ARGUMENT, "invalid paramSet!") + + for (uint32_t i = 0; i < paramSet->paramsCnt; i++) { + if (tag == paramSet->params[i].tag) { + *param = (struct HksParam *)¶mSet->params[i]; + return HKS_SUCCESS; + } + } + + return HKS_ERROR_PARAM_NOT_EXIST; +} + +HKS_API_EXPORT int32_t HksGetParamSet(const struct HksParamSet *inParamSet, + uint32_t inParamSetSize, struct HksParamSet **outParamSet) { + int32_t ret = HksCheckParamSet(inParamSet, inParamSetSize); + HKS_IF_NOT_SUCC_RETURN(ret, ret) + + HKS_IF_NULL_RETURN(outParamSet, HKS_ERROR_NULL_POINTER) + + uint32_t size = inParamSet->paramSetSize; + struct HksParamSet *buf = (struct HksParamSet *)HksMalloc(size); + HKS_IF_NULL_LOGE_RETURN(buf, HKS_ERROR_MALLOC_FAIL, "malloc from param set failed!") + + (void)memcpy_s(buf, size, inParamSet, size); + + ret = FreshParamSet(buf, false); + if (ret != HKS_SUCCESS) { + HKS_FREE_PTR(buf); + return ret; + } + *outParamSet = buf; return HKS_SUCCESS; } -void HksFreeParamSet(struct HksParamSet **paramSet) + +HKS_API_EXPORT int32_t HksCheckParamMatch(const struct HksParam *baseParam, const struct HksParam *param) { + if (baseParam == NULL || param == NULL) { + return HKS_ERROR_NULL_POINTER; + } + if (baseParam->tag != param->tag) { + HKS_LOG_E("unmatch param type!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + + switch (GetTagType((enum HksTag)(baseParam->tag))) { + case HKS_TAG_TYPE_INT: + return (baseParam->int32Param == param->int32Param) ? HKS_SUCCESS : HKS_ERROR_INVALID_ARGUMENT; + case HKS_TAG_TYPE_UINT: + return (baseParam->uint32Param == param->uint32Param) ? HKS_SUCCESS : HKS_ERROR_INVALID_ARGUMENT; + case HKS_TAG_TYPE_ULONG: + return (baseParam->uint64Param == param->uint64Param) ? HKS_SUCCESS : HKS_ERROR_INVALID_ARGUMENT; + case HKS_TAG_TYPE_BOOL: + return (baseParam->boolParam == param->boolParam) ? HKS_SUCCESS : HKS_ERROR_INVALID_ARGUMENT; + case HKS_TAG_TYPE_BYTES: + if (baseParam->blob.size != param->blob.size || + baseParam->blob.data == NULL ||(param->blob.data == NULL)) { + HKS_LOG_E("unmatch byte type len!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + if (HksMemCmp(baseParam->blob.data, param->blob.data, baseParam->blob.size)) { + HKS_LOG_E("unmatch byte type content!"); + return HKS_ERROR_INVALID_ARGUMENT; + } + return HKS_SUCCESS; + default: + HKS_LOG_E("invalid tag type:%" LOG_PUBLIC "x", GetTagType((enum HksTag)(baseParam->tag))); + return HKS_ERROR_INVALID_ARGUMENT; + } } + +HKS_API_EXPORT int32_t HksCheckIsTagAlreadyExist(const struct HksParam *params, uint32_t paramsCnt, + const struct HksParamSet *targetParamSet) +{ + if (params == NULL || targetParamSet == NULL) { + return HKS_ERROR_NULL_POINTER; + } + + int32_t ret = HksCheckParamSet(targetParamSet, targetParamSet->paramSetSize); + HKS_IF_NOT_SUCC_RETURN(ret, ret) + + for (uint32_t i = 0; i < targetParamSet->paramsCnt; ++i) { + for (uint32_t j = 0; j < paramsCnt; ++j) { + if (params[j].tag == targetParamSet->params[i].tag) { + return HKS_ERROR_INVALID_ARGUMENT; + } + } + } + + return HKS_SUCCESS; +} + +HKS_API_EXPORT int32_t HksDeleteTagsFromParamSet(const uint32_t *tag, uint32_t tagCount, + const struct HksParamSet *paramSet, struct HksParamSet **outParamSet) +{ + if (tag == NULL || paramSet == NULL || outParamSet == NULL) { + return HKS_ERROR_NULL_POINTER; + } + int32_t ret = HksFreshParamSet((struct HksParamSet *)paramSet, false); + HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "fresh paramset failed") + + struct HksParamSet *newParamSet = NULL; + ret = HksInitParamSet(&newParamSet); + HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "init param set failed") + + for (uint32_t i = 0; i < paramSet->paramsCnt; ++i) { + bool isDeleteTag = false; + for (uint32_t j = 0; j < tagCount; ++j) { + if (paramSet->params[i].tag == tag[j]) { + isDeleteTag = true; + break; + } + } + if (!isDeleteTag) { + ret = HksAddParams(newParamSet, ¶mSet->params[i], 1); + if (ret != HKS_SUCCESS) { + HksFreeParamSet(&newParamSet); + return ret; + } + } + } + + ret = HksBuildParamSet(&newParamSet); + if (ret != HKS_SUCCESS) { + HksFreeParamSet(&newParamSet); + return ret; + } + + *outParamSet = newParamSet; + return HKS_SUCCESS; +} + int32_t HksInit(const struct HksBlob *keyAlias, const struct HksParamSet *paramSet, struct HksBlob *handle, struct HksBlob *token) { @@ -41,8 +506,8 @@ int32_t HksUpdate(const struct HksBlob *handle, const struct HksParamSet *paramS const struct HksBlob *inData, struct HksBlob *outData) { size_t size = std::min(outData->size, inData->size); - (void)memcpy_s(outData->data, outData->size, inData->data, size); outData->size = size; + (void)memcpy_s(outData->data, outData->size, inData->data, size); return HKS_SUCCESS; } @@ -63,32 +528,51 @@ void HksFree(void *ptr) } -int32_t HksGetParamSet(const struct HksParamSet *fromParamSet, uint32_t fromParamSetSize, struct HksParamSet **paramSet) -{ - return 0; -} -int32_t HksGetParam(const struct HksParamSet *paramSet, uint32_t tag, struct HksParam **param) +int32_t HksLocalGenerateKey(const struct HksParamSet *paramSetIn, struct HksParamSet *paramSetOut) { + paramSetOut->paramSetSize = paramSetIn->paramSetSize; + paramSetOut->paramsCnt = paramSetIn->paramsCnt; +// (void)memcpy_s(paramSetIn->params, paramSetIn->paramSetSize, paramSetOut->params, paramSetOut->paramSetSize); + HksMemCmp(paramSetIn->params, paramSetOut->params, paramSetOut->paramSetSize); return 0; } -int32_t HksFreshParamSet(struct HksParamSet *paramSet, bool isCopy) -{ - return 0; -} -int32_t HksCheckParamSetTag(const struct HksParamSet *paramSet) -{ - return 0; -} -int32_t HksCheckParamSet(const struct HksParamSet *paramSet, uint32_t size) + +int32_t HksClientGenerateKey(const struct HksBlob *keyAlias, const struct HksParamSet *paramSetIn, struct HksParamSet *paramSetOut) { + std::string key((char *)keyAlias->data); + KEYS.insert(key); + if (paramSetOut == nullptr) { + return 0; + } + paramSetOut->paramSetSize = paramSetIn->paramSetSize; + paramSetOut->paramsCnt = paramSetIn->paramsCnt; + HksMemCmp(paramSetIn->params, paramSetOut->params, paramSetOut->paramSetSize); return 0; } -int32_t HksCheckParamMatch(const struct HksParam *baseParam, const struct HksParam *param) + +int32_t HksGenerateKey(const struct HksBlob *keyAlias, const struct HksParamSet *paramSetIn, + struct HksParamSet *paramSetOut) { - return 0; + HKS_LOG_I("enter generate key"); + struct HksParam *storageFlag = NULL; + int32_t ret = HksGetParam(paramSetIn, HKS_TAG_KEY_STORAGE_FLAG, &storageFlag); + if ((ret == HKS_SUCCESS) && (storageFlag->uint32Param == HKS_STORAGE_TEMP)) { + if ((paramSetIn == NULL) || (paramSetOut == NULL)) { + return HKS_ERROR_NULL_POINTER; + } + ret = HksLocalGenerateKey(paramSetIn, paramSetOut); + HKS_LOG_I("leave generate temp key, result = %" LOG_PUBLIC "d", ret); + return ret; + } + + /* generate persistent keys */ + if ((paramSetIn == NULL) || (keyAlias == NULL)) { + return HKS_ERROR_NULL_POINTER; + } + ret = HksClientGenerateKey(keyAlias, paramSetIn, paramSetOut); + HKS_LOG_I("leave generate persistent key, result = %" LOG_PUBLIC "d", ret); + return ret; } -int32_t HksGenerateKey(const struct HksBlob *keyAlias, - const struct HksParamSet *paramSetIn, struct HksParamSet *paramSetOut) { return 0; } int32_t HksGetSdkVersion(struct HksBlob *sdkVersion) { return 0; @@ -120,7 +604,8 @@ int32_t HksGetKeyParamSet(const struct HksBlob *keyAlias, const struct HksParamS } int32_t HksKeyExist(const struct HksBlob *keyAlias, const struct HksParamSet *paramSet) { - return 0; + std::string key((char *)keyAlias->data); + return KEYS.find(key) != KEYS.end() ? 0 : HKS_ERROR_NOT_EXIST; } int32_t HksGenerateRandom(const struct HksParamSet *paramSet, struct HksBlob *random) { @@ -139,23 +624,27 @@ int32_t HksVerify(const struct HksBlob *key, const struct HksParamSet *paramSet, int32_t HksEncrypt(const struct HksBlob *key, const struct HksParamSet *paramSet, const struct HksBlob *plainText, struct HksBlob *cipherText) { - if(plainText->size == 0) { + if (plainText->size == 0) { return HKS_ERROR_INVALID_ARGUMENT; } (void)memcpy_s(cipherText->data, cipherText->size, plainText->data, plainText->size); // cipherText->size = plainText->size; cipherText->size = 48; + cipherText->data[cipherText->size - 1] = 66; return 0; } int32_t HksDecrypt(const struct HksBlob *key, const struct HksParamSet *paramSet, const struct HksBlob *cipherText, struct HksBlob *plainText) { - if(cipherText->size == 0) { + if (cipherText->size == 0) { return HKS_ERROR_INVALID_ARGUMENT; } - (void)memcpy_s(plainText->data, plainText->size, cipherText->data, cipherText->size); - // plainText->size = cipherText->size; plainText->size = 32; + if (cipherText->data[cipherText->size - 1] != 66) { + return HKS_ERROR_INVALID_ARGUMENT; + } + (void)memcpy_s(plainText->data, plainText->size, cipherText->data, plainText->size); + // plainText->size = cipherText->size; return 0; } int32_t HksAgreeKey(const struct HksParamSet *paramSet, const struct HksBlob *privateKey, diff --git a/mock/src/mock_ipc.cpp b/mock/src/mock_ipc.cpp index 38a2cd7a85f833c0d7bb07b288cf0093cd623044..5c8f16aabd979c4897b603ec039e9b9f12845143 100644 --- a/mock/src/mock_ipc.cpp +++ b/mock/src/mock_ipc.cpp @@ -26,33 +26,88 @@ namespace OHOS { BrokerRegistration &BrokerRegistration::Get() { - static OHOS::BrokerRegistration brokerRegistration; - return brokerRegistration; -}; + static BrokerRegistration instance; + return instance; +} -bool BrokerRegistration::Register(const std::u16string &descriptor, const BrokerRegistration::Constructor &creator) +BrokerRegistration::~BrokerRegistration() { - creators_[descriptor] = creator; - return true; + isUnloading = true; + std::lock_guard lockGuard(creatorMutex_); + for (auto it = creators_.begin(); it != creators_.end();) { + it = creators_.erase(it); + } + for (auto it1 = objects_.begin(); it1 != objects_.end();) { + BrokerDelegatorBase *object = reinterpret_cast(*it1); + object->isSoUnloaded = true; + it1 = objects_.erase(it1); + } +} + +bool BrokerRegistration::Register(const std::u16string &descriptor, const Constructor &creator, + const BrokerDelegatorBase *object) +{ + if (descriptor.empty()) { + return false; + } + + std::lock_guard lockGuard(creatorMutex_); + auto it = creators_.find(descriptor); + bool ret = false; + if (it == creators_.end()) { + ret = creators_.insert({ descriptor, creator }).second; + } + auto it1 = std::find_if(objects_.begin(), objects_.end(), [descriptor](uintptr_t id) { + const BrokerDelegatorBase *object = reinterpret_cast(id); + return object->descriptor_ == descriptor; + }); + if (it1 == objects_.end()) { + objects_.push_back(reinterpret_cast(object)); + } + return ret; } void BrokerRegistration::Unregister(const std::u16string &descriptor) { - creators_.erase(descriptor); + if (isUnloading) { +// ZLOGE(LABEL, "BrokerRegistration is Unloading"); + return; + } + std::lock_guard lockGuard(creatorMutex_); + if (!descriptor.empty()) { + auto it = creators_.find(descriptor); + if (it != creators_.end()) { + creators_.erase(it); + } + auto it1 = std::find_if(objects_.begin(), objects_.end(), [descriptor](uintptr_t id) { + const BrokerDelegatorBase *object = reinterpret_cast(id); + return object->descriptor_ == descriptor; + }); + if (it1 != objects_.end()) { + objects_.erase(it1); + } + } } sptr BrokerRegistration::NewInstance(const std::u16string &descriptor, const sptr &object) { - if (object == nullptr) { - return nullptr; - } - if (creators_.find(descriptor) == creators_.end()) { - return nullptr; + std::lock_guard lockGuard(creatorMutex_); + + sptr broker; + if (object != nullptr) { + auto it = creators_.find(descriptor); + if (it != creators_.end()) { + broker = it->second(object); + } +// if (object->IsProxyObject()) { +// +// } else { +// broker = object->AsInterface().GetRefPtr(); +// } } - return creators_[descriptor](object); + return broker; } -BrokerRegistration::~BrokerRegistration() {} PeerHolder::PeerHolder(const sptr &object) : remoteObject_(object) {}; sptr PeerHolder::Remote() { return remoteObject_; } diff --git a/mock/src/mock_ipc_object_stub.cpp b/mock/src/mock_ipc_object_stub.cpp index 96152970017a315ccfdc1a0c3f070a8409e5d8bd..99cd67e1ca5e1beb4ef5ce40bbcaadf9076ff8a8 100644 --- a/mock/src/mock_ipc_object_stub.cpp +++ b/mock/src/mock_ipc_object_stub.cpp @@ -83,30 +83,10 @@ int32_t IPCObjectStub::InvokerDataBusThread(MessageParcel &data, MessageParcel & { return 0; } -int32_t IPCObjectStub::IncStubRefs(MessageParcel &data, MessageParcel &reply) -{ - return 0; -} -int32_t IPCObjectStub::DecStubRefs(MessageParcel &data, MessageParcel &reply) -{ - return 0; -} int32_t IPCObjectStub::AddAuthInfo(MessageParcel &data, MessageParcel &reply, uint32_t code) { return 0; } -int32_t IPCObjectStub::GrantDataBusName(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) -{ - return 0; -} -std::string IPCObjectStub::CreateDatabusName(int uid, int pid) -{ - return std::string(); -} -std::string IPCObjectStub::GetDataBusName() -{ - return std::string(); -} bool IPCObjectStub::IsDeviceIdIllegal(const std::string &deviceID) { return false; diff --git a/mock/src/mock_js_runtime.cpp b/mock/src/mock_js_runtime.cpp index d64fc248b9a5af614e41811e3d8050aac8374a5b..c24b8f8714a542668ae9eda990a038d2d5eca67e 100644 --- a/mock/src/mock_js_runtime.cpp +++ b/mock/src/mock_js_runtime.cpp @@ -15,6 +15,7 @@ #include "js_runtime.h" #include "js_runtime_utils.h" #include "js_extension_context.h" +#include "extra_params.h" namespace OHOS::AbilityRuntime { HandleScope::HandleScope(JsRuntime& jsRuntime) {} HandleScope::HandleScope(NativeEngine &engine) {} @@ -27,8 +28,64 @@ NativeValue* HandleEscape::Escape(NativeValue* value) { return value; } std::unique_ptr JsRuntime::Create(const Options& options) { class JsRuntimeInner : public JsRuntime { public: - bool RunScript(const std::string &path) override { return false; } - void StartDebugMode(bool needBreakPoint, int32_t instanceId) override {} +// bool RunScript(const std::string &path) override { return false; } +// void StartDebugMode(bool needBreakPoint, int32_t instanceId) override {} + Language GetLanguage() const override + { + return JsRuntime::GetLanguage(); + } + void DumpHeapSnapshot(bool isPrivate) override + { + JsRuntime::DumpHeapSnapshot(isPrivate); + } + void NotifyApplicationState(bool isBackground) override + { + JsRuntime::NotifyApplicationState(isBackground); + } + void StartDebugMode(bool needBreakPoint) override + { + JsRuntime::StartDebugMode(needBreakPoint); + } + void PreloadSystemModule(const string &moduleName) override + { + JsRuntime::PreloadSystemModule(moduleName); + } + void FinishPreload() override + { + JsRuntime::FinishPreload(); + } + bool LoadRepairPatch(const string &patchFile, const string &baseFile) override + { + return JsRuntime::LoadRepairPatch(patchFile, baseFile); + } + bool NotifyHotReloadPage() override + { + return JsRuntime::NotifyHotReloadPage(); + } + bool UnLoadRepairPatch(const string &patchFile) override + { + return JsRuntime::UnLoadRepairPatch(patchFile); + } + void UpdateExtensionType(int32_t extensionType) override + { + JsRuntime::UpdateExtensionType(extensionType); + } + void RegisterQuickFixQueryFunc(const std::map &moduleAndPath) override + { + JsRuntime::RegisterQuickFixQueryFunc(moduleAndPath); + } + ~JsRuntimeInner() override = default; + + protected: + bool Initialize(const Options &options) override + { + return JsRuntime::Initialize(options); + } + NativeValue *LoadJsBundle(const string &path) override + { + return JsRuntime::LoadJsBundle(path); + } + protected: NativeValue *LoadJsModule(const std::string &path) override { return nullptr;} }; @@ -42,7 +99,7 @@ std::unique_ptr JsRuntime::LoadSystemModuleByEngine(NativeEngin return std::unique_ptr(); } std::unique_ptr JsRuntime::LoadModule(const std::string &moduleName, const std::string &modulePath, - bool esmodule) + const std::string &hapPath, bool esmodule, bool useCommonChunk) { return std::unique_ptr(); } @@ -54,12 +111,29 @@ std::unique_ptr JsRuntime::LoadSystemModule(const std::string & void JsRuntime::PostTask(const std::function &task, const std::string &name, int64_t delayTime) {} void JsRuntime::RemoveTask(const std::string &name) {} void JsRuntime::DumpHeapSnapshot(bool isPrivate) {} -std::string JsRuntime::BuildJsStackTrace() { return ""; } void JsRuntime::NotifyApplicationState(bool isBackground) {} -bool JsRuntime::RunSandboxScript(const std::string &path) { return false; } +//bool JsRuntime::RunSandboxScript(const std::string &path) { return false; } bool JsRuntime::Initialize(const Runtime::Options &options) { return false; } void JsRuntime::Deinitialize() {} NativeValue *JsRuntime::LoadJsBundle(const std::string &path) { return nullptr;} +void JsRuntime::StartDebugMode(bool needBreakPoint) {} +void JsRuntime::PreloadSystemModule(const std::string &moduleName) {} +void JsRuntime::FinishPreload() {} +bool JsRuntime::LoadRepairPatch(const std::string &patchFile, const std::string &baseFile) +{ + return false; +} +bool JsRuntime::NotifyHotReloadPage() +{ + return false; +} +bool JsRuntime::UnLoadRepairPatch(const std::string &patchFile) +{ + return false; +} +void JsRuntime::UpdateExtensionType(int32_t extensionType) {} +void JsRuntime::RegisterQuickFixQueryFunc(const std::map& moduleAndPath) {} + NativeValue* CreateJsExtensionContext(NativeEngine& engine, const std::shared_ptr& context, std::shared_ptr abilityInfo, DetachCallback detach, AttachCallback attach) { return nullptr; } diff --git a/preferences/frameworks/js/napi/preferences/BUILD.gn b/preferences/frameworks/js/napi/preferences/BUILD.gn index c102cf43afd5d39433a5aaf8fccbfcf02c22ac22..f63e09789bff7b6aacfafc3f90ee08a13ddd7fc1 100644 --- a/preferences/frameworks/js/napi/preferences/BUILD.gn +++ b/preferences/frameworks/js/napi/preferences/BUILD.gn @@ -46,6 +46,7 @@ if (!is_mingw && !is_mac) { external_deps = [ "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", + "common_event_service:cesfwk_innerkits", "hilog_native:libhilog", "napi:ace_napi", "preferences:native_preferences", diff --git a/preferences/frameworks/js/napi/preferences/src/napi_preferences.cpp b/preferences/frameworks/js/napi/preferences/src/napi_preferences.cpp index 5918a8826378b5b770d2a9cd8bf71766b13069d9..9da824be09e5103fcecffbf2feec9045f495ee5b 100644 --- a/preferences/frameworks/js/napi/preferences/src/napi_preferences.cpp +++ b/preferences/frameworks/js/napi/preferences/src/napi_preferences.cpp @@ -115,7 +115,7 @@ napi_status PreferencesProxy::NewInstance( LOG_ERROR("PreferencesProxy::NewInstance unwarp native preferences is null"); return napi_generic_failure; } - proxy->value_ = std::move(value); + proxy->value_ = value; return napi_ok; } @@ -127,7 +127,11 @@ napi_value PreferencesProxy::New(napi_env env, napi_callback_info info) LOG_WARN("get this failed"); return nullptr; } - PreferencesProxy *obj = new PreferencesProxy(); + PreferencesProxy *obj = new (std::nothrow) PreferencesProxy(); + if (obj == nullptr) { + LOG_ERROR("PreferencesProxy::New new failed, obj is nullptr"); + return nullptr; + } obj->env_ = env; obj->uvQueue_ = std::make_shared(env); napi_status status = napi_wrap(env, thiz, obj, PreferencesProxy::Destructor, nullptr, nullptr); @@ -300,6 +304,9 @@ int ParseDefValue(const napi_env &env, const napi_value &jsVal, std::shared_ptr< } else if (valueType == napi_object) { if (ParseDefObject(env, jsVal, context) != E_OK) { LOG_ERROR("ParseDefValue::ParseDefObject failed"); + std::shared_ptr paramError = std::make_shared("value", "a ValueType."); + context->SetError(paramError); + return ERR; } } else { LOG_ERROR("ParseDefValue Wrong second parameter type"); diff --git a/preferences/frameworks/js/napi/storage/src/napi_storage.cpp b/preferences/frameworks/js/napi/storage/src/napi_storage.cpp index e0dffd71ce7f141909bec55279a11b319a9f5a4b..b7f082b79ffcc390596cd75a04eced6076a4af5d 100644 --- a/preferences/frameworks/js/napi/storage/src/napi_storage.cpp +++ b/preferences/frameworks/js/napi/storage/src/napi_storage.cpp @@ -131,7 +131,11 @@ napi_value StorageProxy::New(napi_env env, napi_callback_info info) napi_valuetype valueType = napi_undefined; NAPI_CALL(env, napi_typeof(env, args[0], &valueType)); NAPI_ASSERT(env, valueType == napi_string, "input type not string"); - char *path = new char[PATH_MAX]; + char *path = new (std::nothrow) char[PATH_MAX]; + if (path == nullptr) { + LOG_ERROR("StorageProxy::New new failed, path is nullptr"); + return nullptr; + } size_t pathLen = 0; napi_status status = napi_get_value_string_utf8(env, args[0], path, PATH_MAX, &pathLen); if (status != napi_ok) { @@ -145,7 +149,11 @@ napi_value StorageProxy::New(napi_env env, napi_callback_info info) OHOS::NativePreferences::PreferencesHelper::GetPreferences(path, errCode); delete[] path; NAPI_ASSERT(env, preference != nullptr, "failed to call native"); - StorageProxy *obj = new StorageProxy(preference); + StorageProxy *obj = new (std::nothrow) StorageProxy(preference); + if (obj == nullptr) { + LOG_ERROR("StorageProxy::New new failed, obj is nullptr"); + return nullptr; + } obj->env_ = env; obj->value_ = std::move(preference); obj->uvQueue_ = std::make_shared(env); @@ -221,7 +229,11 @@ napi_value StorageProxy::GetValueSync(napi_env env, napi_callback_info info) double result = obj->value_->GetDouble(key, value); NAPI_CALL(env, napi_create_double(env, result, &output)); // double } else if (valueType == napi_string) { - char *value = new char[MAX_VALUE_LENGTH]; + char *value = new (std::nothrow) char[MAX_VALUE_LENGTH]; + if (value == nullptr) { + LOG_ERROR("StorageProxy::GetValueSync new failed, value is nullptr"); + return nullptr; + } size_t valueSize = 0; napi_get_value_string_utf8(env, args[1], value, MAX_VALUE_LENGTH, &valueSize); // get value diff --git a/preferences/frameworks/js/napi/storage/src/napi_storage_helper.cpp b/preferences/frameworks/js/napi/storage/src/napi_storage_helper.cpp index fbc613fec4a8a98c7fed02878355fff85a3cdb8e..d7b85f29cc8306d8f240b91015587680e5d8f87f 100644 --- a/preferences/frameworks/js/napi/storage/src/napi_storage_helper.cpp +++ b/preferences/frameworks/js/napi/storage/src/napi_storage_helper.cpp @@ -57,7 +57,11 @@ int ParseString(const napi_env &env, const napi_value &value, std::shared_ptrpath = path; @@ -108,7 +112,11 @@ napi_status GetInputPath(napi_env env, napi_callback_info info, std::string &pat return napi_invalid_arg; } - char *path = new char[PATH_MAX]; + char *path = new (std::nothrow) char[PATH_MAX]; + if (path == nullptr) { + LOG_ERROR("GetInputPath new failed, path is nullptr"); + return napi_arraybuffer_expected; + } size_t pathLen = 0; ret = napi_get_value_string_utf8(env, args[0], path, PATH_MAX, &pathLen); pathString = path; diff --git a/preferences/frameworks/js/napi/system_storage/BUILD.gn b/preferences/frameworks/js/napi/system_storage/BUILD.gn index 0be50f750caaddca879531681d08b42842eda559..f284a4430f8291a255a17c8e777687ae41a1c27d 100644 --- a/preferences/frameworks/js/napi/system_storage/BUILD.gn +++ b/preferences/frameworks/js/napi/system_storage/BUILD.gn @@ -43,6 +43,7 @@ if (!is_mingw && !is_mac) { external_deps = [ "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", + "common_event_service:cesfwk_innerkits", "hilog_native:libhilog", "napi:ace_napi", "preferences:native_preferences", diff --git a/preferences/frameworks/js/napi/system_storage/src/napi_system_storage.cpp b/preferences/frameworks/js/napi/system_storage/src/napi_system_storage.cpp index e1f0f06c575d650e87799f2b2b9edc444d59d04a..1c11411d15696cca053d5bca2b61933c18421066 100644 --- a/preferences/frameworks/js/napi/system_storage/src/napi_system_storage.cpp +++ b/preferences/frameworks/js/napi/system_storage/src/napi_system_storage.cpp @@ -157,7 +157,11 @@ napi_value Operate(napi_env env, napi_callback_info info, const char *resource, NAPI_CALL(env, napi_typeof(env, argv[0], &valueType)); NAPI_ASSERT(env, valueType == napi_object, "Wrong argument type, object expected."); - AsyncContext *context = new AsyncContext(); + AsyncContext *context = new (std::nothrow) AsyncContext(); + if (context == nullptr) { + LOG_ERROR("Operate new failed, context is nullptr"); + return nullptr; + } context->prefName = GetPrefName(env); ParseString(env, argv[0], "key", parseStrFlag, context->key); diff --git a/preferences/frameworks/native/include/preferences_impl.h b/preferences/frameworks/native/include/preferences_impl.h index ead876e6b05e472db5b451770ca9f81f98822206..c286308c8ab5a119ab2f736c5ad288f3dc8c6a75 100644 --- a/preferences/frameworks/native/include/preferences_impl.h +++ b/preferences/frameworks/native/include/preferences_impl.h @@ -29,7 +29,6 @@ #include "preferences.h" #include "preferences_observer.h" #include "preferences_value.h" -#include "task_pool.h" namespace OHOS { namespace NativePreferences { @@ -168,12 +167,11 @@ private: int writeToDiskResult_; bool wasWritten_; - bool handled_; }; std::shared_ptr commitToMemory(); void notifyPreferencesObserver(const MemoryToDiskRequest &request); - void StartLoadFromDisk(); + bool StartLoadFromDisk(); int CheckKey(const std::string &key); int CheckStringValue(const std::string &value); @@ -203,12 +201,6 @@ private: const std::string filePath_; const std::string backupPath_; const std::string brokenPath_; - // Task pool - /* max threads of the task pool. */ - static constexpr int MAX_TP_THREADS = 10; - /* min threads of the task pool. */ - static constexpr int MIN_TP_THREADS = 1; - TaskPool taskPool_; }; } // End of namespace NativePreferences } // End of namespace OHOS diff --git a/preferences/frameworks/native/include/task_executor.h b/preferences/frameworks/native/include/task_executor.h new file mode 100644 index 0000000000000000000000000000000000000000..38b44a65884e4e569de68725c11fec6651426f0f --- /dev/null +++ b/preferences/frameworks/native/include/task_executor.h @@ -0,0 +1,35 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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 PREFERENCES_TASK_EXECUTOR_H +#define PREFERENCES_TASK_EXECUTOR_H +#include + +#include "task_scheduler.h" +namespace OHOS { +namespace NativePreferences { +class TaskExecutor { +public: + API_LOCAL static TaskExecutor &GetInstance(); + API_LOCAL bool Execute(TaskScheduler::Task &&task); + +private: + TaskExecutor(); + ~TaskExecutor(); + + std::shared_ptr pool_; +}; +} // namespace NativePreferences +} // namespace OHOS +#endif // PREFERENCES_TASK_EXECUTOR_H diff --git a/preferences/frameworks/native/include/task_scheduler.h b/preferences/frameworks/native/include/task_scheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..33eb71f32fc6d63701fbd7854627c0ac7b5072f4 --- /dev/null +++ b/preferences/frameworks/native/include/task_scheduler.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_PREFERENCES_FRAMEWORKS_COMMON_TASK_SCHEDULER_H +#define OHOS_PREFERENCES_FRAMEWORKS_COMMON_TASK_SCHEDULER_H +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "visibility.h" +namespace OHOS { +class API_LOCAL TaskScheduler { +public: + using TaskId = uint64_t; + using Time = std::chrono::steady_clock::time_point; + using Task = std::function; + inline static constexpr TaskId INVALID_TASK_ID = static_cast(0ULL); + TaskScheduler(const std::string &name) + { + capacity_ = std::numeric_limits::max(); + isRunning_ = true; + taskId_ = INVALID_TASK_ID; + thread_ = std::make_unique([this, name]() { + auto realName = std::string("task_queue_") + name; +#if defined(MAC_PLATFORM) + pthread_setname_np(realName.c_str()); +#else + pthread_setname_np(pthread_self(), realName.c_str()); +#endif + Loop(); + }); + } + + ~TaskScheduler() + { + isRunning_ = false; + { + std::unique_lock lock(mutex_); + indexes_.clear(); + tasks_.clear(); + } + At(std::chrono::steady_clock::now(), []() {}); + thread_->join(); + } + + // execute task at specific time + TaskId At(const Time &time, Task task) + { + std::unique_lock lock(mutex_); + if (tasks_.size() >= capacity_) { + return INVALID_TASK_ID; + } + auto taskId = GenTaskId(); + auto it = tasks_.insert({ time, std::pair{ task, taskId } }); + if (it == tasks_.begin()) { + condition_.notify_one(); + } + indexes_[taskId] = it; + return taskId; + } + + TaskId Execute(Task task) + { + return At(std::chrono::steady_clock::now(), std::move(task)); + } + +private: + using InnerTask = std::pair, uint64_t>; + void Loop() + { + while (isRunning_) { + std::function exec; + { + std::unique_lock lock(mutex_); + condition_.wait(lock, [this] { return !tasks_.empty(); }); + auto it = tasks_.begin(); + exec = it->second.first; + indexes_.erase(it->second.second); + tasks_.erase(it); + } + + if (exec) { + exec(); + } + } + } + + TaskId GenTaskId() + { + auto taskId = ++taskId_; + if (taskId == INVALID_TASK_ID) { + return ++taskId_; + } + return taskId; + } + + volatile bool isRunning_; + size_t capacity_; + std::multimap tasks_; + std::map indexes_; + std::mutex mutex_; + std::unique_ptr thread_; + std::condition_variable condition_; + std::atomic taskId_; +}; +} // namespace OHOS +#endif // OHOS_PREFERENCES_FRAMEWORKS_COMMON_TASK_SCHEDULER_H diff --git a/relational_store/frameworks/native/rdb/include/rdb_manager.h b/preferences/frameworks/native/include/visibility.h similarity index 58% rename from relational_store/frameworks/native/rdb/include/rdb_manager.h rename to preferences/frameworks/native/include/visibility.h index 07185fbb52ee75efe3abda6fa5944fb61f36f9c3..7c7726f4aae34aec74462562be9762c31fea7e43 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_manager.h +++ b/preferences/frameworks/native/include/visibility.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * 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 @@ -13,20 +13,14 @@ * limitations under the License. */ -#ifndef DISTRIBUTED_RDB_RDB_MANAGER_H -#define DISTRIBUTED_RDB_RDB_MANAGER_H +#ifndef OHOS_PREFERENCES_FRAMEWORKS_COMMON_VISIBILITY_H +#define OHOS_PREFERENCES_FRAMEWORKS_COMMON_VISIBILITY_H -#include -#include -#include - -#include "rdb_service.h" -#include "rdb_types.h" - -namespace OHOS::DistributedRdb { -class RdbManager { -public: - static std::shared_ptr GetRdbService(const RdbSyncerParam& param); -}; -} // namespace OHOS::DistributedRdb +#ifndef API_EXPORT +#define API_EXPORT __attribute__((visibility("default"))) #endif +#ifndef API_LOCAL +#define API_LOCAL __attribute__((visibility("hidden"))) +#endif + +#endif // OHOS_PREFERENCES_FRAMEWORKS_COMMON_VISIBILITY_H diff --git a/preferences/frameworks/native/src/preferences_helper.cpp b/preferences/frameworks/native/src/preferences_helper.cpp index 3c8e09923d7f8fee1eaa5f67338fc80276ee367a..a6624c5efd8446e491b2d418e2c3a74b7f62d297 100644 --- a/preferences/frameworks/native/src/preferences_helper.cpp +++ b/preferences/frameworks/native/src/preferences_helper.cpp @@ -108,6 +108,7 @@ std::shared_ptr PreferencesHelper::GetPreferences(const std::string std::shared_ptr pref = std::make_shared(filePath); errCode = pref->Init(); if (errCode != E_OK) { + LOG_ERROR("Preferences Init failed."); return nullptr; } prefsCache_.insert(make_pair(realPath, pref)); diff --git a/preferences/frameworks/native/src/preferences_impl.cpp b/preferences/frameworks/native/src/preferences_impl.cpp index 031669677f504da1b84b3f1fa12a8cedffb79bf4..70db5c7942f0c354b1788785fcf498921411828d 100644 --- a/preferences/frameworks/native/src/preferences_impl.cpp +++ b/preferences/frameworks/native/src/preferences_impl.cpp @@ -20,13 +20,15 @@ #include #include #include +#include +#include "adaptor.h" #include "logger.h" #include "preferences_errno.h" #include "preferences_xml_utils.h" #include "securec.h" - -#include "adaptor.h" +#include "task_executor.h" +#include "task_scheduler.h" namespace OHOS { namespace NativePreferences { @@ -48,7 +50,7 @@ static bool IsFileExist(const std::string &inputPath) PreferencesImpl::PreferencesImpl(const std::string &filePath) : loaded_(false), filePath_(filePath), backupPath_(MakeBackupPath(filePath_)), - brokenPath_(MakeBrokenPath(filePath_)), taskPool_(TaskPool(MAX_TP_THREADS, MIN_TP_THREADS)) + brokenPath_(MakeBrokenPath(filePath_)) { currentMemoryStateGeneration_ = 0; diskStateGeneration_ = 0; @@ -70,26 +72,24 @@ std::string PreferencesImpl::MakeBrokenPath(const std::string &prefPath) PreferencesImpl::~PreferencesImpl() { - taskPool_.Stop(); } int PreferencesImpl::Init() { - int errCode = taskPool_.Start(); - if (errCode != E_OK) { - return errCode; + if (!StartLoadFromDisk()) { + return E_ERROR; } - StartLoadFromDisk(); return E_OK; } -void PreferencesImpl::StartLoadFromDisk() +bool PreferencesImpl::StartLoadFromDisk() { { std::lock_guard lock(mutex_); loaded_ = false; } - taskPool_.Schedule(std::string("PreferencesImpl"), std::bind(&PreferencesImpl::LoadFromDisk, std::ref(*this))); + TaskScheduler::Task task = std::bind(PreferencesImpl::LoadFromDisk, std::ref(*this)); + return TaskExecutor::GetInstance().Execute(std::move(task)); } int PreferencesImpl::CheckKey(const std::string &key) @@ -144,12 +144,7 @@ void PreferencesImpl::AwaitLoadFile() void PreferencesImpl::WriteToDiskFile(std::shared_ptr mcr) { - bool fileExists = false; if (IsFileExist(filePath_)) { - fileExists = true; - } - - if (fileExists) { bool needWrite = CheckRequestValidForStateGeneration(*mcr); if (!needWrite) { mcr->SetDiskWriteResult(false, E_OK); @@ -227,7 +222,7 @@ std::map PreferencesImpl::GetAll() return map_; } -void ReadXmlArrayElement(Element element, std::map &prefMap) +void ReadXmlArrayElement(const Element &element, std::map &prefMap) { if (element.tag_.compare("doubleArray") == 0) { std::vector values; @@ -259,7 +254,7 @@ void ReadXmlArrayElement(Element element, std::map &prefMap, const std::string &prefPath) + const Element &element, std::map &prefMap, const std::string &prefPath) { if (element.tag_.compare("int") == 0) { std::stringstream ss; @@ -306,15 +301,14 @@ bool PreferencesImpl::ReadSettingXml( LOG_ERROR("ReadSettingXml:%{private}s failed!", filePath_.c_str()); return false; } - - for (auto it = settings.begin(); it != settings.end(); it++) { - Element element = *it; + + for (const auto &element : settings) { ReadXmlElement(element, prefMap, prefPath); } return true; } -void WriteXmlElement(Element &elem, PreferencesValue value, const std::string filePath) +void WriteXmlElement(Element &elem, const PreferencesValue &value, const std::string &filePath) { if (value.IsDoubleArray()) { elem.tag_ = std::string("doubleArray"); @@ -492,9 +486,9 @@ void PreferencesImpl::Flush() DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); std::shared_ptr request = commitToMemory(); request->isSyncRequest_ = false; - - taskPool_.Schedule( - std::string("PreferencesImpl"), std::bind(&PreferencesImpl::WriteToDiskFile, std::ref(*this), request)); + TaskScheduler::Task task = std::bind(&PreferencesImpl::WriteToDiskFile, std::ref(*this), request); + TaskExecutor::GetInstance().Execute(std::move(task)); + notifyPreferencesObserver(*request); } @@ -502,15 +496,11 @@ int PreferencesImpl::FlushSync() { std::shared_ptr request = commitToMemory(); request->isSyncRequest_ = true; - - taskPool_.Schedule( - std::string("PreferencesImpl"), std::bind(&PreferencesImpl::WriteToDiskFile, std::ref(*this), request)); std::unique_lock lock(request->reqMutex_); - request->reqCond_.wait(lock, [request] { return request->handled_; }); + WriteToDiskFile(request); if (request->wasWritten_) { LOG_DEBUG("%{private}s:%{public}" PRId64 " written", filePath_.c_str(), request->memoryStateGeneration_); } - notifyPreferencesObserver(*request); return request->writeToDiskResult_; } @@ -559,7 +549,6 @@ PreferencesImpl::MemoryToDiskRequest::MemoryToDiskRequest( preferencesObservers_ = preferencesObservers; memoryStateGeneration_ = memStataGeneration; isSyncRequest_ = false; - handled_ = false; wasWritten_ = false; writeToDiskResult_ = E_ERROR; } @@ -568,7 +557,6 @@ void PreferencesImpl::MemoryToDiskRequest::SetDiskWriteResult(bool wasWritten, i { writeToDiskResult_ = result; wasWritten_ = wasWritten; - handled_ = true; reqCond_.notify_one(); } } // End of namespace NativePreferences diff --git a/preferences/frameworks/native/src/task_executor.cpp b/preferences/frameworks/native/src/task_executor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bfb6a0709c3d7f2158ab5e977f5c0dc5df80ed6 --- /dev/null +++ b/preferences/frameworks/native/src/task_executor.cpp @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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 "task_executor.h" + +namespace OHOS { +namespace NativePreferences { +TaskExecutor &TaskExecutor::GetInstance() +{ + static TaskExecutor instance; + return instance; +} + +bool TaskExecutor::Execute(TaskScheduler::Task &&task) +{ + if (pool_ == nullptr) { + return false; + } + pool_->Execute(std::move(task)); + return true; +} + +TaskExecutor::TaskExecutor() +{ + pool_ = std::make_shared("preferences"); +} + +TaskExecutor::~TaskExecutor() +{ +} +} // namespace NativePreferences +} // namespace OHOS diff --git a/preferences/interfaces/inner_api/BUILD.gn b/preferences/interfaces/inner_api/BUILD.gn index 7ee913a53a1b3db9ceb97adf8e3ea6839e9ce293..1133cb2933c4b1bb644f97157ce078b319418216 100644 --- a/preferences/interfaces/inner_api/BUILD.gn +++ b/preferences/interfaces/inner_api/BUILD.gn @@ -21,7 +21,7 @@ config("native_preferences_config") { } config("native_preferences_public_config") { - visibility = [ "//foundation/distributeddatamgr/preferences:*" ] + visibility = [ ":*" ] include_dirs = [ "include" ] } @@ -35,8 +35,7 @@ base_sources = [ "${preferences_native_path}/src/preferences_observer.cpp", "${preferences_native_path}/src/preferences_value.cpp", "${preferences_native_path}/src/preferences_xml_utils.cpp", - "${preferences_native_path}/src/task_pool.cpp", - "${preferences_native_path}/src/task_queue.cpp", + "${preferences_native_path}/src/task_executor.cpp", ] ohos_shared_library("native_preferences") { diff --git a/preferences/test/native/unittest/preferences_test.cpp b/preferences/test/native/unittest/preferences_test.cpp index 3501bc33e6525d7d6343c35e121a610de3afd37a..83372c1db65c7b90baf4f080da772c8956319daf 100644 --- a/preferences/test/native/unittest/preferences_test.cpp +++ b/preferences/test/native/unittest/preferences_test.cpp @@ -84,7 +84,7 @@ void PreferencesTest::TearDown(void) /* clear all data after every case */ if (pref) { pref->Clear(); - pref->Flush(); + pref->FlushSync(); } } diff --git a/preferences/test/native/unittest/preferences_xml_utils_test.cpp b/preferences/test/native/unittest/preferences_xml_utils_test.cpp index 3ac9e14158e42982d5df4cdb65cedc1785649289..d7295127eb54b41c93b028fc9e2f3115edf4023b 100644 --- a/preferences/test/native/unittest/preferences_xml_utils_test.cpp +++ b/preferences/test/native/unittest/preferences_xml_utils_test.cpp @@ -103,7 +103,7 @@ HWTEST_F(PreferencesXmlUtilsTest, UnnormalReadSettingXml_001, TestSize.Level1) */ HWTEST_F(PreferencesXmlUtilsTest, StringNodeElementTest_001, TestSize.Level1) { - std::string file = "/data/test/test"; + std::string file = "/data/test/test01"; std::remove(file.c_str()); std::vector settings; @@ -131,7 +131,7 @@ HWTEST_F(PreferencesXmlUtilsTest, StringNodeElementTest_001, TestSize.Level1) */ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_001, TestSize.Level1) { - std::string file = "/data/test/test"; + std::string file = "/data/test/test02"; std::remove(file.c_str()); std::vector settings; @@ -170,7 +170,7 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_001, TestSize.Level1) */ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_002, TestSize.Level1) { - std::string file = "/data/test/test"; + std::string file = "/data/test/test03"; std::remove(file.c_str()); std::vector settings; @@ -210,7 +210,7 @@ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_002, TestSize.Level1) */ HWTEST_F(PreferencesXmlUtilsTest, ArrayNodeElementTest_003, TestSize.Level1) { - std::string file = "/data/test/test"; + std::string file = "/data/test/test04"; std::remove(file.c_str()); std::vector settings; diff --git a/relational_store/CMakeLists.txt b/relational_store/CMakeLists.txt index 559ae0fd2156681bf34978f03d191f67622fe10b..0b5c49a9818b6b0ea0d0fdcabbcb9d440c2b08dd 100644 --- a/relational_store/CMakeLists.txt +++ b/relational_store/CMakeLists.txt @@ -12,23 +12,28 @@ set(MOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../mock) set(KV_STORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../kv_store) add_definitions(-DNAPI_EXPERIMENTAL) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/appdatafwk/src relational_store_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/cloud_data/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/dataability/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb_data_ability_adapter/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb_data_share_adapter/src relational_store_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb_device_manager_adapter/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/common/src relational_store_src) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/dataability/src relational_store_src) -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/rdb/src relational_store_src) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/relationalstore/src relational_store_src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/cloud_data/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/common/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/dataability/include) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/rdb/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/js/napi/relationalstore/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/appdatafwk/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/cloud_data/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/dataability/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/rdb/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/rdb_data_ability_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/interfaces/inner_api/rdb_data_share_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb_data_share_adapter/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/frameworks/native/rdb_device_manager_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../datamgr_service/services/distributeddataservice/adapter/include/dfx) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../data_share/interfaces/inner_api/common/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../data_share/interfaces/inner_api/consumer/include) diff --git a/relational_store/bundle.json b/relational_store/bundle.json index baeb0a2ee5d7e3af38b22508758582fc5964c214..6b9df4d3c0078159d716b8b9c91076a088350a56 100644 --- a/relational_store/bundle.json +++ b/relational_store/bundle.json @@ -71,6 +71,7 @@ "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/dataability:native_dataability", "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb_data_share_adapter:rdb_data_share_adapter", "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb:native_rdb", + "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/cloud_data:cloud_data", "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/dataability:dataability", "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/rdb:rdb", "//foundation/distributeddatamgr/relational_store/frameworks/js/napi/rdb:napi_rdb", @@ -136,12 +137,23 @@ ], "header_base": "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/rdb_data_ability_adapter/include" } + }, + { + "name": "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/cloud_data:cloud_data", + "header": { + "header_files": [ + "cloud_manager.h", + "cloud_service.h" + ], + "header_base": "//foundation/distributeddatamgr/relational_store/interfaces/inner_api/cloud_data/include" + } } ], "test": [ "//foundation/distributeddatamgr/relational_store/test/js/dataability:unittest", - "//foundation/distributeddatamgr/relational_store/test/js/relationalstore/performance:performancetest", + "//foundation/distributeddatamgr/relational_store/test/js/rdb:performancetest", "//foundation/distributeddatamgr/relational_store/test/js/rdb:unittest", + "//foundation/distributeddatamgr/relational_store/test/js/relationalstore:performancetest", "//foundation/distributeddatamgr/relational_store/test/js/relationalstore:unittest", "//foundation/distributeddatamgr/relational_store/test/native/dataability:unittest", "//foundation/distributeddatamgr/relational_store/test/native/rdb:unittest", diff --git a/relational_store/frameworks/js/napi/cloud_data/BUILD.gn b/relational_store/frameworks/js/napi/cloud_data/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..fdd30566cee10fe872125c436425065d3282118d --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# 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. +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +ohos_copy("relational_store_declaration") { + sources = [ "./api" ] + outputs = [ target_out_dir + "/$target_name/" ] + module_source_dir = target_out_dir + "/$target_name" + module_install_name = "" +} + +ohos_shared_library("clouddata") { + sources = [ + "src/entry_point.cpp", + "src/js_config.cpp", + "src/js_const_properties.cpp", + "src/js_error_utils.cpp", + "src/js_util.cpp", + "src/napi_queue.cpp", + ] + include_dirs = [ + "include", + "${relational_store_js_common_path}/include", + "${relational_store_napi_path}/cloud_data/include", + "${relational_store_innerapi_path}/cloud_data/include", + "//foundation/distributeddatamgr/kv_store/frameworks/common", + ] + defines = [ "SQLITE_DISTRIBUTE_RELATIONAL" ] + + external_deps = [ + "ability_runtime:abilitykit_native", + "ability_runtime:napi_base_context", + "c_utils:utils", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + "napi:ace_napi", + "relational_store:native_appdatafwk", + "relational_store:native_rdb", + ] + + subsystem_name = "distributeddatamgr" + part_name = "relational_store" + relative_install_dir = "module/data" +} diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_config.h b/relational_store/frameworks/js/napi/cloud_data/include/js_config.h new file mode 100644 index 0000000000000000000000000000000000000000..80b212fcfe83f2e0513dfdedda2dcd8237abff9d --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_config.h @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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 LDBPROJ_JS_CONFIG_H +#define LDBPROJ_JS_CONFIG_H +#include "js_const_properties.h" +#include "js_util.h" +#include "log_print.h" + +namespace OHOS::CloudData { +class JsConfig { +public: + JsConfig(); + ~JsConfig(); + + static napi_value EnableCloud(napi_env env, napi_callback_info info); + static napi_value DisableCloud(napi_env env, napi_callback_info info); + static napi_value ChangeAppCloudSwitch(napi_env env, napi_callback_info info); + static napi_value Clean(napi_env env, napi_callback_info info); + static napi_value NotifyDataChange(napi_env env, napi_callback_info info); +}; + +} // namespace OHOS::CloudData + +#endif //LDBPROJ_JS_CONFIG_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_const_properties.h b/relational_store/frameworks/js/napi/cloud_data/include/js_const_properties.h new file mode 100644 index 0000000000000000000000000000000000000000..6245a158699a31639fa32b27ee61834b5fd2b393 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_const_properties.h @@ -0,0 +1,25 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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 LDBPROJ_JS_CONST_PROPERTIES_H +#define LDBPROJ_JS_CONST_PROPERTIES_H +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CloudData { +napi_status InitConstProperties(napi_env env, napi_value exports); +} // namespace OHOS::CloudData +#endif //LDBPROJ_JS_CONST_PROPERTIES_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h b/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..fbbbc6b79ad486b6299b9da569dd5ec3f898a921 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h @@ -0,0 +1,69 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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 LDBPROJ_JS_ERROR_UTILS_H +#define LDBPROJ_JS_ERROR_UTILS_H +#include +#include + +#include "cloud_service.h" +#include "js_native_api.h" +#include "log_print.h" +#include "napi/native_common.h" + +namespace OHOS { +namespace CloudData { +using Status = OHOS::CloudData::CloudService::Status; + +struct JsErrorCode { + int32_t status; + int32_t jsCode; + const char *message; +}; + +const std::optional GetJsErrorCode(int32_t errorCode); +Status GenerateNapiError(Status status, int32_t &errCode, std::string &errMessage); +void ThrowNapiError(napi_env env, int32_t errCode, std::string errMessage, bool isParamsCheck = true); +napi_value GenerateErrorMsg(napi_env env, JsErrorCode jsInfo); + +#define ASSERT_ERR(env, assertion, errorCode, message) \ + do { \ + if (!(assertion)) { \ + ThrowNapiError(env, errorCode, message); \ + return nullptr; \ + } \ + } while (0) + +#define ASSERT_BUSINESS_ERR(ctxt, assertion, errorCode, message) \ + do { \ + if (!(assertion)) { \ + (ctxt)->isThrowError = true; \ + ThrowNapiError((ctxt)->env, errorCode, message); \ + return; \ + } \ + } while (0) + +#define ASSERT_PERMISSION_ERR(ctxt, assertion, errorCode, message) \ + do { \ + if (!(assertion)) { \ + (ctxt)->isThrowError = true; \ + ThrowNapiError((ctxt)->env, errorCode, message, false); \ + return; \ + } \ + } while (0) + +} // namespace CloudData +} // namespace OHOS +#endif //LDBPROJ_JS_ERROR_UTILS_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_util.h b/relational_store/frameworks/js/napi/cloud_data/include/js_util.h new file mode 100644 index 0000000000000000000000000000000000000000..cc26fb01ee951e697b9240ec0d438b50f955f6e6 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_util.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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 LDBPROJ_JS_UTIL_H +#define LDBPROJ_JS_UTIL_H +#include +#include + +#include "js_error_utils.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CloudData { +class JSUtil final { +public: + enum { + /* exported js Action is (CloudData::Action-1) */ + CLEAR_CLOUD_INFO = 0, + CLEAR_CLOUD_DATA_AND_INFO = 1, + }; + + struct StatusMsg { + napi_status status = napi_ok; + StatusMsg(napi_status status) : status(status) {} + operator napi_status() + { + return status; + } + }; + + using Status = OHOS::CloudData::CloudService::Status; + + static StatusMsg GetValue(napi_env env, napi_value in, napi_value &out); + static StatusMsg SetValue(napi_env env, napi_value in, napi_value &out); + /* napi_value <-> bool */ + static StatusMsg GetValue(napi_env env, napi_value in, bool &out); + static StatusMsg SetValue(napi_env env, const bool &in, napi_value &out); + /* napi_value <-> std::string */ + static StatusMsg GetValue(napi_env env, napi_value in, std::string &out); + static StatusMsg SetValue(napi_env env, const std::string &in, napi_value &out); + /* napi_value <-> int32_t */ + static napi_status GetValue(napi_env env, napi_value in, int32_t &out); + static napi_status SetValue(napi_env env, const int32_t &in, napi_value &out); + /* napi_value <-> std::map */ + static StatusMsg GetValue(napi_env env, napi_value in, std::map &out); + static StatusMsg SetValue(napi_env env, const std::map &in, napi_value &out); + /* napi_value <-> std::map */ + static StatusMsg GetValue(napi_env env, napi_value in, std::map &out); + + /* napi_get_named_property wrapper */ + template + static inline napi_status GetNamedProperty(napi_env env, napi_value in, const std::string &prop, T &value) + { + bool hasProp = false; + napi_status status = napi_has_named_property(env, in, prop.c_str(), &hasProp); + if (!hasProp) { + return napi_generic_failure; + } + if ((status == napi_ok) && hasProp) { + napi_value inner = nullptr; + status = napi_get_named_property(env, in, prop.c_str(), &inner); + if ((status == napi_ok) && (inner != nullptr)) { + return GetValue(env, inner, value); + } + } + return napi_invalid_arg; + }; + + static bool ValidSubscribeType(int32_t type) + { + return (CLEAR_CLOUD_INFO <= type) && (type <= CLEAR_CLOUD_DATA_AND_INFO); + } + +private: + enum { + /* std::map to js::tuple */ + TUPLE_KEY = 0, + TUPLE_VALUE, + TUPLE_SIZE + }; +}; +} // namespace OHOS::CloudData +#endif //LDBPROJ_JS_UTIL_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/napi_queue.h b/relational_store/frameworks/js/napi/cloud_data/include/napi_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..3e92eed53b2a9800774b7c54a08278c0832a3954 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/napi_queue.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 LDBPROJ_NAPI_QUEUE_H +#define LDBPROJ_NAPI_QUEUE_H +#include +#include +#include + +#include "log_print.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CloudData { +constexpr size_t ARGC_MAX = 6; +using NapiCbInfoParser = std::function; +using NapiAsyncExecute = std::function; +using NapiAsyncComplete = std::function; + +struct ContextBase { + virtual ~ContextBase(); + void GetCbInfo(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser(), + bool sync = false); + + inline void GetCbInfoSync(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser()) + { + /* sync = true, means no callback, not AsyncWork. */ + GetCbInfo(env, info, parse, true); + } + + napi_env env = nullptr; + napi_value output = nullptr; + napi_status status = napi_invalid_arg; + std::string error; + int32_t jsCode = 0; + bool isThrowError = false; + + napi_value self = nullptr; + void *native = nullptr; + +private: + napi_ref callbackRef = nullptr; + napi_ref selfRef = nullptr; + friend class NapiQueue; +}; + +/* check condition related to argc/argv, return and logging. */ +#define ASSERT_ARGS(ctxt, condition, message) \ + do { \ + if (!(condition)) { \ + (ctxt)->status = napi_invalid_arg; \ + (ctxt)->error = std::string(message); \ + ZLOGE("test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +#define ASSERT_STATUS(ctxt, message) \ + do { \ + if ((ctxt)->status != napi_ok) { \ + (ctxt)->error = std::string(message); \ + ZLOGE("test (ctxt->status == napi_ok) failed: " message); \ + return; \ + } \ + } while (0) + +/* check condition, return and logging if condition not true. */ +#define ASSERT(condition, message, retVal) \ + do { \ + if (!(condition)) { \ + ZLOGE("test (" #condition ") failed: " message); \ + return retVal; \ + } \ + } while (0) + +#define ASSERT_VOID(condition, message) \ + do { \ + if (!(condition)) { \ + ZLOGE("test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +#define ASSERT_NULL(condition, message) ASSERT(condition, message, nullptr) + +#define ASSERT_CALL(env, theCall, object) \ + do { \ + if ((theCall) != napi_ok) { \ + delete (object); \ + GET_AND_THROW_LAST_ERROR((env)); \ + return nullptr; \ + } \ + } while (0) + +class NapiQueue { +public: + static napi_value AsyncWork(napi_env env, std::shared_ptr ctxt, const std::string &name, + NapiAsyncExecute execute = NapiAsyncExecute(), NapiAsyncComplete complete = NapiAsyncComplete()); + +private: + enum { + /* AsyncCallback / Promise output result index */ + RESULT_ERROR = 0, + RESULT_DATA = 1, + RESULT_ALL = 2 + }; + + struct AsyncContext { + napi_env env = nullptr; + std::shared_ptr ctx; + NapiAsyncExecute execute = nullptr; + NapiAsyncComplete complete = nullptr; + napi_deferred deferred = nullptr; + napi_async_work work = nullptr; + ~AsyncContext() + { + execute = nullptr; + complete = nullptr; + ctx = nullptr; + if (env != nullptr) { + if (work != nullptr) { + napi_delete_async_work(env, work); + } + } + } + }; + static void GenerateOutput(AsyncContext &ctx, napi_value output); +}; +} // namespace OHOS::CloudData +#endif //LDBPROJ_NAPI_QUEUE_H diff --git a/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp b/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12eb000aec88642c3038f4ec074f41dc16f24c2b --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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. +*/ +#define LOG_TAG "EntryPoint" +#include "js_config.h" +#include "js_const_properties.h" +#include "log_print.h" + +using namespace OHOS::CloudData; + +static napi_value Init(napi_env env, napi_value exports) +{ + const napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("enableCloud", JsConfig::EnableCloud), + DECLARE_NAPI_FUNCTION("disableCloud", JsConfig::DisableCloud), + DECLARE_NAPI_FUNCTION("changeAppCloudSwitch", JsConfig::ChangeAppCloudSwitch), + DECLARE_NAPI_FUNCTION("clean", JsConfig::Clean), + DECLARE_NAPI_FUNCTION("notifyDataChange", JsConfig::NotifyDataChange), + + }; + napi_status status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + ZLOGI("init cloudData config %{public}d", status); + status = InitConstProperties(env, exports); + ZLOGI("init Enumerate Constants %{public}d", status); + return exports; +} + +static __attribute__((constructor)) void RegisterModule() +{ + static napi_module module = { .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "data.cloudData", + .nm_priv = ((void *)0), + .reserved = { 0 } }; + napi_module_register(&module); + ZLOGI("module register data.cloudData"); +} diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d2abf659e67f4369ad06a4744457751bfd1ec12 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp @@ -0,0 +1,221 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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. +*/ +#define LOG_TAG "JsConfig" +#include "js_config.h" + +#include "cloud_manager.h" +#include "js_error_utils.h" +#include "js_util.h" +#include "log_print.h" +#include "napi_queue.h" + +using namespace OHOS::CloudData; + +JsConfig::JsConfig() {} + +JsConfig::~JsConfig() {} + +/* + * [JS API Prototype] + * [AsyncCallback] + * enableCloud(accountId: string, switches: {[bundleName: string]: boolean}, callback: AsyncCallback): void; + * [Promise] + * enableCloud(accountId: string, switches: {[bundleName: string]: boolean}): Promise; + */ +napi_value JsConfig::EnableCloud(napi_env env, napi_callback_info info) +{ + struct EnableCloudContext : public ContextBase { + std::string accountId; + std::map switches1; + std::map switches2; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "The type of key must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->switches1); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of key must be {[bundleName: string]: boolean}."); + for (auto item : ctxt->switches1) { + ctxt->switches2.insert(std::pair(item.first, static_cast(item.second))); + } + }); + + ASSERT_NULL(!ctxt->isThrowError, "EnableCloud exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->EnableCloud(ctxt->accountId, ctxt->switches2); + ZLOGD("EnableCloud return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * disableCloud(accountId: string, callback: AsyncCallback): void; + * [Promise] + * disableCloud(accountId: string): Promise; + */ +napi_value JsConfig::DisableCloud(napi_env env, napi_callback_info info) +{ + struct DisableCloudContext : public ContextBase { + std::string accountId; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "DisableCloud exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->DisableCloud(ctxt->accountId); + ZLOGD("DisableCloud return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * changeAppCloudSwitch(accountId: string, bundleName: string, status :boolean, callback: AsyncCallback): void; + * [Promise] + * changeAppCloudSwitch(accountId: string, bundleName: string, status :boolean): Promise; + */ +napi_value JsConfig::ChangeAppCloudSwitch(napi_env env, napi_callback_info info) +{ + struct ChangeAppSwitchContext : public ContextBase { + std::string accountId; + std::string bundleName; + bool status; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 3 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 3, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->bundleName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of bundleName must be string."); + ctxt->status = JSUtil::GetValue(env, argv[2], ctxt->status); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of bundleName must be boolean."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "ChangeAppCloudSwitch exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->ChangeAppSwitch(ctxt->accountId, ctxt->bundleName, ctxt->status); + ZLOGD("kvStore->Put return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * clean(accountId: string, appActions: {[bundleName: string]: Action}, callback: AsyncCallback): void; + * [Promise] + * clean(accountId: string, appActions: {[bundleName: string]: Action}): Promise; + */ +napi_value JsConfig::Clean(napi_env env, napi_callback_info info) +{ + struct CleanContext : public ContextBase { + std::string accountId; + std::map actions; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->actions); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of actions must be {[bundleName: string]: int32_t}."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "Clean exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->Clean(ctxt->accountId, ctxt->actions); + ZLOGD("Clean return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * notifyDataChange(accountId: string, bundleName: string, callback: AsyncCallback): void; + * [Promise] + * notifyDataChange(accountId: string, bundleName: string): Promise; + */ +napi_value JsConfig::NotifyDataChange(napi_env env, napi_callback_info info) +{ + struct ChangeAppSwitchContext : public ContextBase { + std::string accountId; + std::string bundleName; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->bundleName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of bundleName must be string."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "NotifyDataChange exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->NotifyDataChange(ctxt->accountId, ctxt->bundleName); + ZLOGD("NotifyDataChange return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_const_properties.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_const_properties.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60f4df42ae7d5cbbc1c5bc00684c756f1de5bba4 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_const_properties.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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. +*/ +#define LOG_TAG "Const_Properties" +#include "js_const_properties.h" + +#include "cloud_service.h" +#include "log_print.h" +#include "napi_queue.h" + +using Action = OHOS::CloudData::CloudService::Action; +namespace OHOS::CloudData { +static napi_status SetNamedProperty(napi_env env, napi_value &obj, const std::string &name, int32_t value) +{ + napi_value property = nullptr; + napi_status status = napi_create_int32(env, value, &property); + ASSERT(status == napi_ok, "int32_t to napi_value failed!", status); + status = napi_set_named_property(env, obj, name.c_str(), property); + ASSERT(status == napi_ok, "napi_set_named_property failed!", status); + return status; +} + +static napi_value ExportAction(napi_env env) +{ + napi_value action = nullptr; + napi_create_object(env, &action); + SetNamedProperty(env, action, "CLEAR_CLOUD_INFO", (int32_t)Action::CLEAR_CLOUD_INFO); + SetNamedProperty(env, action, "CLEAR_CLOUD_DATA_AND_INFO", (int32_t)Action::CLEAR_CLOUD_DATA_AND_INFO); + napi_object_freeze(env, action); + return action; +} + +napi_status InitConstProperties(napi_env env, napi_value exports) +{ + const napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("Action", ExportAction(env)), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + + return napi_define_properties(env, exports, count, properties); +} +} // namespace OHOS::CloudData diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_error_utils.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_error_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..300c99ee1db7ac1f8c83ed42505b091f0305ee34 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_error_utils.cpp @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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. +*/ +#define LOG_TAG "JS_ERROR_UTILS" + +#include "js_error_utils.h" + +#include + +namespace OHOS::CloudData { +using JsErrorCode = OHOS::CloudData::JsErrorCode; + +static constexpr JsErrorCode JS_ERROR_CODE_MSGS[] = { + { Status::INVALID_ARGUMENT, 401, "Parameter error." }, +}; + +const std::optional GetJsErrorCode(int32_t errorCode) +{ + auto jsErrorCode = JsErrorCode{ errorCode, -1, "" }; + auto iter = std::lower_bound(JS_ERROR_CODE_MSGS, + JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]), jsErrorCode, + [](const JsErrorCode &jsErrorCode1, const JsErrorCode &jsErrorCode2) { + return jsErrorCode1.status < jsErrorCode2.status; + }); + if (iter < JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]) && + iter->status == errorCode) { + return *iter; + } + return std::nullopt; +} + +Status GenerateNapiError(Status status, int32_t &errCode, std::string &errMessage) +{ + auto errorMsg = GetJsErrorCode(status); + if (errorMsg.has_value()) { + auto napiError = errorMsg.value(); + errCode = napiError.jsCode; + errMessage = napiError.message; + } else { + // unmatched status return unified error code + errCode = -1; + errMessage = ""; + } + ZLOGD("GenerateNapiError errCode is %{public}d", errCode); + if (errCode == 0) { + return Status::SUCCESS; + } + return status; +} + +void ThrowNapiError(napi_env env, int32_t status, std::string errMessage, bool isParamsCheck) +{ + ZLOGD("ThrowNapiError message: %{public}s", errMessage.c_str()); + if (status == Status::SUCCESS) { + return; + } + auto errorMsg = GetJsErrorCode(status); + JsErrorCode napiError; + if (errorMsg.has_value()) { + napiError = errorMsg.value(); + } else { + napiError.jsCode = -1; + napiError.message = ""; + } + + std::string message(napiError.message); + if (isParamsCheck) { + napiError.jsCode = 401; + message += errMessage; + } + + std::string jsCode; + if (napiError.jsCode == -1) { + jsCode = ""; + } else { + jsCode = std::to_string(napiError.jsCode); + } + napi_throw_error(env, jsCode.c_str(), message.c_str()); +} +} // namespace OHOS::CloudData diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_util.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..554e7ee24e0b925711a4137c22c2a8e32bf54d4a --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_util.cpp @@ -0,0 +1,166 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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. +*/ +#define LOG_TAG "JSUtil" +#include "js_util.h" + +#include "log_print.h" +#include "napi_base_context.h" +#include "napi_queue.h" + +namespace OHOS::CloudData { +constexpr int32_t STR_MAX_LENGTH = 4096; +constexpr size_t STR_TAIL_LENGTH = 1; + +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, napi_value &out) +{ + out = in; + return napi_ok; +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, napi_value in, napi_value &out) +{ + out = in; + return napi_ok; +} + +/* napi_value <-> bool */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, bool &out) +{ + return napi_get_value_bool(env, in, &out); +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, const bool &in, napi_value &out) +{ + return napi_get_boolean(env, in, &out); +} + +/* napi_value <-> int32_t */ +napi_status JSUtil::GetValue(napi_env env, napi_value in, int32_t &out) +{ + return napi_get_value_int32(env, in, &out); +} + +napi_status JSUtil::SetValue(napi_env env, const int32_t &in, napi_value &out) +{ + return napi_create_int32(env, in, &out); +} + +/* napi_value <-> std::string */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, std::string &out) +{ + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, in, &type); + ASSERT((status == napi_ok) && (type == napi_string), "invalid type", napi_invalid_arg); + + size_t maxLen = STR_MAX_LENGTH; + status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen); + if (maxLen <= 0) { + return status; + } + ZLOGD("napi_value -> std::string get length %{public}d", (int)maxLen); + char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH]; + if (buf != nullptr) { + size_t len = 0; + status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len); + if (status == napi_ok) { + buf[len] = 0; + out = std::string(buf); + } + delete[] buf; + } else { + status = napi_generic_failure; + } + return status; +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, const std::string &in, napi_value &out) +{ + return napi_create_string_utf8(env, in.c_str(), in.size(), &out); +} + +/* napi_value <-> std::map */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, std::map &out) +{ + ZLOGD("napi_value -> std::map "); + out.clear(); + uint32_t length = 0; + napi_status status = napi_get_array_length(env, in, &length); + ASSERT((status == napi_ok) && (length > 0), "get_map failed!", napi_invalid_arg); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + status = napi_get_element(env, in, i, &item); + ASSERT((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg); + int index = 0; + napi_value item1 = nullptr; + status = napi_get_element(env, item, index++, &item1); + std::string key; + status = GetValue(env, item1, key); + napi_value item2 = nullptr; + status = napi_get_element(env, item, index, &item2); + bool value; + status = GetValue(env, item2, value); + out.insert(std::pair(key, status)); + } + return status; +} + +/* napi_value <-> std::map */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, std::map &out) +{ + ZLOGD("napi_value -> std::map "); + out.clear(); + uint32_t length = 0; + napi_status status = napi_get_array_length(env, in, &length); + ASSERT((status == napi_ok) && (length > 0), "get_map failed!", napi_invalid_arg); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + status = napi_get_element(env, in, i, &item); + ASSERT((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg); + int index = 0; + napi_value item1 = nullptr; + status = napi_get_element(env, item, index++, &item1); + std::string key; + status = GetValue(env, item1, key); + napi_value item2 = nullptr; + status = napi_get_element(env, item, index, &item2); + int32_t actionType; + status = GetValue(env, item2, actionType); + ASSERT(ValidSubscribeType(actionType) == true, "not action", napi_invalid_arg); + out.insert(std::pair(key, actionType)); + } + return status; +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, const std::map &in, napi_value &out) +{ + ZLOGD("napi_value <- std::map "); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + ASSERT((status == napi_ok), "invalid object", status); + int index = 0; + for (const auto &[key, value] : in) { + napi_value element = nullptr; + napi_create_array_with_length(env, TUPLE_SIZE, &element); + napi_value jsKey = nullptr; + napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey); + napi_set_element(env, element, TUPLE_KEY, jsKey); + napi_value jsValue = nullptr; + napi_create_int32(env, static_cast(value), &jsValue); + napi_set_element(env, element, TUPLE_VALUE, jsValue); + napi_set_element(env, out, index++, element); + } + return status; +} + +} // namespace OHOS::CloudData diff --git a/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp b/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4db2a0ba68532d148413f4b52c6a83b473db660d --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp @@ -0,0 +1,163 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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. +*/ +#define LOG_TAG "NapiQueue" +#include "napi_queue.h" + +namespace OHOS::CloudData { +ContextBase::~ContextBase() +{ + ZLOGD("no memory leak after callback or promise[resolved/rejected]"); + if (env != nullptr) { + if (callbackRef != nullptr) { + auto status = napi_delete_reference(env, callbackRef); + ZLOGD("status:%{public}d", status); + } + if (selfRef != nullptr) { + auto status = napi_delete_reference(env, selfRef); + ZLOGD("status:%{public}d", status); + } + env = nullptr; + } +} + +void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parse, bool sync) +{ + env = envi; + size_t argc = ARGC_MAX; + napi_value argv[ARGC_MAX] = { nullptr }; + status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr); + ASSERT_STATUS(this, "napi_get_cb_info failed!"); + ASSERT_ARGS(this, argc <= ARGC_MAX, "too many arguments!"); + ASSERT_ARGS(this, self != nullptr, "no JavaScript this argument!"); + if (!sync) { + napi_create_reference(env, self, 1, &selfRef); + } + status = napi_unwrap(env, self, &native); + ASSERT_STATUS(this, "self unwrap failed!"); + + if (!sync && (argc > 0)) { + // get the last arguments :: + size_t index = argc - 1; + napi_valuetype type = napi_undefined; + napi_status tyst = napi_typeof(env, argv[index], &type); + if ((tyst == napi_ok) && (type == napi_function)) { + status = napi_create_reference(env, argv[index], 1, &callbackRef); + ASSERT_STATUS(this, "ref callback failed!"); + argc = index; + ZLOGD("async callback, no promise"); + } else { + ZLOGD("no callback, async pormose"); + } + } + + if (parse) { + parse(argc, argv); + } else { + ASSERT_ARGS(this, argc == 0, "required no arguments!"); + } +} + +napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr ctxt, const std::string &name, + NapiAsyncExecute execute, NapiAsyncComplete complete) +{ + ZLOGD("name=%{public}s", name.c_str()); + AsyncContext *aCtx = new AsyncContext; + aCtx->env = env; + aCtx->ctx = std::move(ctxt); + aCtx->execute = std::move(execute); + aCtx->complete = std::move(complete); + napi_value promise = nullptr; + if (aCtx->ctx->callbackRef == nullptr) { + napi_create_promise(env, &aCtx->deferred, &promise); + ZLOGD("create deferred promise"); + } else { + napi_get_undefined(env, &promise); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource); + napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void *data) { + ASSERT_VOID(data != nullptr, "napi_async_execute_callback nullptr"); + auto actx = reinterpret_cast(data); + ZLOGD("napi_async_execute_callback ctxt->status=%{public}d", actx->ctx->status); + if (actx->execute && actx->ctx->status == napi_ok) { + actx->execute(); + } + }, + [](napi_env env, napi_status status, void *data) { + ASSERT_VOID(data != nullptr, "napi_async_complete_callback nullptr"); + auto actx = reinterpret_cast(data); + ZLOGD("napi_async_complete_callback status=%{public}d, ctxt->status=%{public}d", status, actx->ctx->status); + if ((status != napi_ok) && (actx->ctx->status == napi_ok)) { + actx->ctx->status = status; + } + napi_value output = nullptr; + if ((actx->complete) && (status == napi_ok) && (actx->ctx->status == napi_ok)) { + actx->complete(output); + } + GenerateOutput(*actx, output); + delete actx; + }, + reinterpret_cast(aCtx), &aCtx->work); + auto status = napi_queue_async_work(env, aCtx->work); + if (status != napi_ok) { + napi_get_undefined(env, &promise); + delete aCtx; + } + return promise; +} + +void NapiQueue::GenerateOutput(AsyncContext &ctx, napi_value output) +{ + napi_value result[RESULT_ALL] = { nullptr }; + if (ctx.ctx->status == napi_ok) { + napi_get_undefined(ctx.env, &result[RESULT_ERROR]); + if (output == nullptr) { + napi_get_undefined(ctx.env, &output); + } + result[RESULT_DATA] = output; + } else { + napi_value message = nullptr; + napi_value errorCode = nullptr; + if (ctx.ctx->jsCode != 0 && ctx.ctx->jsCode != -1) { + napi_create_string_utf8(ctx.env, std::to_string(ctx.ctx->jsCode).c_str(), NAPI_AUTO_LENGTH, &errorCode); + } + if (ctx.ctx->jsCode == -1) { + std::string jscode = ""; + napi_create_string_utf8(ctx.env, jscode.c_str(), NAPI_AUTO_LENGTH, &errorCode); + } + napi_create_string_utf8(ctx.env, ctx.ctx->error.c_str(), NAPI_AUTO_LENGTH, &message); + napi_create_error(ctx.env, errorCode, message, &result[RESULT_ERROR]); + napi_get_undefined(ctx.env, &result[RESULT_DATA]); + } + if (ctx.deferred != nullptr) { + if (ctx.ctx->status == napi_ok) { + ZLOGD("deferred promise resolved"); + napi_resolve_deferred(ctx.env, ctx.deferred, result[RESULT_DATA]); + } else { + ZLOGD("deferred promise rejected"); + napi_reject_deferred(ctx.env, ctx.deferred, result[RESULT_ERROR]); + } + } else { + napi_value callback = nullptr; + napi_get_reference_value(ctx.env, ctx.ctx->callbackRef, &callback); + napi_value callbackResult = nullptr; + ZLOGD("call callback function"); + napi_call_function(ctx.env, nullptr, callback, RESULT_ALL, result, &callbackResult); + } +} +} // namespace OHOS::CloudData diff --git a/relational_store/frameworks/js/napi/common/include/js_utils.h b/relational_store/frameworks/js/napi/common/include/js_utils.h index 67aef256db93af21c51042b08457e48c0beaa161..df9e9b60132143a7f0ab8dfd63497f7bb1c0af26 100644 --- a/relational_store/frameworks/js/napi/common/include/js_utils.h +++ b/relational_store/frameworks/js/napi/common/include/js_utils.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "napi/native_api.h" @@ -27,46 +28,139 @@ namespace OHOS { namespace AppDataMgrJsKit { -class JSUtils final { -public: - static constexpr int OK = 0; - static constexpr int ERR = -1; - static constexpr int32_t DEFAULT_BUF_SIZE = 1024; - // 1 is the margin - static constexpr int32_t BUF_CACHE_MARGIN = 4 + 1; - static constexpr int32_t ASYNC_RST_SIZE = 2; - static constexpr int32_t MAX_VALUE_LENGTH = 8 * 1024; - static constexpr int32_t SYNC_RESULT_ELEMNT_NUM = 2; - - static std::string Convert2String(napi_env env, napi_value jsStr, bool useDefaultBufSize = true); - static int32_t Convert2Bool(napi_env env, napi_value jsBool, bool &output); - static int32_t Convert2Double(napi_env env, napi_value jsNum, double &output); - static int32_t Convert2String(napi_env env, napi_value jsStr, std::string &output); - static int32_t Convert2U8Vector(napi_env env, napi_value jsValue, std::vector &output); - static std::vector Convert2StrVector(napi_env env, napi_value value); - static std::vector Convert2U8Vector(napi_env env, napi_value jsValue); - static std::string ConvertAny2String(napi_env env, const napi_value jsValue); - - static int32_t Convert2StrVector(napi_env env, napi_value value, std::vector &output); - static int32_t Convert2BoolVector(napi_env env, napi_value value, std::vector &output); - static int32_t Convert2DoubleVector(napi_env env, napi_value value, std::vector &output); - - static napi_value Convert2JSValue(napi_env env, const std::vector &value); - static napi_value Convert2JSValue(napi_env env, const std::string &value); - static napi_value Convert2JSValue(napi_env env, const std::vector &value); - static napi_value Convert2JSValue(napi_env env, int32_t value); - static napi_value Convert2JSValue(napi_env env, int64_t value); - static napi_value Convert2JSValue(napi_env env, double value); - static napi_value Convert2JSValue(napi_env env, bool value); - static napi_value Convert2JSValue(napi_env env, const std::map &value); - - static int32_t Convert2JSValue(napi_env env, std::string value, napi_value &output); - static int32_t Convert2JSValue(napi_env env, bool value, napi_value &output); - static int32_t Convert2JSValue(napi_env env, double value, napi_value &output); - static int32_t Convert2JSStringArr(napi_env env, std::vector value, napi_value &output); - static int32_t Convert2JSBoolArr(napi_env env, std::vector value, napi_value &output); - static int32_t Convert2JSDoubleArr(napi_env env, std::vector value, napi_value &output); -}; +namespace JSUtils { +constexpr int OK = 0; +constexpr int ERR = -1; +constexpr int32_t DEFAULT_BUF_SIZE = 1024; +// 1 is the margin +constexpr int32_t BUF_CACHE_MARGIN = 4 + 1; +constexpr int32_t ASYNC_RST_SIZE = 2; +constexpr int32_t MAX_VALUE_LENGTH = 8 * 1024; +constexpr int32_t SYNC_RESULT_ELEMNT_NUM = 2; + +std::string Convert2String(napi_env env, napi_value jsStr, bool useDefaultBufSize = true); +int32_t Convert2Value(napi_env env, napi_value jsBool, bool &output); +int32_t Convert2Value(napi_env env, napi_value jsNum, int64_t &output); +int32_t Convert2Value(napi_env env, napi_value jsNum, double &output); +int32_t Convert2Value(napi_env env, napi_value jsStr, std::string &output); +int32_t Convert2Value(napi_env env, napi_value jsValue, std::vector &output); +int32_t Convert2Value(napi_env env, napi_value jsValue, std::monostate &value); +std::vector Convert2StrVector(napi_env env, napi_value value); +std::vector Convert2U8Vector(napi_env env, napi_value jsValue); +std::string ConvertAny2String(napi_env env, napi_value jsValue); + +template +int32_t Convert2Value(napi_env env, napi_value jsValue, T &output); +template +int32_t Convert2Value(napi_env env, napi_value jsValue, std::vector &value); +template +int32_t Convert2Value(napi_env env, napi_value jsValue, std::variant<_Types...> &value); + +template +napi_value Convert2JSValue(napi_env env, const std::variant<_Types...> &value); + +int32_t Convert2JSValue(napi_env env, std::string value, napi_value &output); +int32_t Convert2JSValue(napi_env env, bool value, napi_value &output); +int32_t Convert2JSValue(napi_env env, double value, napi_value &output); + +napi_value Convert2JSValue(napi_env env, const std::vector &value); +napi_value Convert2JSValue(napi_env env, const std::string &value); +napi_value Convert2JSValue(napi_env env, const std::vector &value); +napi_value Convert2JSValue(napi_env env, int32_t value); +napi_value Convert2JSValue(napi_env env, int64_t value); +napi_value Convert2JSValue(napi_env env, double value); +napi_value Convert2JSValue(napi_env env, bool value); +napi_value Convert2JSValue(napi_env env, const std::map &value); +napi_value Convert2JSValue(napi_env env, const std::monostate &value); +template +napi_value Convert2JSValue(napi_env env, const T &value); +template +napi_value Convert2JSValue(napi_env env, const std::vector &value); + +template +napi_value Convert2JSValue(napi_env env, const std::variant<_Types...> &value); + +template +int32_t GetCPPValue(napi_env env, napi_value jsValue, _T &value) +{ + return napi_invalid_arg; +} + +template +int32_t GetCPPValue(napi_env env, napi_value jsValue, _T &value) +{ + _First cValue; + auto ret = Convert2Value(env, jsValue, cValue); + if (ret != napi_invalid_arg) { + if (ret == napi_ok) { + value = cValue; + } + return ret; + } + return GetCPPValue<_T, _Types...>(env, jsValue, value); +} + +template +napi_value GetJSValue(napi_env env, const _T &value) +{ + return nullptr; +} + +template +napi_value GetJSValue(napi_env env, const _T &value) +{ + auto *val = std::get_if<_First>(&value); + if (val == nullptr) { + return Convert2JSValue(env, *val); + } + return GetJSValue<_T, _Types...>(env, value); +} +} // namespace JSUtils + +template +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::vector &value) +{ + uint32_t arrLen = 0; + napi_get_array_length(env, jsValue, &arrLen); + if (arrLen == 0) { + return napi_ok; + } + for (size_t i = 0; i < arrLen; ++i) { + napi_value element; + napi_get_element(env, jsValue, i, &element); + T item; + Convert2Value(env, element, item); + value.push_back(std::move(item)); + } + return napi_ok; +} + +template +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::variant<_Types...> &value) +{ + return GetCPPValue(env, jsValue, value); +} + +template +napi_value JSUtils::Convert2JSValue(napi_env env, const std::vector &value) +{ + napi_value jsValue; + napi_status status = napi_create_array_with_length(env, value.size(), &jsValue); + if (status != napi_ok) { + return nullptr; + } + + for (size_t i = 0; i < value.size(); ++i) { + napi_set_element(env, jsValue, i, Convert2JSValue(env, value[i])); + } + return jsValue; +} + +template +napi_value JSUtils::Convert2JSValue(napi_env env, const std::variant<_Types...> &value) +{ + return GetJSValue(env, value); +} } // namespace AppDataMgrJsKit } // namespace OHOS diff --git a/relational_store/frameworks/js/napi/common/src/js_utils.cpp b/relational_store/frameworks/js/napi/common/src/js_utils.cpp index baf7b22579e352e9a5ef6b2ed5695004f4cb0cd2..3cc72bfaac59d45b0ef4f2061c99208fcf575996 100644 --- a/relational_store/frameworks/js/napi/common/src/js_utils.cpp +++ b/relational_store/frameworks/js/napi/common/src/js_utils.cpp @@ -26,7 +26,11 @@ std::string JSUtils::Convert2String(napi_env env, napi_value jsStr, bool useDefa str_buffer_size = (useDefaultBufSize && (str_buffer_size > DEFAULT_BUF_SIZE)) ? (DEFAULT_BUF_SIZE + BUF_CACHE_MARGIN) : (str_buffer_size + BUF_CACHE_MARGIN); - char *buf = new char[str_buffer_size]; + char *buf = new (std::nothrow) char[str_buffer_size]; + if (buf == nullptr) { + LOG_ERROR("JSUtils::Convert2String new failed, buf is nullptr"); + return ""; + } size_t len = 0; napi_get_value_string_utf8(env, jsStr, buf, str_buffer_size, &len); buf[len] = 0; @@ -35,13 +39,17 @@ std::string JSUtils::Convert2String(napi_env env, napi_value jsStr, bool useDefa return value; } -int32_t JSUtils::Convert2String(napi_env env, napi_value jsStr, std::string &output) +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsStr, std::string &output) { - char *str = new char[MAX_VALUE_LENGTH + 1]; + char *str = new (std::nothrow) char[MAX_VALUE_LENGTH + 1]; + if (str == nullptr) { + LOG_ERROR("JSUtils::Convert2Value new failed, str is nullptr"); + return ERR; + } size_t valueSize = 0; napi_status status = napi_get_value_string_utf8(env, jsStr, str, MAX_VALUE_LENGTH, &valueSize); if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2String get jsVal failed, status = %{public}d", status); + LOG_ERROR("JSUtils::Convert2Value get jsVal failed, status = %{public}d", status); delete[] str; return ERR; } @@ -50,7 +58,7 @@ int32_t JSUtils::Convert2String(napi_env env, napi_value jsStr, std::string &out return OK; } -int32_t JSUtils::Convert2U8Vector(napi_env env, napi_value jsValue, std::vector &output) +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::vector &output) { bool isTypedArray = false; napi_is_typedarray(env, jsValue, &isTypedArray); @@ -71,24 +79,49 @@ int32_t JSUtils::Convert2U8Vector(napi_env env, napi_value jsValue, std::vector< return OK; } -int32_t JSUtils::Convert2Bool(napi_env env, napi_value jsBool, bool &output) +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsValue, std::monostate &value) +{ + napi_value tempValue; + napi_get_null(env, &tempValue); + bool equal = false; + napi_strict_equals(env, jsValue, tempValue, &equal); + if (equal) { + return OK; + } + napi_get_undefined(env, &tempValue); + napi_strict_equals(env, jsValue, tempValue, &equal); + if (equal) { + return OK; + } + return ERR; +} + +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsBool, bool &output) { bool bValue = false; napi_status status = napi_get_value_bool(env, jsBool, &bValue); if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2Bool get jsVal failed, status = %{public}d", status); + LOG_ERROR("JSUtils::Convert2Value get jsVal failed, status = %{public}d", status); return ERR; } output = bValue; return OK; } - -int32_t JSUtils::Convert2Double(napi_env env, napi_value jsNum, double &output) +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsNum, int64_t &output) +{ + napi_status status = napi_get_value_int64(env, jsNum, &output); + if (status != napi_ok) { + LOG_ERROR("JSUtils::Convert2Value get jsVal failed, status = %{public}d", status); + return ERR; + } + return OK; +} +int32_t JSUtils::Convert2Value(napi_env env, napi_value jsNum, double &output) { double number = 0.0; napi_status status = napi_get_value_double(env, jsNum, &number); if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2Double get jsVal failed, status = %{public}d", status); + LOG_ERROR("JSUtils::Convert2Value get jsVal failed, status = %{public}d", status); return ERR; } output = number; @@ -111,88 +144,6 @@ std::vector JSUtils::Convert2StrVector(napi_env env, napi_value val return result; } -int32_t JSUtils::Convert2StrVector(napi_env env, napi_value value, std::vector &output) -{ - uint32_t arrLen = 0; - napi_status status = napi_get_array_length(env, value, &arrLen); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2StrVector get arrLength failed, status = %{public}d", status); - output = {}; - return ERR; - } - if (arrLen == 0) { - output = {}; - return OK; - } - napi_value element = nullptr; - for (size_t i = 0; i < arrLen; ++i) { - status = napi_get_element(env, value, i, &element); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2StrVector get element failed, status = %{public}d", status); - return ERR; - } - std::string str; - if (Convert2String(env, element, str) != OK) { - LOG_ERROR("JSUtils::Convert2StrVector convert element failed"); - return ERR; - } - output.push_back(str); - } - return OK; -} - -int32_t JSUtils::Convert2BoolVector(napi_env env, napi_value value, std::vector &output) -{ - uint32_t arrLen = 0; - napi_status status = napi_get_array_length(env, value, &arrLen); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2BoolVector get arrLength failed, status = %{public}d", status); - output = {}; - return ERR; - } - napi_value element = nullptr; - for (size_t i = 0; i < arrLen; ++i) { - status = napi_get_element(env, value, i, &element); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2BoolVector get element failed, status = %{public}d", status); - return ERR; - } - bool bVal = false; - if (Convert2Bool(env, element, bVal) != OK) { - LOG_ERROR("JSUtils::Convert2BoolVector convert element failed"); - return ERR; - } - output.push_back(bVal); - } - return OK; -} - -int32_t JSUtils::Convert2DoubleVector(napi_env env, napi_value value, std::vector &output) -{ - uint32_t arrLen = 0; - napi_status status = napi_get_array_length(env, value, &arrLen); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2DoubleVector get arrLength failed, status = %{public}d", status); - output = {}; - return ERR; - } - napi_value element = nullptr; - for (size_t i = 0; i < arrLen; ++i) { - status = napi_get_element(env, value, i, &element); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2DoubleVector get element failed, status = %{public}d", status); - return ERR; - } - double number = 0.0; - if (Convert2Double(env, element, number) != OK) { - LOG_ERROR("JSUtils::Convert2Double convert element failed"); - return ERR; - } - output.push_back(number); - } - return OK; -} - std::vector JSUtils::Convert2U8Vector(napi_env env, napi_value input_array) { bool isTypedArray = false; @@ -371,73 +322,11 @@ int32_t JSUtils::Convert2JSValue(napi_env env, double value, napi_value &output) return OK; } -int32_t JSUtils::Convert2JSDoubleArr(napi_env env, std::vector value, napi_value &output) +napi_value JSUtils::Convert2JSValue(napi_env env, const std::monostate &value) { - size_t arrLen = value.size(); - napi_status status = napi_create_array_with_length(env, arrLen, &output); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2JSValue get arrLength failed"); - return ERR; - } - for (size_t i = 0; i < arrLen; i++) { - napi_value val = nullptr; - if (Convert2JSValue(env, value[i], val) != OK) { - LOG_ERROR("JSUtils::Convert2JSValue creat double failed"); - return ERR; - } - status = napi_set_element(env, output, i, val); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2JSValue set element failed"); - return ERR; - } - } - return OK; -} - -int32_t JSUtils::Convert2JSBoolArr(napi_env env, std::vector value, napi_value &output) -{ - size_t arrLen = value.size(); - napi_status status = napi_create_array_with_length(env, arrLen, &output); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2JSValue get arrLength failed"); - return ERR; - } - for (size_t i = 0; i < arrLen; i++) { - napi_value val = nullptr; - if (Convert2JSValue(env, value[i], val) != OK) { - LOG_ERROR("JSUtils::Convert2JSValue creat bool failed"); - return ERR; - } - status = napi_set_element(env, output, i, val); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2JSValue set element failed"); - return ERR; - } - } - return OK; -} - -int32_t JSUtils::Convert2JSStringArr(napi_env env, std::vector value, napi_value &output) -{ - size_t arrLen = value.size(); - napi_status status = napi_create_array_with_length(env, arrLen, &output); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2JSValue get arrLength failed"); - return ERR; - } - for (size_t i = 0; i < arrLen; i++) { - napi_value val = nullptr; - if (Convert2JSValue(env, value[i], val) != OK) { - LOG_ERROR("JSUtils::Convert2JSValue creat string failed"); - return ERR; - } - status = napi_set_element(env, output, i, val); - if (status != napi_ok) { - LOG_ERROR("JSUtils::Convert2JSValue set element failed"); - return ERR; - } - } - return OK; + napi_value result; + napi_get_undefined(env, &result); + return result; } } // namespace AppDataMgrJsKit } // namespace OHOS diff --git a/relational_store/frameworks/js/napi/dataability/src/napi_data_ability_predicates.cpp b/relational_store/frameworks/js/napi/dataability/src/napi_data_ability_predicates.cpp index 848825b0314992261c0819bec3c5d7c04764bc84..1089e67ddf3961faab05a5697a0b2c14cb8308fd 100644 --- a/relational_store/frameworks/js/napi/dataability/src/napi_data_ability_predicates.cpp +++ b/relational_store/frameworks/js/napi/dataability/src/napi_data_ability_predicates.cpp @@ -91,7 +91,11 @@ napi_value DataAbilityPredicatesProxy::New(napi_env env, napi_callback_info info NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thiz, nullptr)); if (is_constructor) { - auto *proxy = new DataAbilityPredicatesProxy(); + auto *proxy = new (std::nothrow) DataAbilityPredicatesProxy(); + if (proxy == nullptr) { + LOG_ERROR("DataAbilityPredicatesProxy::New new failed, proxy is nullptr"); + return nullptr; + } napi_status status = napi_wrap(env, thiz, proxy, DataAbilityPredicatesProxy::Destructor, nullptr, nullptr); if (status != napi_ok) { LOG_ERROR("DataAbilityPredicatesProxy::New napi_wrap failed! napi_status:%{public}d!", status); diff --git a/relational_store/frameworks/js/napi/dataability/src/napi_predicates_utils.cpp b/relational_store/frameworks/js/napi/dataability/src/napi_predicates_utils.cpp index a4fa6a17fd36ea69d51648b7db92fb08023367be..21451dab781b1eea8c269ca190959e05b4bc7d69 100644 --- a/relational_store/frameworks/js/napi/dataability/src/napi_predicates_utils.cpp +++ b/relational_store/frameworks/js/napi/dataability/src/napi_predicates_utils.cpp @@ -52,7 +52,7 @@ napi_value CreateRdbPredicates(napi_env env, napi_callback_info info) absPredicates->GetIndex(), absPredicates->GetGroup(), absPredicates->GetOrder(), absPredicates->GetLimit(), absPredicates->GetOffset()); - return RdbJsKit::RdbPredicatesProxy::NewInstance(env, predicates); + return RelationalStoreJsKit::RdbPredicatesProxy::NewInstance(env, predicates); } napi_value InitPredicatesUtils(napi_env env, napi_value exports) diff --git a/relational_store/frameworks/js/napi/rdb/BUILD.gn b/relational_store/frameworks/js/napi/rdb/BUILD.gn index 2692746190157467068e129eb117627d8ddb3aeb..2a91a602ebe3081e1786ea094a29fd2aa24a49f4 100644 --- a/relational_store/frameworks/js/napi/rdb/BUILD.gn +++ b/relational_store/frameworks/js/napi/rdb/BUILD.gn @@ -27,6 +27,7 @@ ohos_shared_library("napi_rdb") { "../common/src/js_utils.cpp", "src/napi_async_call.cpp", "src/napi_rdb_const_properties.cpp", + "src/napi_rdb_js_utils.cpp", "src/napi_rdb_predicates.cpp", "src/napi_rdb_store.cpp", "src/napi_rdb_store_helper.cpp", @@ -78,6 +79,7 @@ ohos_shared_library("napi_rdb") { "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hilog_native:libhilog", "hitrace_native:hitrace_meter", "napi:ace_napi", diff --git a/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h index f4dda5a29d4fc8c38454458651c0b9cf71b4b0a8..35430275a6f10c54cd478ad64b71a9add3b06e2f 100644 --- a/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h +++ b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_error.h @@ -26,7 +26,6 @@ constexpr int APIVERSION_V9 = 9; constexpr int APIVERSION_8 = 8; constexpr int E_PARAM_ERROR = 401; - constexpr int E_INNER_ERROR = 14800000; constexpr int E_DB_INVALID = 14800010; @@ -42,7 +41,7 @@ constexpr int E_RESULT_GOTO_ERROR = 14800012; napi_throw_error((env), nullptr, "error message is empty"); \ return retVal; \ } \ - if (((version) > (APIVERSION_8)) || ((error->GetCode()) == (401))) { \ + if (((version) > (APIVERSION_8)) || ((error->GetCode()) == (401))) { \ LOG_ERROR("throw error: code = %{public}d , message = %{public}s, version= %{public}d", \ error->GetCode(), error->GetMessage().c_str(), version); \ napi_throw_error((env), std::to_string(error->GetCode()).c_str(), error->GetMessage().c_str()); \ diff --git a/relational_store/frameworks/js/napi/rdb/include/napi_rdb_js_utils.h b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_js_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..22c5dcc787b6d62ef925c24d7f211ce3eb8c6fde --- /dev/null +++ b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_js_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 RDB_JSKIT_NAPI_RDB_JS_UTILS_H +#define RDB_JSKIT_NAPI_RDB_JS_UTILS_H +#include "asset_value.h" +#include "value_object.h" +#include "js_utils.h" +namespace OHOS::AppDataMgrJsKit { +namespace JSUtils { +using Asset = OHOS::NativeRdb::AssetValue; +template<> +int32_t Convert2Value(napi_env env, napi_value input, Asset &output); +template<> +napi_value Convert2JSValue(napi_env env, const Asset &value); +}; // namespace JSUtils +} // namespace OHOS::AppDataMgrJsKit +#endif // RDB_JSKIT_NAPI_RDB_JS_UTILS_H diff --git a/relational_store/frameworks/js/napi/rdb/include/napi_rdb_store.h b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_store.h index 9302486ee8d53448f38d78fb7b79abf77012dece..7cfcc6fbcdd9a4cf8e6188b85be5cb389e81ba8c 100644 --- a/relational_store/frameworks/js/napi/rdb/include/napi_rdb_store.h +++ b/relational_store/frameworks/js/napi/rdb/include/napi_rdb_store.h @@ -49,10 +49,8 @@ private: static napi_value Insert(napi_env env, napi_callback_info info); static napi_value BatchInsert(napi_env env, napi_callback_info info); static napi_value Query(napi_env env, napi_callback_info info); - static napi_value RemoteQuery(napi_env env, napi_callback_info info); static napi_value QuerySql(napi_env env, napi_callback_info info); static napi_value ExecuteSql(napi_env env, napi_callback_info info); - static napi_value Backup(napi_env env, napi_callback_info info); static napi_value Count(napi_env env, napi_callback_info info); static napi_value Replace(napi_env env, napi_callback_info info); static napi_value Attach(napi_env env, napi_callback_info info); @@ -68,7 +66,6 @@ private: static napi_value IsOpen(napi_env env, napi_callback_info info); static napi_value GetVersion(napi_env env, napi_callback_info info); static napi_value SetVersion(napi_env env, napi_callback_info info); - static napi_value Restore(napi_env env, napi_callback_info info); static napi_value SetDistributedTables(napi_env env, napi_callback_info info); static napi_value ObtainDistributedTableName(napi_env env, napi_callback_info info); static napi_value Sync(napi_env env, napi_callback_info info); diff --git a/relational_store/frameworks/js/napi/rdb/mock/include/napi_rdb_store.h b/relational_store/frameworks/js/napi/rdb/mock/include/napi_rdb_store.h index b0bad0952276bedf5a590b51edfa3e6a9cc0c772..f0f862bb076dbf812ad70ea81275f444326450f1 100644 --- a/relational_store/frameworks/js/napi/rdb/mock/include/napi_rdb_store.h +++ b/relational_store/frameworks/js/napi/rdb/mock/include/napi_rdb_store.h @@ -49,7 +49,6 @@ private: static napi_value Query(napi_env env, napi_callback_info info); static napi_value QuerySql(napi_env env, napi_callback_info info); static napi_value ExecuteSql(napi_env env, napi_callback_info info); - static napi_value Backup(napi_env env, napi_callback_info info); static napi_value Count(napi_env env, napi_callback_info info); static napi_value Replace(napi_env env, napi_callback_info info); static napi_value Attach(napi_env env, napi_callback_info info); @@ -65,7 +64,6 @@ private: static napi_value IsOpen(napi_env env, napi_callback_info info); static napi_value GetVersion(napi_env env, napi_callback_info info); static napi_value SetVersion(napi_env env, napi_callback_info info); - static napi_value Restore(napi_env env, napi_callback_info info); std::mutex mutex_; std::shared_ptr rdbStore_; }; diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_js_utils.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_js_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6415eae6d90fe4b9838a85776b9731837430d09 --- /dev/null +++ b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_js_utils.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "napi_rdb_js_utils.h" +namespace OHOS::AppDataMgrJsKit { +namespace JSUtils { +template<> +int32_t Convert2Value(napi_env env, napi_value input, Asset &output) +{ + return nullptr; +} +template<> +napi_value Convert2JSValue(napi_env env, const Asset &value) +{ + return nullptr; +} +}; // namespace JSUtils +} // namespace OHOS::AppDataMgrJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_predicates.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_predicates.cpp index aa59249b448313f358599ac3bc12da9775fc0af9..541607578f28687aac2b44834491be433453a245 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_predicates.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_predicates.cpp @@ -128,7 +128,11 @@ napi_value RdbPredicatesProxy::InnerNew(napi_env env, napi_callback_info info, i std::string tableName = JSUtils::Convert2String(env, args[0]); RDB_NAPI_ASSERT_FROMV9( env, !tableName.empty(), std::make_shared("name", "a non empty string."), version); - auto *proxy = new RdbPredicatesProxy(tableName); + auto *proxy = new (std::nothrow) RdbPredicatesProxy(tableName); + if (proxy == nullptr) { + LOG_ERROR("RdbPredicatesProxy::InnerNew new failed, proxy is nullptr"); + return nullptr; + } napi_status status = napi_wrap(env, thiz, proxy, RdbPredicatesProxy::Destructor, nullptr, nullptr); if (status != napi_ok) { LOG_ERROR("RdbPredicatesProxy::InnerNew napi_wrap failed! napi_status:%{public}d!", status); diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store.cpp index e96585c44b49b57eac8afdedb6924f92ad585ff8..96a498ed7e5610ffcb06a6e5182fcaa49d09b2b2 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store.cpp @@ -157,12 +157,8 @@ void RdbStoreProxy::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("batchInsert", BatchInsert), DECLARE_NAPI_FUNCTION("querySql", QuerySql), DECLARE_NAPI_FUNCTION("query", Query), -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) - DECLARE_NAPI_FUNCTION("remoteQuery", RemoteQuery), -#endif DECLARE_NAPI_FUNCTION("executeSql", ExecuteSql), DECLARE_NAPI_FUNCTION("replace", Replace), - DECLARE_NAPI_FUNCTION("backup", Backup), DECLARE_NAPI_FUNCTION("count", Count), DECLARE_NAPI_FUNCTION("addAttach", Attach), DECLARE_NAPI_FUNCTION("beginTransaction", BeginTransaction), @@ -171,7 +167,6 @@ void RdbStoreProxy::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("queryByStep", QueryByStep), DECLARE_NAPI_FUNCTION("getVersion", GetVersion), DECLARE_NAPI_FUNCTION("setVersion", SetVersion), - DECLARE_NAPI_FUNCTION("restore", Restore), DECLARE_NAPI_GETTER("isInTransaction", IsInTransaction), DECLARE_NAPI_GETTER("isOpen", IsOpen), DECLARE_NAPI_GETTER("path", GetPath), @@ -757,45 +752,6 @@ napi_value RdbStoreProxy::Query(napi_env env, napi_callback_info info) return AsyncCall::Call(env, context); } -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) -napi_value RdbStoreProxy::RemoteQuery(napi_env env, napi_callback_info info) -{ - LOG_DEBUG("RdbStoreProxy::RemoteQuery start"); - auto context = std::make_shared(); - auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int { - std::shared_ptr paramNumError = std::make_shared("4 or 5"); - RDB_CHECK_RETURN_CALL_RESULT(argc == 4 || argc == 5, context->SetError(paramNumError)); - RDB_ASYNC_PARAM_CHECK_FUNCTION(ParseDevice(env, argv[0], context)); - RDB_ASYNC_PARAM_CHECK_FUNCTION(ParseTableName(env, argv[1], context)); - RDB_ASYNC_PARAM_CHECK_FUNCTION(ParsePredicates(env, argv[2], context)); - RDB_ASYNC_PARAM_CHECK_FUNCTION(ParseColumns(env, argv[3], context)); - ParserThis(env, self, context); - return OK; - }; - auto exec = [context]() { - LOG_DEBUG("RdbStoreProxy::RemoteQuery Async"); - RdbStoreProxy *obj = reinterpret_cast(context->boundObj); - context->newResultSet = - obj->rdbStore_->RemoteQuery(context->device, *(context->rdbPredicates), context->columns); - LOG_DEBUG("RdbStoreProxy::RemoteQuery result is nullptr ? %{public}d", (context->newResultSet == nullptr)); - return (context->newResultSet != nullptr) ? OK : ERR; - }; - auto output = [context](napi_env env, napi_value &result) -> int { - if (context->newResultSet == nullptr) { - LOG_DEBUG("RdbStoreProxy::RemoteQuery result is nullptr"); - return ERR; - } - result = ResultSetProxy::NewInstance(env, context->newResultSet, context->apiversion); - LOG_DEBUG("RdbStoreProxy::RemoteQuery end"); - return (result != nullptr) ? OK : ERR; - }; - context->SetAction(env, info, input, exec, output); - - RDB_CHECK_RETURN_NULLPTR(context->error == nullptr || context->error->GetCode() == OK); - return AsyncCall::Call(env, context); -} -#endif - napi_value RdbStoreProxy::QuerySql(napi_env env, napi_callback_info info) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); @@ -947,35 +903,6 @@ napi_value RdbStoreProxy::Replace(napi_env env, napi_callback_info info) return AsyncCall::Call(env, context); } -napi_value RdbStoreProxy::Backup(napi_env env, napi_callback_info info) -{ - LOG_DEBUG("RdbStoreProxy::Backup start"); - auto context = std::make_shared(); - auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int { - std::shared_ptr paramNumError = std::make_shared("1 or 2"); - RDB_CHECK_RETURN_CALL_RESULT(argc == 1 || argc == 2, context->SetError(paramNumError)); - RDB_ASYNC_PARAM_CHECK_FUNCTION(ParseTableName(env, argv[0], context)); - ParserThis(env, self, context); - return OK; - }; - auto exec = [context]() { - LOG_DEBUG("RdbStoreProxy::Backup Async"); - RdbStoreProxy *obj = reinterpret_cast(context->boundObj); - int errCode = obj->rdbStore_->Backup(context->tableName, context->newKey); - LOG_DEBUG("RdbStoreProxy::Backup errCode is: %{public}d", errCode); - return (errCode == E_OK) ? OK : ERR; - }; - auto output = [context](napi_env env, napi_value &result) -> int { - napi_status status = napi_get_undefined(env, &result); - LOG_DEBUG("RdbStoreProxy::Backup end"); - return (status == napi_ok) ? OK : ERR; - }; - context->SetAction(env, info, input, exec, output); - - RDB_CHECK_RETURN_NULLPTR(context->error == nullptr || context->error->GetCode() == OK); - return AsyncCall::Call(env, context); -} - napi_value RdbStoreProxy::Attach(napi_env env, napi_callback_info info) { LOG_DEBUG("RdbStoreProxy::Attach start"); @@ -1171,36 +1098,6 @@ napi_value RdbStoreProxy::SetVersion(napi_env env, napi_callback_info info) return nullptr; } -napi_value RdbStoreProxy::Restore(napi_env env, napi_callback_info info) -{ - LOG_DEBUG("RdbStoreProxy::Restore start"); - auto context = std::make_shared(); - auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> int { - std::shared_ptr paramNumError = std::make_shared("1 or 2"); - RDB_CHECK_RETURN_CALL_RESULT(argc == 1 || argc == 2, context->SetError(paramNumError)); - RDB_ASYNC_PARAM_CHECK_FUNCTION(ParseSrcName(env, argv[0], context)); - ParserThis(env, self, context); - return OK; - }; - auto exec = [context]() { - LOG_DEBUG("RdbStoreProxy::Restore Async"); - RdbStoreProxy *obj = reinterpret_cast(context->boundObj); - int errCode = 0; - errCode = obj->rdbStore_->Restore(context->srcName, context->newKey); - LOG_DEBUG("RdbStoreProxy::Restore errCode is : %{public}d", errCode); - return (errCode == E_OK) ? OK : ERR; - }; - auto output = [context](napi_env env, napi_value &result) -> int { - napi_status status = napi_get_undefined(env, &result); - LOG_DEBUG("RdbStoreProxy::Restore end"); - return (status == napi_ok) ? OK : ERR; - }; - context->SetAction(env, info, input, exec, output); - - RDB_CHECK_RETURN_NULLPTR(context->error == nullptr || context->error->GetCode() == OK); - return AsyncCall::Call(env, context); -} - #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) napi_value RdbStoreProxy::SetDistributedTables(napi_env env, napi_callback_info info) { @@ -1216,9 +1113,9 @@ napi_value RdbStoreProxy::SetDistributedTables(napi_env env, napi_callback_info auto exec = [context]() { LOG_DEBUG("RdbStoreProxy::SetDistributedTables Async"); RdbStoreProxy *obj = reinterpret_cast(context->boundObj); - bool res = obj->rdbStore_->SetDistributedTables(context->tablesName); + int res = obj->rdbStore_->SetDistributedTables(context->tablesName); LOG_DEBUG("RdbStoreProxy::SetDistributedTables res is : %{public}d", res); - return res ? OK : ERR; + return (res == E_OK || res == E_NOT_SUPPORTED) ? OK : ERR; }; auto output = [context](napi_env env, napi_value &result) -> int { napi_status status = napi_get_undefined(env, &result); @@ -1246,8 +1143,10 @@ napi_value RdbStoreProxy::ObtainDistributedTableName(napi_env env, napi_callback auto exec = [context]() { LOG_DEBUG("RdbStoreProxy::ObtainDistributedTableName Async"); RdbStoreProxy *obj = reinterpret_cast(context->boundObj); - auto name = obj->rdbStore_->ObtainDistributedTableName(context->device, context->tableName); - LOG_INFO("RdbStoreProxy::ObtainDistributedTableName name is empty ? : %{public}d", name.empty()); + int errCode = E_ERROR; + auto name = obj->rdbStore_->ObtainDistributedTableName(context->device, context->tableName, errCode); + LOG_INFO("RdbStoreProxy::ObtainDistributedTableName name is empty ? : %{public}d, errCode is %{public}d", + name.empty(), errCode); context->tableName = name; return name.empty() ? ERR : OK; }; @@ -1281,10 +1180,10 @@ napi_value RdbStoreProxy::Sync(napi_env env, napi_callback_info info) SyncOption option; option.mode = static_cast(context->enumArg); option.isBlock = true; - bool res = obj->rdbStore_->Sync(option, *context->predicatesProxy->GetPredicates(), + int res = obj->rdbStore_->Sync(option, *context->predicatesProxy->GetPredicates(), [context](const SyncResult &result) { context->syncResult = result; }); LOG_INFO("RdbStoreProxy::Sync res is : %{public}d", res); - return res ? OK : ERR; + return res == E_OK ? OK : ERR; }; auto output = [context](napi_env env, napi_value &result) -> int { result = JSUtils::Convert2JSValue(env, context->syncResult); @@ -1329,7 +1228,8 @@ void RdbStoreProxy::OnDataChangeEvent(napi_env env, size_t argc, napi_value *arg SubscribeOption option; option.mode = static_cast(mode); auto observer = std::make_shared(env, argv[1]); - if (!rdbStore_->Subscribe(option, observer.get())) { + int errCode = rdbStore_->Subscribe(option, observer.get()); + if (errCode != E_OK) { LOG_ERROR("RdbStoreProxy::OnDataChangeEvent: subscribe failed"); return; } diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_helper.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_helper.cpp index 64e2aa2e69a6b2c4f52a592ce7dc4d8665c911d0..ed233346dfd598813722f45c5289474ac2e926e8 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_helper.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_helper.cpp @@ -294,7 +294,7 @@ int ParseIsEncrypt(const napi_env &env, const napi_value &object, std::shared_pt napi_status status = napi_get_named_property(env, object, "encrypt", &value); if (status == napi_ok && value != nullptr) { bool isEncrypt = false; - JSUtils::Convert2Bool(env, value, isEncrypt); + JSUtils::Convert2Value(env, value, isEncrypt); context->config.SetEncryptStatus(isEncrypt); } return OK; @@ -451,6 +451,7 @@ napi_value InnerGetRdbStore(napi_env env, napi_callback_info info, std::shared_p int errCode = OK; DefaultOpenCallback callback; context->proxy = RdbHelper::GetRdbStore(context->config, context->version, callback, errCode); + std::shared_ptr dbInvalidError = std::make_shared(); RDB_CHECK_RETURN_CALL_RESULT(errCode == E_OK && context->proxy != nullptr, context->SetError(dbInvalidError)); return (errCode == E_OK) ? OK : ERR; diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_observer.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_observer.cpp index 8df0222ef71692dd9db79d8aecd03c0532af5d1b..8033cd5453f22e313545875c827feb1c2583e599 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_observer.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_rdb_store_observer.cpp @@ -18,7 +18,7 @@ #include "js_logger.h" #include "js_utils.h" -using OHOS::AppDataMgrJsKit::JSUtils; +using namespace OHOS::AppDataMgrJsKit; using OHOS::AppDataMgrJsKit::PREFIX_LABEL; namespace OHOS::RdbJsKit { diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_result_set.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_result_set.cpp index 5ed14e1ecca2025e70f6a45f2adcf59f9f22dbaf..87dd8a47b3f0e7d6d6e9a2867c65f9832b931568 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_result_set.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_result_set.cpp @@ -163,7 +163,11 @@ napi_value ResultSetProxy::InnerInitialize(napi_env env, napi_callback_info info { napi_value self = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); - auto *proxy = new ResultSetProxy(); + auto *proxy = new (std::nothrow) ResultSetProxy(); + if (proxy == nullptr) { + LOG_ERROR("ResultSetProxy::InnerInitialize new failed, proxy is nullptr"); + return nullptr; + } proxy->apiversion = version; auto finalize = [](napi_env env, void *data, void *hint) { ResultSetProxy *proxy = reinterpret_cast(data); diff --git a/relational_store/frameworks/js/napi/rdb/src/napi_values_bucket.cpp b/relational_store/frameworks/js/napi/rdb/src/napi_values_bucket.cpp index 327ad774680935223185ea97b8a93a31caa57792..d12e2b4c92b722e1027f3f55b171d241912634e2 100644 --- a/relational_store/frameworks/js/napi/rdb/src/napi_values_bucket.cpp +++ b/relational_store/frameworks/js/napi/rdb/src/napi_values_bucket.cpp @@ -27,44 +27,9 @@ __attribute__((visibility("default"))) napi_value NAPI_OHOS_Data_RdbJsKit_Values { napi_value ret; NAPI_CALL(env, napi_create_object(env, &ret)); - std::map valuesMap; - valuesBucket.GetAll(valuesMap); - std::map::iterator it; - for (it = valuesMap.begin(); it != valuesMap.end(); ++it) { - std::string key = it->first; - auto valueObject = it->second; - napi_value value = nullptr; - switch (valueObject.GetType()) { - case ValueObjectType::TYPE_NULL: { - value = nullptr; - } break; - case ValueObjectType::TYPE_INT: { - int64_t intVal = 0; - valueObject.GetLong(intVal); - value = JSUtils::Convert2JSValue(env, intVal); - } break; - case ValueObjectType::TYPE_DOUBLE: { - double doubleVal = 0L; - valueObject.GetDouble(doubleVal); - value = JSUtils::Convert2JSValue(env, doubleVal); - } break; - case ValueObjectType::TYPE_BLOB: { - std::vector blobVal; - valueObject.GetBlob(blobVal); - value = JSUtils::Convert2JSValue(env, blobVal); - } break; - case ValueObjectType::TYPE_BOOL: { - bool boolVal = false; - valueObject.GetBool(boolVal); - value = JSUtils::Convert2JSValue(env, boolVal); - } break; - default: { - std::string strVal = ""; - valueObject.GetString(strVal); - value = JSUtils::Convert2JSValue(env, strVal); - } break; - } - NAPI_CALL(env, napi_set_named_property(env, ret, key.c_str(), value)); + for (auto &[key, value]: valuesBucket.values_) { + napi_value jsValue = JSUtils::Convert2JSValue(env, value.value); + NAPI_CALL(env, napi_set_named_property(env, ret, key.c_str(), jsValue)); } return ret; @@ -73,7 +38,11 @@ __attribute__((visibility("default"))) napi_value NAPI_OHOS_Data_RdbJsKit_Values __attribute__((visibility("default"))) ValuesBucket *NAPI_OHOS_Data_RdbJsKit_ValuesBucketProxy_GetNativeObject( napi_env env, napi_value &arg) { - ValuesBucket *valuesBucket = new ValuesBucket; + ValuesBucket *valuesBucket = new (std::nothrow) ValuesBucket; + if (valuesBucket == nullptr) { + LOG_ERROR("ValuesBucket new failed, valuesBucket is nullptr"); + return nullptr; + } napi_value keys = 0; napi_get_property_names(env, arg, &keys); uint32_t arrLen = 0; diff --git a/relational_store/frameworks/js/napi/relationalstore/BUILD.gn b/relational_store/frameworks/js/napi/relationalstore/BUILD.gn index 439a34e4284d41f4c8941d03d723165000b4b65c..e03667fdc1e16536103c3f0d29732881fd9b4076 100644 --- a/relational_store/frameworks/js/napi/relationalstore/BUILD.gn +++ b/relational_store/frameworks/js/napi/relationalstore/BUILD.gn @@ -78,6 +78,7 @@ ohos_shared_library("relationalstore") { "ability_runtime:abilitykit_native", "ability_runtime:napi_base_context", "c_utils:utils", + "common_event_service:cesfwk_innerkits", "hilog_native:libhilog", "hitrace_native:hitrace_meter", "napi:ace_napi", diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h index f0ef6f7d2ca532ccc86778032d55bf7f6db59741..ed704e5e3a4902a4f6a7fbd18458122b42c056ff 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_error.h @@ -36,8 +36,9 @@ const static std::map ERROR_MAPS = { { NativeRdb::E_WAL_SIZE_OVER_LIMIT, "The WAL file size over default limit." }, { NativeRdb::E_EMPTY_FILE_NAME, "Failed to open database by database corrupted." }, { NativeRdb::E_INVALID_FILE_PATH, "Failed to open database by database corrupted" }, + { NativeRdb::E_NOT_SUPPORTED, "Capability not supported" }, { E_RESULT_GOTO_ERROR, "The result set is empty or the specified location is invalid." }, - { E_RESULT_GET_ERROR, "The column value is null or the column type is incompatible." }, + { NativeRdb::E_INVALID_STATEMENT, "The column value is null or the column type is incompatible." }, }; #define RDB_REVT_NOTHING diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..22c5dcc787b6d62ef925c24d7f211ce3eb8c6fde --- /dev/null +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_js_utils.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 RDB_JSKIT_NAPI_RDB_JS_UTILS_H +#define RDB_JSKIT_NAPI_RDB_JS_UTILS_H +#include "asset_value.h" +#include "value_object.h" +#include "js_utils.h" +namespace OHOS::AppDataMgrJsKit { +namespace JSUtils { +using Asset = OHOS::NativeRdb::AssetValue; +template<> +int32_t Convert2Value(napi_env env, napi_value input, Asset &output); +template<> +napi_value Convert2JSValue(napi_env env, const Asset &value); +}; // namespace JSUtils +} // namespace OHOS::AppDataMgrJsKit +#endif // RDB_JSKIT_NAPI_RDB_JS_UTILS_H diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h index 7ee322775dc43d58f438a33c8cade5f0520d76b2..5d10f762f2e81165e3d47dd721ebfdb4403c6f9b 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_rdb_store.h @@ -69,14 +69,15 @@ private: static napi_value SetDistributedTables(napi_env env, napi_callback_info info); static napi_value ObtainDistributedTableName(napi_env env, napi_callback_info info); static napi_value Sync(napi_env env, napi_callback_info info); + static napi_value CloudSync(napi_env env, napi_callback_info info); static napi_value OnEvent(napi_env env, napi_callback_info info); static napi_value OffEvent(napi_env env, napi_callback_info info); static constexpr int MIN_ON_EVENT_ARG_NUM = 2; static constexpr int MAX_ON_EVENT_ARG_NUM = 5; - void OnDataChangeEvent(napi_env env, size_t argc, napi_value *argv); - void OffDataChangeEvent(napi_env env, size_t argc, napi_value *argv); + int OnDataChangeEvent(napi_env env, size_t argc, napi_value *argv); + int OffDataChangeEvent(napi_env env, size_t argc, napi_value *argv); std::mutex mutex_; bool isSystemAppCalled_ = false; diff --git a/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h b/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h index 65b3bda4ecaa73aa6f6b6e0f0d68562e7592bd29..f0118af1546b6b26618500c6ffcee161fede5460 100644 --- a/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h +++ b/relational_store/frameworks/js/napi/relationalstore/include/napi_result_set.h @@ -68,7 +68,9 @@ private: static napi_value GetBlob(napi_env env, napi_callback_info info); static napi_value GetString(napi_env env, napi_callback_info info); static napi_value GetDouble(napi_env env, napi_callback_info info); + static napi_value GetModifyTime(napi_env env, napi_callback_info info); static napi_value IsColumnNull(napi_env env, napi_callback_info info); + static napi_value GetRow(napi_env env, napi_callback_info info); static napi_value IsClosed(napi_env env, napi_callback_info info); static napi_value GetSharedBlockName(napi_env env, napi_callback_info info); diff --git a/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h b/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h index a4add516961f11bc922772514fce05670c25c23a..283e4fd68768ddeca0eae51bee5dfdced0c302af 100644 --- a/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h +++ b/relational_store/frameworks/js/napi/relationalstore/mock/include/napi_result_set.h @@ -66,6 +66,7 @@ private: static napi_value GetString(napi_env env, napi_callback_info info); static napi_value GetDouble(napi_env env, napi_callback_info info); static napi_value IsColumnNull(napi_env env, napi_callback_info info); + static napi_value GetRow(napi_env env, napi_callback_info info); static napi_value IsClosed(napi_env env, napi_callback_info info); static napi_value GetSharedBlockName(napi_env env, napi_callback_info info); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp index 8e970dceb3e27e6d218fd26ceebdfd0b2f19794e..9ec40d65b7d4f20551a64ea578e3d800e1b9b9a7 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_async_call.cpp @@ -75,7 +75,7 @@ void AsyncCall::SetBusinessError(napi_env env, std::shared_ptr error, nap napi_value msg = nullptr; napi_create_object(env, businessError); // if error is not inner error - if (error != nullptr && error->GetCode() != E_INNER_ERROR) { + if (error != nullptr) { napi_create_int32(env, error->GetCode(), &code); napi_create_string_utf8(env, error->GetMessage().c_str(), NAPI_AUTO_LENGTH, &msg); napi_set_named_property(env, *businessError, "code", code); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp index 44c80ca227950fd7f9be61f6efe18aab04224c96..06629ba7246dcf087592f4960703fccf45c91e5b 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_const_properties.cpp @@ -54,6 +54,9 @@ static napi_value ExportSyncMode(napi_env env) SET_NAPI_PROPERTY(syncMode, "SYNC_MODE_PUSH", SyncMode::PUSH); SET_NAPI_PROPERTY(syncMode, "SYNC_MODE_PULL", SyncMode::PULL); + SET_NAPI_PROPERTY(syncMode, "SYNC_MODE_TIME_FIRST", SyncMode::TIME_FIRST); + SET_NAPI_PROPERTY(syncMode, "SYNC_MODE_NATIVE_FIRST", SyncMode::NATIVE_FIRST); + SET_NAPI_PROPERTY(syncMode, "SYNC_MODE_CLOUD_FIRST", SyncMode::CLOUD_FIRST); napi_object_freeze(env, syncMode); return syncMode; } @@ -64,6 +67,7 @@ static napi_value ExportSubscribeType(napi_env env) napi_create_object(env, &subscribeType); SET_NAPI_PROPERTY(subscribeType, "SUBSCRIBE_TYPE_REMOTE", SubscribeMode::REMOTE); + SET_NAPI_PROPERTY(subscribeType, "SUBSCRIBE_TYPE_CLOUD", SubscribeMode::REMOTE); napi_object_freeze(env, subscribeType); return subscribeType; } @@ -81,6 +85,28 @@ static napi_value ExportSecurityLevel(napi_env env) return securityLevel; } #endif +static napi_value ExportProgress(napi_env env) +{ + napi_value progress = nullptr; + napi_create_object(env, &progress); + + SET_NAPI_PROPERTY(progress, "SYNC_BEGIN", 0); + SET_NAPI_PROPERTY(progress, "SYNC_IN_PROGRESS", 1); + SET_NAPI_PROPERTY(progress, "SYNC_FINISH", 2); + napi_object_freeze(env, progress); + return progress; +} + +static napi_value ExportDistributedType(napi_env env) +{ + napi_value distributedType = nullptr; + napi_create_object(env, &distributedType); + + SET_NAPI_PROPERTY(distributedType, "DISTRIBUTED_DEVICE", 0); + SET_NAPI_PROPERTY(distributedType, "DISTRIBUTED_CLOUD", 1); + napi_object_freeze(env, distributedType); + return distributedType; +} static napi_value ExportConflictResolution(napi_env env) { @@ -107,6 +133,8 @@ napi_status InitConstProperties(napi_env env, napi_value exports) DECLARE_NAPI_PROPERTY("SubscribeType", ExportSubscribeType(env)), DECLARE_NAPI_PROPERTY("SecurityLevel", ExportSecurityLevel(env)), #endif + DECLARE_NAPI_PROPERTY("Progress", ExportProgress(env)), + DECLARE_NAPI_PROPERTY("DistributedType", ExportDistributedType(env)), }; size_t count = sizeof(properties) / sizeof(properties[0]); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db0c0f0756745919349ff724b5210ffa2040ee88 --- /dev/null +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_js_utils.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "napi_rdb_js_utils.h" +namespace OHOS::AppDataMgrJsKit { +namespace JSUtils { +template<> +int32_t Convert2Value(napi_env env, napi_value jsValue, Asset &output) +{ + return OK; +} +template<> +napi_value Convert2JSValue(napi_env env, const Asset &value) +{ + return nullptr; +} + +}; // namespace JSUtils +} // namespace OHOS::AppDataMgrJsKit \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp index 4d30a1c5682574e9b1503994ba6d83188199553a..2eb54a2a39fbc6f5b64e0621d79a6be91cb6f070 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_predicates.cpp @@ -101,7 +101,11 @@ napi_value RdbPredicatesProxy::New(napi_env env, napi_callback_info info) RDB_NAPI_ASSERT(env, valueType == napi_string, std::make_shared("name", "not empty")); std::string tableName = JSUtils::Convert2String(env, args[0]); RDB_NAPI_ASSERT(env, !tableName.empty(), std::make_shared("name", "not empty")); - auto *proxy = new RdbPredicatesProxy(tableName); + auto *proxy = new (std::nothrow) RdbPredicatesProxy(tableName); + if (proxy == nullptr) { + LOG_ERROR("RdbPredicatesProxy::New new failed, proxy is nullptr"); + return nullptr; + } napi_status status = napi_wrap(env, thiz, proxy, RdbPredicatesProxy::Destructor, nullptr, nullptr); if (status != napi_ok) { LOG_ERROR("RdbPredicatesProxy::New napi_wrap failed! napi_status:%{public}d!", status); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp index c10e46ba782e89171a015f2d4b7322179d006e37..885be3c7d8a0630b3329152e638898af507f7346 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store.cpp @@ -81,7 +81,7 @@ struct RdbStoreContext : public Context { std::shared_ptr rdbPredicates = nullptr; RdbStoreContext() - : predicatesProxy(nullptr), int64Output(0), intOutput(0), enumArg(0), + : predicatesProxy(nullptr), int64Output(0), intOutput(0), enumArg(-1), conflictResolution(NativeRdb::ConflictResolution::ON_CONFLICT_NONE) { } @@ -169,6 +169,7 @@ void RdbStoreProxy::Init(napi_env env, napi_value exports) DECLARE_NAPI_FUNCTION("setDistributedTables", SetDistributedTables), DECLARE_NAPI_FUNCTION("obtainDistributedTableName", ObtainDistributedTableName), DECLARE_NAPI_FUNCTION("sync", Sync), + DECLARE_NAPI_FUNCTION("cloudSync", CloudSync), DECLARE_NAPI_FUNCTION("on", OnEvent), DECLARE_NAPI_FUNCTION("off", OffEvent), #endif @@ -276,7 +277,11 @@ int ParseTablesName(const napi_env &env, const napi_value &arg, std::shared_ptr< int ParseSyncModeArg(const napi_env &env, const napi_value &arg, std::shared_ptr context) { - napi_get_value_int32(env, arg, &context->enumArg); + napi_valuetype type = napi_undefined; + napi_typeof(env, arg, &type); + CHECK_RETURN_SET(type == napi_number, std::make_shared("mode", "a SyncMode Type.")); + napi_status status = napi_get_value_int32(env, arg, &context->enumArg); + CHECK_RETURN_SET(status == napi_ok, std::make_shared("mode", "a SyncMode Type.")); bool checked = context->enumArg == 0 || context->enumArg == 1; CHECK_RETURN_SET(checked, std::make_shared("mode", "a SyncMode.")); @@ -622,10 +627,11 @@ napi_value RdbStoreProxy::RemoteQuery(napi_env env, napi_callback_info info) auto exec = [context]() -> int { LOG_DEBUG("RdbStoreProxy::RemoteQuery Async"); RdbStoreProxy *obj = reinterpret_cast(context->boundObj); + int errCode = E_ERROR; context->newResultSet = - obj->rdbStore_->RemoteQuery(context->device, *(context->rdbPredicates), context->columns); - LOG_DEBUG("RdbStoreProxy::RemoteQuery result is nullptr ? %{public}d", (context->newResultSet == nullptr)); - return (context->newResultSet != nullptr) ? E_OK : E_ERROR; + obj->rdbStore_->RemoteQuery(context->device, *(context->rdbPredicates), context->columns, errCode); + LOG_DEBUG("RemoteQuerry ret is %{public}d.", errCode); + return errCode; }; auto output = [context](napi_env env, napi_value &result) { result = ResultSetProxy::NewInstance(env, context->newResultSet); @@ -699,35 +705,10 @@ int ParseBindArgs(const napi_env &env, const napi_value &arg, std::shared_ptr(std::to_string(i), "a correct boolean")); - context->bindArgs.push_back(ValueObject(value)); - } break; - case napi_number: { - double value; - int32_t ret = JSUtils::Convert2Double(env, element, value); - CHECK_RETURN_SET(ret == OK, std::make_shared(std::to_string(i), "a correct number")); - context->bindArgs.push_back(ValueObject(value)); - } break; - case napi_null: { - context->bindArgs.push_back(ValueObject()); - } break; - case napi_string: { - context->bindArgs.push_back(ValueObject(JSUtils::Convert2String(env, element, false))); - } break; - case napi_object: { - std::vector value; - int32_t ret = JSUtils::Convert2U8Vector(env, element, value); - CHECK_RETURN_SET(ret == OK, std::make_shared(std::to_string(i), "Uint8Array")); - context->bindArgs.push_back(ValueObject(value)); - } break; - default: { - CHECK_RETURN_SET(false, std::make_shared(std::to_string(i), "a valid ValueType")); - } break; - } + ValueObject valueObject; + int32_t ret = JSUtils::Convert2Value(env, element, valueObject.value); + CHECK_RETURN_SET(ret == OK, std::make_shared(std::to_string(i), "ValueObject")); + context->bindArgs.push_back(std::move(valueObject)); } return OK; } @@ -1061,7 +1042,7 @@ napi_value RdbStoreProxy::SetDistributedTables(napi_env env, napi_callback_info auto exec = [context]() -> int { LOG_DEBUG("RdbStoreProxy::SetDistributedTables Async"); RdbStoreProxy *obj = reinterpret_cast(context->boundObj); - return obj->rdbStore_->SetDistributedTables(context->tablesNames) ? E_OK : E_ERROR; + return obj->rdbStore_->SetDistributedTables(context->tablesNames); }; auto output = [context](napi_env env, napi_value &result) { napi_status status = napi_get_undefined(env, &result); @@ -1087,8 +1068,9 @@ napi_value RdbStoreProxy::ObtainDistributedTableName(napi_env env, napi_callback auto exec = [context]() -> int { LOG_DEBUG("RdbStoreProxy::ObtainDistributedTableName Async"); RdbStoreProxy *obj = reinterpret_cast(context->boundObj); - context->tableName = obj->rdbStore_->ObtainDistributedTableName(context->device, context->tableName); - return context->tableName.empty() ? E_OK : E_ERROR; + int errCode = E_ERROR; + context->tableName = obj->rdbStore_->ObtainDistributedTableName(context->device, context->tableName, errCode); + return errCode; }; auto output = [context](napi_env env, napi_value &result) { std::string table = context->tableName; @@ -1118,10 +1100,8 @@ napi_value RdbStoreProxy::Sync(napi_env env, napi_callback_info info) SyncOption option; option.mode = static_cast(context->enumArg); option.isBlock = true; - bool res = obj->rdbStore_->Sync(option, *context->predicatesProxy->GetPredicates(), + return obj->rdbStore_->Sync(option, *context->predicatesProxy->GetPredicates(), [context](const SyncResult &result) { context->syncResult = result; }); - LOG_INFO("RdbStoreProxy::Sync res is : %{public}d", res); - return res ? E_OK : E_ERROR; }; auto output = [context](napi_env env, napi_value &result) { result = JSUtils::Convert2JSValue(env, context->syncResult); @@ -1134,26 +1114,31 @@ napi_value RdbStoreProxy::Sync(napi_env env, napi_callback_info info) return AsyncCall::Call(env, context); } -void RdbStoreProxy::OnDataChangeEvent(napi_env env, size_t argc, napi_value *argv) +napi_value RdbStoreProxy::CloudSync(napi_env env, napi_callback_info info) +{ + return nullptr; +} + +int RdbStoreProxy::OnDataChangeEvent(napi_env env, size_t argc, napi_value *argv) { napi_valuetype type; napi_typeof(env, argv[0], &type); if (type != napi_number) { LOG_ERROR("RdbStoreProxy::OnDataChangeEvent: first argument is not number"); - return; + return ERR; } int32_t mode = SubscribeMode::SUBSCRIBE_MODE_MAX; napi_get_value_int32(env, argv[0], &mode); if (mode < 0 || mode >= SubscribeMode::SUBSCRIBE_MODE_MAX) { LOG_ERROR("RdbStoreProxy::OnDataChangeEvent: first argument value is invalid"); - return; + return ERR; } LOG_INFO("RdbStoreProxy::OnDataChangeEvent: mode=%{public}d", mode); napi_typeof(env, argv[1], &type); if (type != napi_function) { LOG_ERROR("RdbStoreProxy::OnDataChangeEvent: second argument is not function"); - return; + return ERR; } std::lock_guard lockGuard(mutex_); @@ -1162,39 +1147,38 @@ void RdbStoreProxy::OnDataChangeEvent(napi_env env, size_t argc, napi_value *arg }); if (result) { LOG_ERROR("RdbStoreProxy::OnDataChangeEvent: duplicate subscribe"); - return; + return ERR; } SubscribeOption option; option.mode = static_cast(mode); auto observer = std::make_shared(env, argv[1]); - if (!rdbStore_->Subscribe(option, observer.get())) { - LOG_ERROR("RdbStoreProxy::OnDataChangeEvent: subscribe failed"); - return; - } + int errCode = rdbStore_->Subscribe(option, observer.get()); + LOG_DEBUG("Subscribe ret is %{public}d.", errCode); + RDB_NAPI_ASSERT_BASE(env, errCode == E_OK, std::make_shared(errCode), ERR); observers_[mode].push_back(observer); - LOG_ERROR("RdbStoreProxy::OnDataChangeEvent: subscribe success"); + return OK; } -void RdbStoreProxy::OffDataChangeEvent(napi_env env, size_t argc, napi_value *argv) +int RdbStoreProxy::OffDataChangeEvent(napi_env env, size_t argc, napi_value *argv) { napi_valuetype type; napi_typeof(env, argv[0], &type); if (type != napi_number) { LOG_ERROR("RdbStoreProxy::OffDataChangeEvent: first argument is not number"); - return; + return ERR; } int32_t mode = SubscribeMode::SUBSCRIBE_MODE_MAX; napi_get_value_int32(env, argv[0], &mode); if (mode < 0 || mode >= SubscribeMode::SUBSCRIBE_MODE_MAX) { LOG_ERROR("RdbStoreProxy::OffDataChangeEvent: first argument value is invalid"); - return; + return ERR; } LOG_INFO("RdbStoreProxy::OffDataChangeEvent: mode=%{public}d", mode); napi_typeof(env, argv[1], &type); if (type != napi_function) { LOG_ERROR("RdbStoreProxy::OffDataChangeEvent: second argument is not function"); - return; + return ERR; } SubscribeOption option; @@ -1202,13 +1186,15 @@ void RdbStoreProxy::OffDataChangeEvent(napi_env env, size_t argc, napi_value *ar std::lock_guard lockGuard(mutex_); for (auto it = observers_[mode].begin(); it != observers_[mode].end(); it++) { if (**it == argv[1]) { - rdbStore_->UnSubscribe(option, it->get()); + int errCode = rdbStore_->UnSubscribe(option, it->get()); observers_[mode].erase(it); - LOG_INFO("RdbStoreProxy::OffDataChangeEvent: unsubscribe success"); - return; + LOG_INFO("unsubscribe err is %{public}d.", errCode); + RDB_NAPI_ASSERT_BASE(env, errCode == E_OK, std::make_shared(errCode), ERR); + return OK; } } LOG_INFO("RdbStoreProxy::OffDataChangeEvent: not found"); + return ERR; } napi_value RdbStoreProxy::OnEvent(napi_env env, napi_callback_info info) @@ -1228,7 +1214,9 @@ napi_value RdbStoreProxy::OnEvent(napi_env env, napi_callback_info info) std::string event = JSUtils::Convert2String(env, argv[0]); if (event == "dataChange") { - proxy->OnDataChangeEvent(env, argc - 1, argv + 1); + if (proxy->OnDataChangeEvent(env, argc - 1, argv + 1) != OK) { + return nullptr; + } } LOG_INFO("RdbStoreProxy::OnEvent end"); @@ -1252,7 +1240,9 @@ napi_value RdbStoreProxy::OffEvent(napi_env env, napi_callback_info info) std::string event = JSUtils::Convert2String(env, argv[0]); if (event == "dataChange") { - proxy->OffDataChangeEvent(env, argc - 1, argv + 1); + if (proxy->OffDataChangeEvent(env, argc - 1, argv + 1) != OK) { + return nullptr; + } } LOG_INFO("RdbStoreProxy::OffEvent end"); diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp index 03a4392d87acbd489dac4c98435e8d1c86064593..687057e4270a466c721cf827b8f02389c83b093e 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_helper.cpp @@ -77,7 +77,7 @@ int ParseIsEncrypt(const napi_env &env, const napi_value &object, std::shared_pt napi_status status = napi_get_named_property(env, object, "encrypt", &value); if (status == napi_ok && value != nullptr) { bool isEncrypt = false; - JSUtils::Convert2Bool(env, value, isEncrypt); + JSUtils::Convert2Value(env, value, isEncrypt); context->config.SetEncryptStatus(isEncrypt); } return OK; diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp index 0257e361f68348ffed67687eceb3f88d28840300..a6b20cf6a1e6e138cfe0cd81cb5fe64916d3acfe 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_rdb_store_observer.cpp @@ -18,7 +18,7 @@ #include "js_logger.h" #include "js_utils.h" -using OHOS::AppDataMgrJsKit::JSUtils; +using namespace OHOS::AppDataMgrJsKit; using OHOS::AppDataMgrJsKit::PREFIX_LABEL; namespace OHOS::RelationalStoreJsKit { diff --git a/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp b/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp index ed36e5ad235f7d1522026b92fc277cbbf332af4b..cccb3d9fa33ef8deaa28dd91b40ee58f3df3937b 100644 --- a/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp +++ b/relational_store/frameworks/js/napi/relationalstore/src/napi_result_set.cpp @@ -16,12 +16,14 @@ #include "napi_result_set.h" #include +#include #include "js_logger.h" #include "js_utils.h" #include "napi_rdb_error.h" #include "napi_rdb_trace.h" #include "rdb_errno.h" +#include "value_object.h" #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) #include "rdb_result_set_bridge.h" @@ -32,6 +34,25 @@ using namespace OHOS::NativeRdb; using namespace OHOS::AppDataMgrJsKit; namespace OHOS { +namespace AppDataMgrJsKit { +namespace JSUtils { +template<> +napi_value Convert2JSValue(napi_env env, const RowEntity &rowEntity) +{ + napi_value ret; + NAPI_CALL(env, napi_create_object(env, &ret)); + std::map values; + rowEntity.Get(values); + napi_value value = nullptr; + for (auto const &it : values) { + value = JSUtils::Convert2JSValue(env, static_cast(it.second)); + NAPI_CALL(env, napi_set_named_property(env, ret, it.first.c_str(), value)); + } + return ret; +} +} +} + namespace RelationalStoreJsKit { static napi_ref __thread ctorRef_ = nullptr; static const int E_OK = 0; @@ -92,7 +113,9 @@ napi_value ResultSetProxy::GetConstructor(napi_env env) DECLARE_NAPI_FUNCTION("getBlob", GetBlob), DECLARE_NAPI_FUNCTION("getString", GetString), DECLARE_NAPI_FUNCTION("getDouble", GetDouble), + DECLARE_NAPI_FUNCTION("getModifyTime", GetModifyTime), DECLARE_NAPI_FUNCTION("isColumnNull", IsColumnNull), + DECLARE_NAPI_FUNCTION("getRow", GetRow), DECLARE_NAPI_GETTER("columnNames", GetAllColumnNames), DECLARE_NAPI_GETTER("columnCount", GetColumnCount), @@ -115,7 +138,11 @@ napi_value ResultSetProxy::Initialize(napi_env env, napi_callback_info info) { napi_value self = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); - auto *proxy = new ResultSetProxy(); + auto *proxy = new (std::nothrow) ResultSetProxy(); + if (proxy == nullptr) { + LOG_ERROR("ResultSetProxy::Initialize new failed, proxy is nullptr"); + return nullptr; + } auto finalize = [](napi_env env, void *data, void *hint) { ResultSetProxy *proxy = reinterpret_cast(data); delete proxy; @@ -465,6 +492,15 @@ napi_value ResultSetProxy::GetDouble(napi_env env, napi_callback_info info) return JSUtils::Convert2JSValue(env, result); } +napi_value ResultSetProxy::GetModifyTime(napi_env env, napi_callback_info info) +{ + auto resultSet = GetInnerResultSet(env, info); + CHECK_RETURN_NULL(resultSet && resultSet->resultSet_); + std::string modifyTime; + resultSet->resultSet_->GetModifyTime(modifyTime); + return JSUtils::Convert2JSValue(env, modifyTime); +} + napi_value ResultSetProxy::GetColumnIndex(napi_env env, napi_callback_info info) { std::string input; @@ -503,11 +539,22 @@ napi_value ResultSetProxy::IsColumnNull(napi_env env, napi_callback_info info) bool result = false; int errCode = resultSetProxy->resultSet_->IsColumnNull(columnIndex, result); - RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(E_RESULT_GET_ERROR)); + RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); return JSUtils::Convert2JSValue(env, result); } +napi_value ResultSetProxy::GetRow(napi_env env, napi_callback_info info) +{ + ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); + CHECK_RETURN_NULL(resultSetProxy && resultSetProxy->resultSet_); + + RowEntity rowEntity; + int errCode = resultSetProxy->resultSet_->GetRow(rowEntity); + RDB_NAPI_ASSERT(env, errCode == E_OK, std::make_shared(errCode)); + return JSUtils::Convert2JSValue(env, rowEntity); +} + napi_value ResultSetProxy::IsClosed(napi_env env, napi_callback_info info) { ResultSetProxy *resultSetProxy = GetInnerResultSet(env, info); diff --git a/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp b/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp index b4d312e10653c5643a9184c00e832fac85bf79b0..4c56ccbf7075b95e15dfe6a7788505fb06170395 100644 --- a/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp +++ b/relational_store/frameworks/native/appdatafwk/src/shared_block.cpp @@ -37,7 +37,6 @@ SharedBlock::~SharedBlock() if (ashmem_ != nullptr) { ashmem_->UnmapAshmem(); ashmem_->CloseAshmem(); - LOG_WARN("SharedBlock: close ashmem"); } } @@ -350,6 +349,16 @@ int SharedBlock::PutString(uint32_t row, uint32_t column, const char *value, siz return PutBlobOrString(row, column, value, sizeIncludingNull, CELL_UNIT_TYPE_STRING); } +int SharedBlock::PutAsset(uint32_t row, uint32_t column, const void *value, size_t size) +{ + return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSET); +} + +int SharedBlock::PutAssets(uint32_t row, uint32_t column, const void *value, size_t size) +{ + return PutBlobOrString(row, column, value, size, CELL_UNIT_TYPE_ASSETS); +} + int SharedBlock::PutBlobOrString(uint32_t row, uint32_t column, const void *value, size_t size, int32_t type) { if (mReadOnly) { diff --git a/relational_store/frameworks/native/cloud_data/include/cloud_service_proxy.h b/relational_store/frameworks/native/cloud_data/include/cloud_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..7dec3bf806788cc32dbe148eb8f9380126c01794 --- /dev/null +++ b/relational_store/frameworks/native/cloud_data/include/cloud_service_proxy.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_SERVICE_PROXY_H +#define OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_SERVICE_PROXY_H + +#include "icloud_service.h" +#include "iremote_object.h" +#include "iremote_proxy.h" + +namespace OHOS::CloudData { +class CloudServiceProxy: public IRemoteProxy { +public: + explicit CloudServiceProxy(const sptr& object); + virtual ~CloudServiceProxy() = default; + int32_t EnableCloud(const std::string &id, const std::map &switches) override; + int32_t DisableCloud(const std::string &id) override; + int32_t ChangeAppSwitch(const std::string &id, const std::string &bundleName, int32_t appSwitch) override; + int32_t Clean(const std::string &id, const std::map &actions) override; + int32_t NotifyDataChange(const std::string &id, const std::string &bundleName) override; + +private: + sptr remote_; +}; +} // namespace OHOS::CloudData +#endif // OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_SERVICE_PROXY_H diff --git a/datamgr_service/services/distributeddataservice/app/test/unittest/uninstaller_test.cpp b/relational_store/frameworks/native/cloud_data/include/icloud_service.h similarity index 42% rename from datamgr_service/services/distributeddataservice/app/test/unittest/uninstaller_test.cpp rename to relational_store/frameworks/native/cloud_data/include/icloud_service.h index dedd386d560e1b1c1075fe060fa627268ffb879e..a21def4f50c48b9c94c8e38e23636e4a54f6231b 100644 --- a/datamgr_service/services/distributeddataservice/app/test/unittest/uninstaller_test.cpp +++ b/relational_store/frameworks/native/cloud_data/include/icloud_service.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * 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 @@ -13,41 +13,25 @@ * limitations under the License. */ -#include -#include "uninstaller/uninstaller.h" +#ifndef OHOS_DISTRIBUTED_DATA_CLOUD_ICLOUD_SERVICE_H +#define OHOS_DISTRIBUTED_DATA_CLOUD_ICLOUD_SERVICE_H -using namespace testing::ext; -using namespace OHOS::DistributedKv; +#include "cloud_service.h" +#include "iremote_broker.h" -class UninstallerTest : public testing::Test { +namespace OHOS::CloudData { +class ICloudService : public CloudService, public IRemoteBroker { public: - static void SetUpTestCase(void); - static void TearDownTestCase(void); - void SetUp(); - void TearDown(); + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CloudData.CloudServer"); }; -void UninstallerTest::SetUpTestCase(void) -{} - -void UninstallerTest::TearDownTestCase(void) -{} - -void UninstallerTest::SetUp(void) -{} +class IKvStoreDataService : public IRemoteBroker { +public: + enum { GET_FEATURE_INTERFACE = 0 }; -void UninstallerTest::TearDown(void) -{} + virtual sptr GetFeatureInterface(const std::string &name) = 0; -/** - * @tc.name: Test001 - * @tc.desc: test get uninstaller instance. - * @tc.type: FUNC - * @tc.require: SR000DOGUN AR000DPSE9 - * @tc.author: hongbo - */ -HWTEST_F(UninstallerTest, Test001, TestSize.Level0) -{ - auto &unin = Uninstaller::GetInstance(); - unin.Init(nullptr); -} + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.DistributedKv.IKvStoreDataService"); +}; +} // namespace OHOS::CloudData +#endif // OHOS_DISTRIBUTED_DATA_CLOUD_ICLOUD_SERVICE_H diff --git a/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp b/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78823f7f1e4a1cc052ca4968a40581dab3b07b2e --- /dev/null +++ b/relational_store/frameworks/native/cloud_data/src/cloud_manager.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ + +#define LOG_TAG "CloudManagerImpl" + +#include "cloud_manager.h" + +#include "cloud_service_proxy.h" +#include "icloud_service.h" +#include "iservice_registry.h" +#include "itypes_util.h" +#include "log_print.h" +#include "system_ability_definition.h" +namespace OHOS::CloudData { +class DataMgrService : public IRemoteProxy { +public: + explicit DataMgrService(const sptr &impl); + ~DataMgrService() = default; + sptr GetFeatureInterface(const std::string &name) override; +}; + +class CloudDeath : public IRemoteObject::DeathRecipient { +public: + CloudDeath(std::function action) : action_(std::move(action)){}; + void OnRemoteDied(const wptr &object) override + { + if (action_) { + action_(); + } + } + +private: + std::function action_; +}; + +CloudManager &CloudManager::GetInstance() +{ + static CloudManager instance; + return instance; +} + +std::shared_ptr CloudManager::GetCloudService() +{ + std::lock_guard lg(mutex_); + if (cloudService_ != nullptr) { + return cloudService_; + } + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saMgr == nullptr) { + ZLOGE("get system ability manager failed"); + return nullptr; + } + auto dataMgrObject = saMgr->CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); + if (dataMgrObject == nullptr) { + ZLOGE("get distributed data manager failed"); + return nullptr; + } + + sptr dataMgr = new (std::nothrow) DataMgrService(dataMgrObject); + if (dataMgr == nullptr) { + ZLOGE("new CloudDataServiceProxy failed"); + return nullptr; + } + + auto cloudObject = dataMgr->GetFeatureInterface(CloudService::SERVICE_NAME); + if (cloudObject == nullptr) { + ZLOGE("get cloud service failed"); + return nullptr; + } + + cloudObject->AddDeathRecipient(new CloudDeath([this]() { + std::lock_guard lg(mutex_); + cloudService_ = nullptr; + })); + + sptr proxy = new (std::nothrow) CloudServiceProxy(cloudObject); + if (proxy == nullptr) { + return nullptr; + } + + cloudService_ = std::shared_ptr(proxy.GetRefPtr(), [holder = proxy](const auto *) {}); + if (cloudService_ == nullptr) { + return nullptr; + } + return cloudService_; +} + +DataMgrService::DataMgrService(const sptr &impl) : IRemoteProxy(impl) +{ + ZLOGI("init proxy"); +} + +sptr DataMgrService::GetFeatureInterface(const std::string &name) +{ + ZLOGI("%s", name.c_str()); + MessageParcel data; + if (!data.WriteInterfaceToken(DataMgrService::GetDescriptor())) { + ZLOGE("write descriptor failed"); + return nullptr; + } + + if (!ITypesUtil::Marshal(data, name)) { + ZLOGE("write descriptor failed"); + return nullptr; + } + + MessageParcel reply; + MessageOption mo{ MessageOption::TF_SYNC }; + int32_t error = Remote()->SendRequest(GET_FEATURE_INTERFACE, data, reply, mo); + if (error != 0) { + ZLOGE("SendRequest returned %{public}d", error); + return nullptr; + } + + sptr remoteObject; + if (!ITypesUtil::Unmarshal(reply, remoteObject)) { + ZLOGE("remote object is nullptr"); + return nullptr; + } + return remoteObject; +} +} // namespace OHOS::CloudData \ No newline at end of file diff --git a/relational_store/frameworks/native/cloud_data/src/cloud_service_proxy.cpp b/relational_store/frameworks/native/cloud_data/src/cloud_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd2955952e297bd114c74381c714c4dd3d4e1650 --- /dev/null +++ b/relational_store/frameworks/native/cloud_data/src/cloud_service_proxy.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ + +#define LOG_TAG "CloudServiceProxy" + +#include "cloud_service_proxy.h" +#include "itypes_util.h" +#include "log_print.h" + +namespace OHOS::CloudData { +#define IPC_SEND(code, reply, ...) \ +({ \ + int32_t __status = SUCCESS; \ + do { \ + MessageParcel request; \ + if (!request.WriteInterfaceToken(GetDescriptor())) { \ + __status = IPC_PARCEL_ERROR; \ + break; \ + } \ + if (!ITypesUtil::Marshal(request, ##__VA_ARGS__)) { \ + __status = IPC_PARCEL_ERROR; \ + break; \ + } \ + MessageOption option; \ + auto result = remote_->SendRequest((code), request, reply, option); \ + if (result != 0) { \ + __status = IPC_ERROR; \ + break; \ + } \ + \ + ITypesUtil::Unmarshal(reply, __status); \ + } while (0); \ + __status; \ +}) + +CloudServiceProxy::CloudServiceProxy(const sptr &object) + : IRemoteProxy(object) +{ + remote_ = Remote(); +} + +int32_t CloudServiceProxy::EnableCloud(const std::string &id, const std::map &switches) +{ + MessageParcel reply; + int32_t status = IPC_SEND(TRANS_ENABLE_CLOUD, reply, id, switches); + if (status != SUCCESS) { + ZLOGE("status:0x%{public}x id:%{public}.6s size:%{public}zu", status, id.c_str(), switches.size()); + } + return static_cast(status); +} + +int32_t CloudServiceProxy::DisableCloud(const std::string &id) +{ + MessageParcel reply; + int32_t status = IPC_SEND(TRANS_DISABLE_CLOUD, reply, id); + if (status != SUCCESS) { + ZLOGE("status:0x%{public}x id:%{public}.6s", status, id.c_str()); + } + return static_cast(status); +} + +int32_t CloudServiceProxy::ChangeAppSwitch(const std::string &id, const std::string &bundleName, int32_t appSwitch) +{ + MessageParcel reply; + int32_t status = IPC_SEND(TRANS_CHANGE_APP_SWITCH, reply, id, bundleName, appSwitch); + if (status != SUCCESS) { + ZLOGE("status:0x%{public}x id:%{public}.6s bundleName:%{public}s switch:%{public}d", + status, id.c_str(), bundleName.c_str(), appSwitch); + } + return static_cast(status); +} + +int32_t CloudServiceProxy::Clean(const std::string &id, const std::map &actions) +{ + MessageParcel reply; + int32_t status = IPC_SEND(TRANS_CLEAN, reply, id, actions); + if (status != SUCCESS) { + ZLOGE("status:0x%{public}x id:%{public}.6s size:%{public}zu", status, id.c_str(), actions.size()); + } + return static_cast(status); + +} + +int32_t CloudServiceProxy::NotifyDataChange(const std::string &id, const std::string &bundleName) +{ + MessageParcel reply; + int32_t status = IPC_SEND(TRANS_NOTIFY_DATA_CHANGE, reply, id, bundleName); + if (status != SUCCESS) { + ZLOGE("status:0x%{public}x id:%{public}.6s bundleName:%{public}s", status, id.c_str(), bundleName.c_str()); + } + return static_cast(status); +} +} // namespace OHOS::CloudData \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/include/iresult_set.h b/relational_store/frameworks/native/rdb/include/iresult_set.h index 0206aa12367dffcf50336e08a0b0d7f6b2100185..01da83b10a914421582ef2a9aa4e50d3a3940ef2 100644 --- a/relational_store/frameworks/native/rdb/include/iresult_set.h +++ b/relational_store/frameworks/native/rdb/include/iresult_set.h @@ -16,11 +16,11 @@ #ifndef NATIVE_RDB_IRESULT_SET_H #define NATIVE_RDB_IRESULT_SET_H -#include "result_set.h" +#include "abs_result_set.h" #include "iremote_broker.h" namespace OHOS::NativeRdb { -class IResultSet : public ResultSet, public IRemoteBroker { +class IResultSet : public AbsResultSet, public IRemoteBroker { public: virtual ~IResultSet() = default; DECLARE_INTERFACE_DESCRIPTOR(u"OHOS::NativeRdb.IResultSet"); diff --git a/relational_store/frameworks/native/rdb/include/parser.h b/relational_store/frameworks/native/rdb/include/parser.h new file mode 100644 index 0000000000000000000000000000000000000000..906815fed8cade3fe6efe90fce0e08310ec917e7 --- /dev/null +++ b/relational_store/frameworks/native/rdb/include/parser.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_RELATIONAL_STORE_FRAMEWORKS_NATIVE_RDB_PARSER_H +#define OHOS_DISTRIBUTED_DATA_RELATIONAL_STORE_FRAMEWORKS_NATIVE_RDB_PARSER_H +#include "traits.h" +#include "value_object.h" +namespace OHOS::NativeRdb { +class Parser final { +public: + using Asset = ValueObject::Asset; + using Assets = ValueObject::Assets; + template + static bool Convert(T input, std::variant &output); + static size_t ParserRawData(const uint8_t *data, size_t length, Asset &asset); + static size_t ParserRawData(const uint8_t *data, size_t length, Assets &assets); + static std::vector PackageRawData(const Asset &asset); + static std::vector PackageRawData(const Assets &assets); + +private: + template + static bool Get(T &&input, O &output) + { + return false; + } + + template + static bool Get(T &&input, O &output) + { + auto *val = Traits::get_if(&input); + if (val != nullptr) { + output = std::move(*val); + return true; + } + return Get(std::move(input), output); + } +}; + +template +bool Parser::Convert(T input, std::variant &output) +{ + return Get(std::move(input), output); +} +} + +#endif // OHOS_DISTRIBUTED_DATA_RELATIONAL_STORE_FRAMEWORKS_NATIVE_RDB_PARSER_H diff --git a/relational_store/frameworks/native/rdb/include/rdb_manager_impl.h b/relational_store/frameworks/native/rdb/include/rdb_manager_impl.h index f2c20f3eade0c35c0b1211b6140364b0fe6f1668..22150516fcfb14105494405197585946659afc78 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_manager_impl.h +++ b/relational_store/frameworks/native/rdb/include/rdb_manager_impl.h @@ -33,13 +33,12 @@ class RdbServiceProxy; class RdbStoreDataServiceProxy; class RdbManagerImpl { public: - static constexpr int GET_SA_RETRY_TIMES = 3; static constexpr int RETRY_INTERVAL = 1; static constexpr int WAIT_TIME = 2; static RdbManagerImpl &GetInstance(); - std::shared_ptr GetRdbService(const RdbSyncerParam& param); + int GetRdbService(const std::string& bundleName, std::shared_ptr &service); void OnRemoteDied(); @@ -61,8 +60,6 @@ private: ~RdbManagerImpl(); - sptr GetRdbService(); - void ResetServiceHandle(); static std::shared_ptr GetDistributedDataManager(); diff --git a/relational_store/frameworks/native/rdb/include/rdb_security_manager.h b/relational_store/frameworks/native/rdb/include/rdb_security_manager.h index 1bed52ff0f47bf8b47d04809c0dd6a3059da0d7a..c2e880b68ee49f5a9784572657306161b4ed9b0a 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_security_manager.h +++ b/relational_store/frameworks/native/rdb/include/rdb_security_manager.h @@ -49,6 +49,7 @@ public: RdbPassword(); ~RdbPassword(); + bool isKeyExpired = false; bool operator==(const RdbPassword &input) const; bool operator!=(const RdbPassword &input) const; @@ -56,6 +57,7 @@ public: const uint8_t *GetData() const; int SetValue(const uint8_t *inputData, size_t inputSize); int Clear(); + bool IsValid() const; private: static constexpr size_t MAX_PASSWORD_SIZE = 128; @@ -65,18 +67,19 @@ private: class RdbSecurityManager { public: - enum class KeyFileType { PUB_KEY_FILE = 1, PUB_KEY_BAK_FILE }; + enum class KeyFileType { + PUB_KEY_FILE = 1, + PUB_KEY_FILE_NEW_KEY + }; RdbPassword GetRdbPassword(KeyFileType keyFile); void DelRdbSecretDataFile(const std::string &path); - bool CheckKeyDataFileExists(RdbSecurityManager::KeyFileType keyFile); - bool SaveSecretKeyToFile(RdbSecurityManager::KeyFileType keyFile, const std::vector &key); + void DelRdbSecretDataFile(RdbSecurityManager::KeyFileType keyFile); static RdbSecurityManager &GetInstance(); int GetKeyDistributedStatus(KeyFileType keyFile, bool &status); int SetKeyDistributedStatus(KeyFileType keyFile, bool status); void Init(const std::string &bundleName, const std::string &path); - std::vector GenerateRandomNum(int32_t len); - static constexpr int RDB_KEY_SIZE = 32; + void UpdateKeyFile(); private: RdbSecurityManager(); @@ -89,9 +92,14 @@ private: std::vector GenerateRootKeyAlias(const std::string &bundleName); bool InitPath(const std::string &path); void ParsePath(const std::string &path); + bool CheckKeyDataFileExists(RdbSecurityManager::KeyFileType keyFile); + std::vector GenerateRandomNum(int32_t len); + bool SaveSecretKeyToFile(RdbSecurityManager::KeyFileType keyFile); bool SaveSecretKeyToDisk(const std::string &path, RdbSecretKeyData &keyData); + RdbPassword LoadSecretKeyFromFile(KeyFileType keyFile); bool LoadSecretKeyFromDisk(const std::string &keyPath, RdbSecretKeyData &keyData); - bool IsKeyOutOfdate(const time_t &createTime) const; + static bool IsKeyExpired(const time_t &createTime) ; + void GetKeyPath(KeyFileType keyType, std::string &keyPath); int32_t MallocAndCheckBlobData(struct HksBlob *blob, const uint32_t blobSize); int32_t HksLoopUpdate(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, struct HksBlob *outData); @@ -101,7 +109,7 @@ private: const struct HksBlob *cipherText, struct HksBlob *plainText); static constexpr char const *SUFFIX_PUB_KEY = ".pub_key"; - static constexpr char const *SUFFIX_PUB_KEY_BAK = ".pub_key_bak"; + static constexpr char const *SUFFIX_PUB_KEY_NEW = ".pub_key.new"; static constexpr const char *RDB_ROOT_KEY_ALIAS_PREFIX = "DistributedDataRdb"; static constexpr const char *RDB_HKS_BLOB_TYPE_NONCE = "Z5s0Bo571Koq"; static constexpr const char *RDB_HKS_BLOB_TYPE_AAD = "RdbClientAAD"; @@ -109,13 +117,14 @@ private: static const uint32_t MAX_UPDATE_SIZE = 64; static const uint32_t MAX_OUTDATA_SIZE = MAX_UPDATE_SIZE * TIMES; static const uint8_t AEAD_LEN = 16; + static constexpr int RDB_KEY_SIZE = 32; std::string bundleName_; std::string dbDir_; std::string dbName_; std::string dbKeyDir_; std::string keyPath_; - std::string keyBakPath_; + std::string newKeyPath_; static constexpr int HOURS_PER_YEAR = (24 * 365); static constexpr uint8_t UNDISTRIBUTED = 0; diff --git a/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h b/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h index 24651ee6c400afa2f440479074bddd4ab1c22c18..c73873146efaf2e0b4f3bf6fd09bb6ac38195ce7 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h +++ b/relational_store/frameworks/native/rdb/include/rdb_service_proxy.h @@ -33,8 +33,8 @@ public: std::string ObtainDistributedTableName(const std::string& device, const std::string& table) override; - int32_t InitNotifier(const RdbSyncerParam& param); - int32_t InitNotifier(const RdbSyncerParam& param, const sptr notifier) override; + int32_t InitNotifier(const std::string& bundleName); + int32_t InitNotifier(const std::string& bundleName, const sptr ¬ifier) override; int32_t SetDistributedTables(const RdbSyncerParam& param, const std::vector& tables) override; @@ -56,6 +56,8 @@ public: void ImportObservers(ObserverMap& observers); + /*CLoudData*/ + int32_t GetSchema(const std::string &bundleName, const std::string &storeName) override; protected: int32_t DoSync(const RdbSyncerParam& param, const SyncOption& option, const RdbPredicates& predicates, SyncResult& result) override; @@ -88,6 +90,7 @@ private: ObserverMap observers_; sptr notifier_; + sptr remote_; static inline BrokerDelegator delegator_; }; } // namespace OHOS::DistributedRdb diff --git a/relational_store/frameworks/native/rdb/include/rdb_store_impl.h b/relational_store/frameworks/native/rdb/include/rdb_store_impl.h index df19a713c2abf9fde9b88a2ab497ca874029f68b..149ac934ad703d63b5390d992b10a12cceb0732e 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_store_impl.h +++ b/relational_store/frameworks/native/rdb/include/rdb_store_impl.h @@ -26,7 +26,6 @@ #include "rdb_store_config.h" #include "sqlite_connection_pool.h" #include "sqlite_statement.h" -#include "store_session.h" #include "transaction_observer.h" namespace OHOS::NativeRdb { @@ -98,17 +97,17 @@ public: int Delete(int &deletedRows, const AbsRdbPredicates &predicates) override; std::shared_ptr RemoteQuery(const std::string &device, const AbsRdbPredicates &predicates, - const std::vector &columns) override; + const std::vector &columns, int &errCode) override; - bool SetDistributedTables(const std::vector& tables) override; + int SetDistributedTables(const std::vector& tables) override; - std::string ObtainDistributedTableName(const std::string& device, const std::string& table) override; + std::string ObtainDistributedTableName(const std::string& device, const std::string& table, int &errCode) override; - bool Sync(const SyncOption& option, const AbsRdbPredicates& predicate, const SyncCallback& callback) override; + int Sync(const SyncOption& option, const AbsRdbPredicates& predicate, const SyncCallback& callback) override; - bool Subscribe(const SubscribeOption& option, RdbStoreObserver *observer) override; + int Subscribe(const SubscribeOption& option, RdbStoreObserver *observer) override; - bool UnSubscribe(const SubscribeOption& option, RdbStoreObserver *observer) override; + int UnSubscribe(const SubscribeOption& option, RdbStoreObserver *observer) override; // user must use UDID bool DropDeviceData(const std::vector& devices, const DropOption& option) override; @@ -124,8 +123,6 @@ private: SqliteConnectionPool *connectionPool; static const int MAX_IDLE_SESSION_SIZE = 5; std::mutex sessionMutex; - std::map, int>> threadMap; - std::list> idleSessions; bool isOpen; std::string path; std::string orgPath; diff --git a/relational_store/frameworks/native/rdb/include/rdb_types_util.h b/relational_store/frameworks/native/rdb/include/rdb_types_util.h index 018a78f270c0022f0c4678c809779aa84b718e1a..ca4465ae55441990d7ac586aa1cd28d85bd5dbfb 100644 --- a/relational_store/frameworks/native/rdb/include/rdb_types_util.h +++ b/relational_store/frameworks/native/rdb/include/rdb_types_util.h @@ -19,18 +19,25 @@ #include "rdb_types.h" #include "value_object.h" #include "values_bucket.h" +#include "rdb_visibility.h" namespace OHOS::ITypesUtil { using SyncerParam = DistributedRdb::RdbSyncerParam; +using CloudParam = DistributedRdb::CloudParam; using SyncOption = DistributedRdb::SyncOption; using RdbPredicates = DistributedRdb::RdbPredicates; using RdbOperation = DistributedRdb::RdbPredicateOperation; using ValueObject = NativeRdb::ValueObject; using ValuesBucket = NativeRdb::ValuesBucket; +using Asset = NativeRdb::AssetValue; template<> RDB_API_EXPORT bool Marshalling(const SyncerParam &input, MessageParcel &data); template<> RDB_API_EXPORT bool Unmarshalling(SyncerParam &output, MessageParcel &data); template<> +RDB_API_EXPORT bool Marshalling(const CloudParam &input, MessageParcel &data); +template<> +RDB_API_EXPORT bool Unmarshalling(CloudParam &output, MessageParcel &data); +template<> RDB_API_EXPORT bool Marshalling(const SyncOption &input, MessageParcel &data); template<> RDB_API_EXPORT bool Unmarshalling(SyncOption &output, MessageParcel &data); @@ -50,5 +57,9 @@ template<> bool Marshalling(const ValuesBucket &input, MessageParcel &data); template<> bool Unmarshalling(ValuesBucket &output, MessageParcel &data); +template<> +bool Marshalling(const Asset &input, MessageParcel &data); +template<> +bool Unmarshalling(Asset &output, MessageParcel &data); } #endif // DISTRIBUTED_RDB_RDB_TYPES_UTIL_H diff --git a/relational_store/frameworks/native/rdb/include/result_set_proxy.h b/relational_store/frameworks/native/rdb/include/result_set_proxy.h index fe57d8d2f67482c37988651073c044a10a493d2d..60240ab1eddcd6c6caf8162dcccdf0d113c1ddc1 100644 --- a/relational_store/frameworks/native/rdb/include/result_set_proxy.h +++ b/relational_store/frameworks/native/rdb/include/result_set_proxy.h @@ -47,6 +47,7 @@ public: int GetLong(int columnIndex, int64_t &value) override; int GetDouble(int columnIndex, double &value) override; int IsColumnNull(int columnIndex, bool &isNull) override; + int GetRow(RowEntity &rowEntity) override; bool IsClosed() const override; int Close() override; diff --git a/relational_store/frameworks/native/rdb/include/sqlite_config.h b/relational_store/frameworks/native/rdb/include/sqlite_config.h index 607de29e4581da05b0505d96bbe739155a06f0ab..2cc9e0410fac4fe97c55ae461f1b22d4ede2b903 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_config.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_config.h @@ -35,7 +35,7 @@ public: std::string GetSyncMode() const; std::string GetDatabaseFileType() const; bool IsReadOnly() const; - bool IsEncrypt() const; + bool IsAutoEncrypt() const; std::string GetBundleName() const; bool IsCreateNecessary() const; void SetCreateNecessary(bool CreateNecessary); @@ -49,8 +49,12 @@ public: void SetEncryptAlgo(const std::string &encryptAlgo); int GetReadConSize() const; void SetReadConSize(int readConSize); + void SetEncryptKey(const std::vector &encryptKey); + std::vector GetEncryptKey() const; private: + void ClearEncryptKey(); + std::string path; StorageMode storageMode; std::string journalMode; @@ -65,6 +69,7 @@ private: // Encryption bool isEncrypt = false; + std::vector encryptKey_{}; std::string bundleName; bool isCreateNecessary; }; diff --git a/relational_store/frameworks/native/rdb/include/sqlite_connection.h b/relational_store/frameworks/native/rdb/include/sqlite_connection.h index ea9827945043f5244498d58f103b007753a563cb..e44082a3e4e20d550d1ac46cc689133ba2cf8390 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_connection.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_connection.h @@ -64,16 +64,13 @@ private: int Config(const SqliteConfig &config); int SetPageSize(const SqliteConfig &config); int SetEncryptAlgo(const SqliteConfig &config); - int SetEncryptKey(const std::vector &encryptKey); + int SetEncryptKey(const SqliteConfig &config); int SetJournalMode(const SqliteConfig &config); int SetJournalSizeLimit(const SqliteConfig &config); int SetAutoCheckpoint(const SqliteConfig &config); int SetWalSyncMode(const std::string &syncMode); int PrepareAndBind(const std::string &sql, const std::vector &bindArgs); void LimitPermission(const std::string &dbPath) const; - int ManageKey(const SqliteConfig &config); - int InitKey(); - int GetKeyFromFile(); int SetPersistWal(); int SetBusyTimeout(int timeout); diff --git a/relational_store/frameworks/native/rdb/include/sqlite_connection_pool.h b/relational_store/frameworks/native/rdb/include/sqlite_connection_pool.h index 6a283a6101143ff974ac78c7fb9e02a1d2552b00..f3dbc0a81c3b5e7f1a7c6bcf13cecc5de7e0fc6d 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_connection_pool.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_connection_pool.h @@ -44,7 +44,7 @@ public: int ChangeDbFileForRestore(const std::string newPath, const std::string backupPath, const std::vector &newKey); std::stack &getTransactionStack(); - void AcquireTransaction(); + int AcquireTransaction(); void ReleaseTransaction(); private: diff --git a/relational_store/frameworks/native/rdb/include/sqlite_global_config.h b/relational_store/frameworks/native/rdb/include/sqlite_global_config.h index 21edf315c1a19fd1da96f8f8eda19891b05784b9..4138ea18551bc8565ba4d8f92a1bbe4f16746473 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_global_config.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_global_config.h @@ -31,6 +31,7 @@ public: static constexpr int DB_WAL_SIZE_LIMIT = 200 * 1024 * 1024; /* default wal file maximum size : 200M */ static constexpr int WAL_AUTO_CHECKPOINT = 100; /* 100 pages */ static constexpr int APP_DEFAULT_UMASK = 0002; + static constexpr int SQLITE_MAX_COLUMN = 2000; static constexpr char ATTACH_BACKUP_SQL[] = "ATTACH ? AS backup KEY ?"; static constexpr char ATTACH_SQL[] = "ATTACH ? AS ? KEY ?"; static constexpr char EXPORT_SQL[] = "SELECT export_database('backup')"; diff --git a/relational_store/frameworks/native/rdb/include/sqlite_shared_result_set.h b/relational_store/frameworks/native/rdb/include/sqlite_shared_result_set.h index 199653da6190697cc64c3f84a9fc5269b559de04..7928de31297c434d877ed53aa9086872e68b98e1 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_shared_result_set.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_shared_result_set.h @@ -52,7 +52,6 @@ protected: private: int PrepareStep(); - int CheckSession(); void FillSharedBlock(int requiredPos); private: diff --git a/relational_store/frameworks/native/rdb/include/sqlite_statement.h b/relational_store/frameworks/native/rdb/include/sqlite_statement.h index ca4cb1d1753202cc21956053fd8745e1e1cd8530..702f1cb64e99e3fef2ea72fa902a74ec2205e194 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_statement.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_statement.h @@ -40,6 +40,7 @@ public: int GetColumnString(int index, std::string &value) const; int GetColumnLong(int index, int64_t &value) const; int GetColumnDouble(int index, double &value) const; + int GetColumn(int index, ValueObject &value) const; bool IsReadOnly() const; int GetNumParameters(int &numParams) const; sqlite3_stmt *GetSql3Stmt() const @@ -48,6 +49,9 @@ public: } private: + using Asset = ValueObject::Asset; + using Assets = ValueObject::Assets; + int InnerBindArguments(const std::vector &bindArgs) const; std::string sql; sqlite3_stmt *stmtHandle; diff --git a/relational_store/frameworks/native/rdb/include/sqlite_utils.h b/relational_store/frameworks/native/rdb/include/sqlite_utils.h index 0a3941003504b5fa460c9f375095073bd2b951dd..f5264d716eb64c34ced8fedef90cb90cffc4c738 100644 --- a/relational_store/frameworks/native/rdb/include/sqlite_utils.h +++ b/relational_store/frameworks/native/rdb/include/sqlite_utils.h @@ -43,6 +43,7 @@ public: static std::string StrToUpper(std::string s); static bool DeleteFile(const std::string path); static int RenameFile(const std::string srcFile, const std::string destFile); + static std::string Anonymous(const std::string &srcFile); static int GetFileSize(const std::string fileName); private: diff --git a/relational_store/frameworks/native/rdb/include/step_result_set.h b/relational_store/frameworks/native/rdb/include/step_result_set.h index 9a7c1fd8208958362a0f2c8a52e33c5615d07381..7b7cd59c29360d9b90d80d882044f95249a3f280 100644 --- a/relational_store/frameworks/native/rdb/include/step_result_set.h +++ b/relational_store/frameworks/native/rdb/include/step_result_set.h @@ -47,6 +47,9 @@ public: int GetInt(int columnIndex, int &value) override; int GetLong(int columnIndex, int64_t &value) override; int GetDouble(int columnIndex, double &value) override; + int GetAsset(int32_t col, ValueObject::Asset &value) override; + int GetAssets(int32_t col, ValueObject::Assets &value) override; + int GetModifyTime(std::string &modifyTime) override; int IsColumnNull(int columnIndex, bool &isNull) override; bool IsClosed() const override; int Close() override; @@ -54,7 +57,8 @@ public: int PrepareStep(); private: - int CheckSession(); + template + int GetValue(int32_t col, T &value); void Reset(); std::shared_ptr rdb; std::string sql; diff --git a/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h b/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h index efd7f3dddd33cc607856108542e8eeae51649953..765306a8ba1d9240b1be66d612a7d5b64f447d89 100644 --- a/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h +++ b/relational_store/frameworks/native/rdb/mock/include/rdb_store_impl.h @@ -26,7 +26,6 @@ #include "rdb_store_config.h" #include "sqlite_connection_pool.h" #include "sqlite_statement.h" -#include "store_session.h" #include "transaction_observer.h" namespace OHOS::NativeRdb { @@ -104,8 +103,6 @@ private: SqliteConnectionPool *connectionPool; static const int MAX_IDLE_SESSION_SIZE = 5; std::mutex sessionMutex; - std::map, int>> threadMap; - std::list> idleSessions; bool isOpen; std::string path; std::string orgPath; diff --git a/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h b/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h index 1526f86767f757da360c6234f2acc22c2ec6d335..c87cb0abebfd3b05946df79612335befeeb596fc 100644 --- a/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h +++ b/relational_store/frameworks/native/rdb/mock/include/sqlite_connection.h @@ -60,7 +60,7 @@ private: int Config(const SqliteConfig &config); int SetPageSize(const SqliteConfig &config); int SetEncryptAlgo(const SqliteConfig &config); - int SetEncryptKey(const std::vector &encryptKey); + int SetEncryptKey(const SqliteConfig &config); int SetJournalMode(const SqliteConfig &config); int SetJournalSizeLimit(const SqliteConfig &config); int SetAutoCheckpoint(const SqliteConfig &config); diff --git a/relational_store/frameworks/native/rdb/mock/include/sqlite_connection_pool.h b/relational_store/frameworks/native/rdb/mock/include/sqlite_connection_pool.h index 7d02e6846db44fec58d888862cf6055767b5901e..73101e55cd5efefcbf4acb9eec9198329b2734f3 100644 --- a/relational_store/frameworks/native/rdb/mock/include/sqlite_connection_pool.h +++ b/relational_store/frameworks/native/rdb/mock/include/sqlite_connection_pool.h @@ -44,7 +44,7 @@ public: int ChangeDbFileForRestore(const std::string newPath, const std::string backupPath, const std::vector &newKey); std::stack &getTransactionStack(); - void AcquireTransaction(); + int AcquireTransaction(); void ReleaseTransaction(); private: diff --git a/relational_store/frameworks/native/rdb/mock/include/sqlite_global_config.h b/relational_store/frameworks/native/rdb/mock/include/sqlite_global_config.h index a8b1cf24e44a379abfac9693e3a9082ce8e8d4c6..08900d5510b0fbb070c3588b4b7916e2ddae5ae6 100644 --- a/relational_store/frameworks/native/rdb/mock/include/sqlite_global_config.h +++ b/relational_store/frameworks/native/rdb/mock/include/sqlite_global_config.h @@ -32,6 +32,7 @@ public: static constexpr int DB_WAL_SIZE_LIMIT = 200 * 1024 * 1024; /* default wal file maximum size : 200M */ static constexpr int WAL_AUTO_CHECKPOINT = 100; /* 100 pages */ static constexpr int APP_DEFAULT_UMASK = 0002; + static constexpr int SQLITE_MAX_COLUMN = 2000; static constexpr char ATTACH_BACKUP_SQL[] = "ATTACH ? AS backup KEY ?"; static constexpr char ATTACH_SQL[] = "ATTACH ? AS ? KEY ?"; static constexpr char EXPORT_SQL[] = "SELECT export_database('backup')"; diff --git a/relational_store/frameworks/native/rdb/mock/include/sqlite_utils.h b/relational_store/frameworks/native/rdb/mock/include/sqlite_utils.h index c6d5afba28c9a2ec55629874b42caeb4aafca859..577a7f0885e9088d94459db02447635ef73b036e 100644 --- a/relational_store/frameworks/native/rdb/mock/include/sqlite_utils.h +++ b/relational_store/frameworks/native/rdb/mock/include/sqlite_utils.h @@ -42,6 +42,7 @@ public: static std::string StrToUpper(std::string s); static bool DeleteFile(const std::string path); static int RenameFile(const std::string srcFile, const std::string destFile); + static std::string Anonymous(const std::string &srcFile); static int GetFileSize(const std::string fileName); private: diff --git a/relational_store/frameworks/native/rdb/mock/include/step_result_set.h b/relational_store/frameworks/native/rdb/mock/include/step_result_set.h index 209669bcc63a8a702abf6f8205948b045317bb89..85d52516fe20e7dec807597ed8efface1d17c570 100644 --- a/relational_store/frameworks/native/rdb/mock/include/step_result_set.h +++ b/relational_store/frameworks/native/rdb/mock/include/step_result_set.h @@ -54,7 +54,6 @@ public: int PrepareStep(); private: - int CheckSession(); void Reset(); std::shared_ptr rdb; std::string sql; diff --git a/relational_store/frameworks/native/rdb/src/abs_predicates.cpp b/relational_store/frameworks/native/rdb/src/abs_predicates.cpp index 982174cb6921f22d826547412dfcc42bbe34429a..cf34ed33bd96818ba0b36dcdfba20cc9e52fd4d1 100644 --- a/relational_store/frameworks/native/rdb/src/abs_predicates.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_predicates.cpp @@ -98,8 +98,7 @@ AbsPredicates *AbsPredicates::BeginWrap() AbsPredicates *AbsPredicates::EndWrap() { if (!isNeedAnd) { - LOG_WARN("AbsPredicates.endGroup(): you cannot use function or() before end parenthesis,\ - start a AbsPredicates with endGroup(), or use endGroup() right after beginGroup()."); + LOG_WARN("fail to add EndWrap."); return this; } whereClause += " ) "; @@ -109,8 +108,7 @@ AbsPredicates *AbsPredicates::EndWrap() AbsPredicates *AbsPredicates::Or() { if (!isNeedAnd) { - LOG_WARN("QueryImpl.or(): you are starting a sql request with predicate \"or\" or \ - using function or() immediately after another or(). that is ridiculous."); + LOG_WARN("fail to add Or."); return this; } whereClause += " OR "; @@ -121,7 +119,7 @@ AbsPredicates *AbsPredicates::Or() AbsPredicates *AbsPredicates::And() { if (!isNeedAnd) { - LOG_WARN("QueryImpl.and(): you should not start a request with \"and\" or use or() before this function."); + LOG_WARN("fail to add And."); return this; } return this; diff --git a/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp b/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp index 9086980fe97e697f75d1019532cc80b7d43a75cf..4d32ba9a927a67c9808c1d810f20c80c182018ab 100644 --- a/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_rdb_predicates.cpp @@ -18,10 +18,6 @@ #include "abs_rdb_predicates.h" #include "logger.h" #include "rdb_trace.h" -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) -#include "rdb_manager.h" -#include "rdb_service.h" -#endif namespace OHOS::NativeRdb { AbsRdbPredicates::AbsRdbPredicates(std::string tableName) diff --git a/relational_store/frameworks/native/rdb/src/abs_result_set.cpp b/relational_store/frameworks/native/rdb/src/abs_result_set.cpp index c4c0348b520395baa73fe039e5033bdc89071d84..aba2d207ef8336e4aea66cb6a3359317ecca42af 100644 --- a/relational_store/frameworks/native/rdb/src/abs_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_result_set.cpp @@ -24,6 +24,40 @@ namespace OHOS { namespace NativeRdb { +void RowEntity::Put(const std::string &name, const ValueObject &value) +{ + auto it = values_.emplace(name, std::move(value)); + indexs_.push_back(it.first); +} + +ValueObject RowEntity::Get(const std::string &name) const +{ + auto it = values_.find(name); + if (it == values_.end()) { + return ValueObject(); + } + return it->second; +} + +ValueObject RowEntity::Get(int index) const +{ + if (index < 0 || index >= indexs_.size()) { + return ValueObject(); + } + return indexs_[index]->second; +} + +void RowEntity::Get(std::map &outValues) const +{ + outValues = values_; +} + +void RowEntity::Clear() +{ + values_.clear(); + indexs_.clear(); +} + AbsResultSet::AbsResultSet() : rowPos_(INIT_POS), isClosed(false) { } @@ -70,6 +104,61 @@ int AbsResultSet::IsColumnNull(int columnIndex, bool &isNull) return E_OK; } +int AbsResultSet::GetRow(RowEntity &rowEntity) +{ + rowEntity.Clear(); + std::vector columnNames; + int ret = GetAllColumnNames(columnNames); + if (ret != E_OK) { + LOG_ERROR("GetAllColumnNames::ret is %{public}d", ret); + return ret; + } + int columnCount = static_cast(columnNames.size()); + + ColumnType columnType; + for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex) { + ret = GetColumnType(columnIndex, columnType); + if (ret != E_OK) { + LOG_ERROR("GetColumnType::ret is %{public}d", ret); + return ret; + } + switch (columnType) { + case ColumnType::TYPE_NULL: { + rowEntity.Put(columnNames[columnIndex], ValueObject()); + break; + } + case ColumnType::TYPE_INTEGER: { + int64_t value; + GetLong(columnIndex, value); + rowEntity.Put(columnNames[columnIndex], ValueObject(value)); + break; + } + case ColumnType::TYPE_FLOAT: { + double value; + GetDouble(columnIndex, value); + rowEntity.Put(columnNames[columnIndex], ValueObject(value)); + break; + } + case ColumnType::TYPE_STRING: { + std::string value; + GetString(columnIndex, value); + rowEntity.Put(columnNames[columnIndex], ValueObject(value)); + break; + } + case ColumnType::TYPE_BLOB: { + std::vector value; + GetBlob(columnIndex, value); + rowEntity.Put(columnNames[columnIndex], ValueObject(value)); + break; + } + default: { + return E_ERROR; + } + } + } + return E_OK; +} + int AbsResultSet::GoToRow(int position) { return E_OK; @@ -91,7 +180,7 @@ int AbsResultSet::GoTo(int offset) DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int ret = GoToRow(rowPos_ + offset); if (ret != E_OK) { - LOG_WARN("AbsResultSet::GoTo return ret is wrong!"); + LOG_WARN("GoToRow ret is %{public}d", ret); return ret; } return E_OK; @@ -102,7 +191,7 @@ int AbsResultSet::GoToFirstRow() DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int ret = GoToRow(0); if (ret != E_OK) { - LOG_WARN("AbsResultSet::GoToFirstRow return ret is wrong!"); + LOG_WARN("GoToRow ret is %{public}d", ret); return ret; } return E_OK; @@ -114,13 +203,13 @@ int AbsResultSet::GoToLastRow() int rowCnt = 0; int ret = GetRowCount(rowCnt); if (ret != E_OK) { - LOG_WARN("AbsResultSet::GoToLastRow return GetRowCount::ret is wrong!"); + LOG_ERROR("Failed to GetRowCount, ret is %{public}d", ret); return ret; } ret = GoToRow(rowCnt - 1); if (ret != E_OK) { - LOG_WARN("AbsResultSet::GoToLastRow return GoToRow::ret is wrong!"); + LOG_WARN("GoToRow ret is %{public}d", ret); return ret; } return E_OK; @@ -131,7 +220,7 @@ int AbsResultSet::GoToNextRow() DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int ret = GoToRow(rowPos_ + 1); if (ret != E_OK) { - LOG_WARN("AbsResultSet::GoToNextRow return GoToRow::ret is wrong!"); + LOG_WARN("GoToRow ret is %{public}d", ret); return ret; } return E_OK; @@ -142,7 +231,7 @@ int AbsResultSet::GoToPreviousRow() DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); int ret = GoToRow(rowPos_ - 1); if (ret != E_OK) { - LOG_WARN("AbsResultSet::GoToPreviousRow return GoToRow::ret is wrong!"); + LOG_WARN("GoToRow ret is %{public}d", ret); return ret; } return E_OK; @@ -159,7 +248,7 @@ int AbsResultSet::IsAtLastRow(bool &result) int rowCnt = 0; int ret = GetRowCount(rowCnt); if (ret != E_OK) { - LOG_ERROR("AbsResultSet::IsAtLastRow return GetRowCount::ret is wrong!"); + LOG_ERROR("Failed to GetRowCount, ret is %{public}d", ret); return ret; } result = (rowPos_ == (rowCnt - 1)); @@ -175,9 +264,9 @@ int AbsResultSet::IsStarted(bool &result) const int AbsResultSet::IsEnded(bool &result) { int rowCnt = 0; - int ret = GetRowCount(rowCnt); + int ret = GetRowCount(rowCnt); if (ret != E_OK) { - LOG_ERROR("AbsResultSet::IsEnded return GetRowCount::ret is wrong!"); + LOG_ERROR("Failed to GetRowCount, ret is %{public}d", ret); return ret; } result = (rowCnt == 0) ? true : (rowPos_ == rowCnt); @@ -193,7 +282,7 @@ int AbsResultSet::GetColumnCount(int &count) std::vector columnNames; int ret = GetAllColumnNames(columnNames); if (ret != E_OK) { - LOG_ERROR("AbsResultSet::GetColumnCount return GetAllColumnNames::ret is wrong!"); + LOG_ERROR("Failed to GetAllColumnNames, ret is %{public}d", ret); return ret; } columnCount_ = static_cast(columnNames.size()); @@ -218,7 +307,7 @@ int AbsResultSet::GetColumnIndex(const std::string &columnName, int &columnIndex std::vector columnNames; int ret = GetAllColumnNames(columnNames); if (ret != E_OK) { - LOG_ERROR("AbsResultSet::GetColumnIndex return GetAllColumnNames::ret is wrong!"); + LOG_ERROR("Failed to GetAllColumnNames, ret is %{public}d", ret); return ret; } @@ -233,6 +322,7 @@ int AbsResultSet::GetColumnIndex(const std::string &columnName, int &columnIndex columnIndex++; } columnIndex = -1; + LOG_WARN("columnName %{public}s is not in resultSet", columnName.c_str()); return E_ERROR; } @@ -241,10 +331,11 @@ int AbsResultSet::GetColumnName(int columnIndex, std::string &columnName) int rowCnt = 0; int ret = GetColumnCount(rowCnt); if (ret != E_OK) { - LOG_ERROR("AbsResultSet::GetColumnName return GetColumnCount::ret is wrong!"); + LOG_ERROR("Failed to GetColumnCount, ret is %{public}d", ret); return ret; } if (columnIndex >= rowCnt || columnIndex < 0) { + LOG_ERROR("invalid column columnIndex as %{public}d", columnIndex); return E_INVALID_COLUMN_INDEX; } std::vector columnNames; @@ -263,5 +354,20 @@ int AbsResultSet::Close() isClosed = true; return E_OK; } + +int AbsResultSet::GetModifyTime(std::string &modifyTime) +{ + return E_NOT_SUPPORT; +} + +int AbsResultSet::GetAsset(int32_t col, ValueObject::Asset &value) +{ + return E_NOT_SUPPORT; +} + +int AbsResultSet::GetAssets(int32_t col, ValueObject::Assets &value) +{ + return E_NOT_SUPPORT; +} } // namespace NativeRdb } // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp b/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp index b4d3c029b8c9321b888d6d97623b8c4a070107d8..6483d8c3ea4ee6c6c358914d34674015d2bdacfe 100644 --- a/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/abs_shared_result_set.cpp @@ -23,6 +23,7 @@ #include "logger.h" #include "parcel.h" +#include "parser.h" #include "rdb_errno.h" #include "rdb_trace.h" #include "shared_block.h" @@ -35,9 +36,7 @@ AbsSharedResultSet::AbsSharedResultSet(std::string name) AppDataFwk::SharedBlock::Create(name, DEFAULT_BLOCK_SIZE, sharedBlock_); } -AbsSharedResultSet::AbsSharedResultSet() -{ -} +AbsSharedResultSet::AbsSharedResultSet() {} AbsSharedResultSet::~AbsSharedResultSet() { @@ -158,8 +157,7 @@ int AbsSharedResultSet::GetBlob(int columnIndex, std::vector &value) value.resize(0); int type = cellUnit->type; - if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_BLOB - || type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_STRING) { + if (type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_BLOB || type == AppDataFwk::SharedBlock::CELL_UNIT_TYPE_STRING) { size_t size; const auto *blob = static_cast(sharedBlock_->GetCellUnitValueBlob(cellUnit, &size)); if (size == 0 || blob == nullptr) { @@ -319,6 +317,60 @@ int AbsSharedResultSet::GetDouble(int columnIndex, double &value) } } +int AbsSharedResultSet::GetAsset(int32_t col, ValueObject::Asset &value) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + int errorCode = CheckState(col); + if (errorCode != E_OK) { + return errorCode; + } + + AppDataFwk::SharedBlock::CellUnit *cellUnit = sharedBlock_->GetCellUnit(sharedBlock_->GetBlockPos(), col); + if (!cellUnit) { + LOG_ERROR("GetAsset cellUnit is null!"); + return E_ERROR; + } + + if (cellUnit->type != AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSET) { + LOG_ERROR("GetAsset AppDataFwk::SharedBlock::nothing !"); + return E_INVALID_OBJECT_TYPE; + } + + size_t size = 0; + auto data = reinterpret_cast(sharedBlock_->GetCellUnitValueBlob(cellUnit, &size)); + ValueObject::Asset asset; + Parser::ParserRawData(data, size, asset); + value = std::move(asset); + return E_OK; +} + +int AbsSharedResultSet::GetAssets(int32_t col, ValueObject::Assets &value) +{ + DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); + int errorCode = CheckState(col); + if (errorCode != E_OK) { + return errorCode; + } + + auto *cellUnit = sharedBlock_->GetCellUnit(sharedBlock_->GetBlockPos(), col); + if (!cellUnit) { + LOG_ERROR("GetAssets cellUnit is null!"); + return E_ERROR; + } + + if (cellUnit->type != AppDataFwk::SharedBlock::CELL_UNIT_TYPE_ASSETS) { + LOG_ERROR("GetAssets AppDataFwk::SharedBlock::nothing !"); + return E_INVALID_OBJECT_TYPE; + } + + size_t size = 0; + auto data = reinterpret_cast(sharedBlock_->GetCellUnitValueBlob(cellUnit, &size)); + ValueObject::Assets assets; + Parser::ParserRawData(data, size, assets); + value = std::move(assets); + return E_OK; +} + int AbsSharedResultSet::IsColumnNull(int columnIndex, bool &isNull) { int errorCode = CheckState(columnIndex); @@ -399,7 +451,7 @@ int AbsSharedResultSet::CheckState(int columnIndex) if (rowPos_ < 0 || rowPos_ >= count) { return E_INVALID_STATEMENT; } - + GetColumnCount(count); if (columnIndex >= count || columnIndex < 0) { return E_INVALID_COLUMN_INDEX; diff --git a/relational_store/frameworks/native/rdb/src/parser.cpp b/relational_store/frameworks/native/rdb/src/parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d86fd27fa7c3f0fa9734a73b8b05bda74be1e390 --- /dev/null +++ b/relational_store/frameworks/native/rdb/src/parser.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 "parser.h" +#include "value_object.h" +#include "securec.h" +namespace OHOS::NativeRdb { +size_t Parser::ParserRawData(const uint8_t *data, size_t length, Asset &asset) +{ + size_t used = 0; + uint16_t type = ValueObject::TYPE_INDEX; + if (used + sizeof(type) > length) { + return used; + } + memcpy_s(&asset.version, sizeof(asset.version), data, length); + asset.version = le32toh(asset.version); + used += sizeof(asset.version); + return sizeof(asset.version); +} +size_t Parser::ParserRawData(const uint8_t *data, size_t length, Assets &assets) +{ + uint16_t num = 0; + return 0; +} +std::vector Parser::PackageRawData(const Asset &asset) +{ + std::vector rawData; + uint32_t version = htole32(asset.version); + rawData.assign(reinterpret_cast(&version), reinterpret_cast(&version) + sizeof(version)); + return rawData; +} +std::vector Parser::PackageRawData(const Assets &assets) +{ + return std::vector(); +} +} // namespace OHOS::NativeRdb \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp b/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp index f7f934881257ac265357e32cdaf610aa663f5f21..0e38609fbdb466a0dc4adbe514ad31391ffaf639 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_manager_impl.cpp @@ -26,8 +26,10 @@ #include "irdb_service.h" #include "itypes_util.h" #include "rdb_service_proxy.h" +#include "rdb_errno.h" namespace OHOS::DistributedRdb { +using namespace OHOS::NativeRdb; std::shared_ptr RdbManagerImpl::GetDistributedDataManager() { auto manager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); @@ -78,46 +80,40 @@ RdbManagerImpl& RdbManagerImpl::GetInstance() return manager; } -sptr RdbManagerImpl::GetRdbService() +int RdbManagerImpl::GetRdbService(const std::string& bundleName, std::shared_ptr &service) { + std::lock_guard lock(mutex_); + if (rdbService_ != nullptr) { + service = rdbService_; + return E_OK; + } if (distributedDataMgr_ == nullptr) { distributedDataMgr_ = GetDistributedDataManager(); } if (distributedDataMgr_ == nullptr) { ZLOGE("get distributed data manager failed"); - return nullptr; + return E_ERROR; } - auto remote = distributedDataMgr_->GetFeatureInterface("relational_store"); + auto remote = distributedDataMgr_->GetFeatureInterface(DistributedRdb::RdbService::SERVICE_NAME); if (remote == nullptr) { ZLOGE("get rdb service failed"); - return nullptr; + return E_NOT_SUPPORTED; } - return iface_cast(remote); -} - -std::shared_ptr RdbManagerImpl::GetRdbService(const RdbSyncerParam& param) -{ - std::lock_guard lock(mutex_); - if (rdbService_ != nullptr) { - return rdbService_; - } - auto service = GetRdbService(); - if (service == nullptr) { - return nullptr; - } - if (service->InitNotifier(param) != RDB_OK) { + sptr serviceProxy = iface_cast(remote); + if (serviceProxy->InitNotifier(bundleName) != RDB_OK) { ZLOGE("init notifier failed"); - return nullptr; + return E_ERROR; } - sptr serviceBase = service; + sptr serviceBase = serviceProxy; LinkToDeath(serviceBase->AsObject().GetRefPtr()); - rdbService_ = std::shared_ptr(service.GetRefPtr(), [holder = service] (const auto*) {}); + rdbService_ = std::shared_ptr(serviceProxy.GetRefPtr(), [holder = serviceProxy] (const auto*) {}); if (rdbService_ == nullptr) { - return nullptr; + return E_ERROR; } - bundleName_ = param.bundleName_; - return rdbService_; + bundleName_ = bundleName; + service = rdbService_; + return E_OK; } void RdbManagerImpl::OnRemoteDied() @@ -134,8 +130,9 @@ void RdbManagerImpl::OnRemoteDied() std::this_thread::sleep_for(std::chrono::seconds(WAIT_TIME)); RdbSyncerParam param; param.bundleName_ = bundleName_; - auto service = GetRdbService(param); - if (service == nullptr) { + std::shared_ptr service = nullptr; + int errCode = GetRdbService(bundleName_, service); + if (errCode != E_OK) { return; } proxy = std::static_pointer_cast(service); diff --git a/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp b/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp index e060c932329051939c89877d082e82a0631935ec..5847fabe471c2200d2641c94281555e0bc6e8214 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_security_manager.cpp @@ -1,17 +1,17 @@ /* -* Copyright (c) 2022 Huawei Device Co., Ltd. -* 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. -*/ + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 "rdb_security_manager.h" @@ -26,6 +26,7 @@ #include "hks_param.h" #include "logger.h" #include "sqlite_database_utils.h" +#include "sqlite_utils.h" namespace OHOS { namespace NativeRdb { @@ -33,131 +34,136 @@ RdbPassword::RdbPassword() = default; RdbPassword::~RdbPassword() { - (void)Clear(); + (void)Clear(); } bool RdbPassword::operator==(const RdbPassword &input) const { - if (size_ != input.GetSize()) { - return false; - } - return memcmp(data_, input.GetData(), size_) == 0; + if (size_ != input.GetSize()) { + return false; + } + return memcmp(data_, input.GetData(), size_) == 0; } bool RdbPassword::operator!=(const RdbPassword &input) const { - return !(*this == input); + return !(*this == input); } size_t RdbPassword::GetSize() const { - return size_; + return size_; } const uint8_t *RdbPassword::GetData() const { - return data_; + return data_; } int RdbPassword::SetValue(const uint8_t *inputData, size_t inputSize) { - if (inputSize > MAX_PASSWORD_SIZE) { - return E_ERROR; - } - if (inputSize != 0 && inputData == nullptr) { - return E_ERROR; - } - - if (inputSize != 0) { - std::copy(inputData, inputData + inputSize, data_); - } - - size_t filledSize = std::min(size_, MAX_PASSWORD_SIZE); - if (inputSize < filledSize) { - std::fill(data_ + inputSize, data_ + filledSize, UCHAR_MAX); - } - - size_ = inputSize; - return E_OK; + if (inputSize > MAX_PASSWORD_SIZE) { + return E_ERROR; + } + if (inputSize != 0 && inputData == nullptr) { + return E_ERROR; + } + + if (inputSize != 0) { + std::copy(inputData, inputData + inputSize, data_); + } + + size_t filledSize = std::min(size_, MAX_PASSWORD_SIZE); + if (inputSize < filledSize) { + std::fill(data_ + inputSize, data_ + filledSize, UCHAR_MAX); + } + + size_ = inputSize; + return E_OK; } int RdbPassword::Clear() { - return SetValue(nullptr, 0); + return SetValue(nullptr, 0); +} + +bool RdbPassword::IsValid() const +{ + return size_ != 0; } int32_t RdbSecurityManager::MallocAndCheckBlobData(struct HksBlob *blob, const uint32_t blobSize) { - blob->data = (uint8_t *)malloc(blobSize); - if (blob->data == NULL) { - LOG_ERROR("Blob data is NULL."); - return HKS_FAILURE; - } - return HKS_SUCCESS; + blob->data = (uint8_t *)malloc(blobSize); + if (blob->data == NULL) { + LOG_ERROR("Blob data is NULL."); + return HKS_FAILURE; + } + return HKS_SUCCESS; } int32_t RdbSecurityManager::HksLoopUpdate(const struct HksBlob *handle, const struct HksParamSet *paramSet, - const struct HksBlob *inData, struct HksBlob *outData) -{ - struct HksBlob inDataSeg = *inData; - uint8_t *lastPtr = inData->data + inData->size - 1; - uint8_t *cur = outData->data; - uint32_t length = outData->size; - outData->size = 0; - - inDataSeg.size = MAX_UPDATE_SIZE; - while (inDataSeg.data <= lastPtr) { - if (inDataSeg.data + MAX_UPDATE_SIZE > lastPtr) { - inDataSeg.size = lastPtr - inDataSeg.data + 1; - break; - } - struct HksBlob outDataSeg = { length - outData->size, cur }; - if (HksUpdate(handle, paramSet, &inDataSeg, &outDataSeg) != HKS_SUCCESS) { - LOG_ERROR("HksUpdate Failed."); - return HKS_FAILURE; - } - cur += outDataSeg.size; - outData->size += outDataSeg.size; - if (inDataSeg.data + MAX_UPDATE_SIZE > lastPtr) { - LOG_ERROR("isFinished and inDataSeg data Error"); - return HKS_FAILURE; - } - inDataSeg.data += MAX_UPDATE_SIZE; - } - - struct HksBlob outDataFinish = { length - outData->size, cur }; - if (HksFinish(handle, paramSet, &inDataSeg, &outDataFinish) != HKS_SUCCESS) { - LOG_ERROR("HksFinish Failed."); - return HKS_FAILURE; - } - outData->size += outDataFinish.size; - return HKS_SUCCESS; + const struct HksBlob *inData, struct HksBlob *outData) +{ + struct HksBlob inDataSeg = *inData; + uint8_t *lastPtr = inData->data + inData->size - 1; + uint8_t *cur = outData->data; + uint32_t length = outData->size; + outData->size = 0; + + inDataSeg.size = MAX_UPDATE_SIZE; + while (inDataSeg.data <= lastPtr) { + if (inDataSeg.data + MAX_UPDATE_SIZE > lastPtr) { + inDataSeg.size = lastPtr - inDataSeg.data + 1; + break; + } + struct HksBlob outDataSeg = { length - outData->size, cur }; + if (HksUpdate(handle, paramSet, &inDataSeg, &outDataSeg) != HKS_SUCCESS) { + LOG_ERROR("HksUpdate Failed."); + return HKS_FAILURE; + } + cur += outDataSeg.size; + outData->size += outDataSeg.size; + if (inDataSeg.data + MAX_UPDATE_SIZE > lastPtr) { + LOG_ERROR("isFinished and inDataSeg data Error"); + return HKS_FAILURE; + } + inDataSeg.data += MAX_UPDATE_SIZE; + } + + struct HksBlob outDataFinish = { length - outData->size, cur }; + if (HksFinish(handle, paramSet, &inDataSeg, &outDataFinish) != HKS_SUCCESS) { + LOG_ERROR("HksFinish Failed."); + return HKS_FAILURE; + } + outData->size += outDataFinish.size; + return HKS_SUCCESS; } int32_t RdbSecurityManager::HksEncryptThreeStage(const struct HksBlob *keyAlias, const struct HksParamSet *paramSet, - const struct HksBlob *plainText, struct HksBlob *cipherText) + const struct HksBlob *plainText, struct HksBlob *cipherText) { - uint8_t handle[sizeof(uint64_t)] = { 0 }; - struct HksBlob handleBlob = { sizeof(uint64_t), handle }; - int32_t result = HksInit(keyAlias, paramSet, &handleBlob, nullptr); - if (result != HKS_SUCCESS) { - LOG_ERROR("HksEncrypt failed with error %{public}d", result); - return result; - } - return HksLoopUpdate(&handleBlob, paramSet, plainText, cipherText); + uint8_t handle[sizeof(uint64_t)] = { 0 }; + struct HksBlob handleBlob = { sizeof(uint64_t), handle }; + int32_t result = HksInit(keyAlias, paramSet, &handleBlob, nullptr); + if (result != HKS_SUCCESS) { + LOG_ERROR("HksEncrypt failed with error %{public}d", result); + return result; + } + return HksLoopUpdate(&handleBlob, paramSet, plainText, cipherText); } int32_t RdbSecurityManager::HksDecryptThreeStage(const struct HksBlob *keyAlias, const struct HksParamSet *paramSet, - const struct HksBlob *cipherText, struct HksBlob *plainText) + const struct HksBlob *cipherText, struct HksBlob *plainText) { - uint8_t handle[sizeof(uint64_t)] = { 0 }; - struct HksBlob handleBlob = { sizeof(uint64_t), handle }; - int32_t result = HksInit(keyAlias, paramSet, &handleBlob, nullptr); - if (result != HKS_SUCCESS) { - LOG_ERROR("HksEncrypt failed with error %{public}d", result); - return result; - } - return HksLoopUpdate(&handleBlob, paramSet, cipherText, plainText); + uint8_t handle[sizeof(uint64_t)] = { 0 }; + struct HksBlob handleBlob = { sizeof(uint64_t), handle }; + int32_t result = HksInit(keyAlias, paramSet, &handleBlob, nullptr); + if (result != HKS_SUCCESS) { + LOG_ERROR("HksEncrypt failed with error %{public}d", result); + return result; + } + return HksLoopUpdate(&handleBlob, paramSet, cipherText, plainText); } RdbSecurityManager::RdbSecurityManager() = default; @@ -166,449 +172,483 @@ RdbSecurityManager::~RdbSecurityManager() = default; std::vector RdbSecurityManager::GenerateRandomNum(int32_t len) { - std::random_device randomDevice; - std::uniform_int_distribution distribution(0, std::numeric_limits::max()); - std::vector key(len); - for (int32_t i = 0; i < len; i++) { - key[i] = static_cast(distribution(randomDevice)); - } - return key; + std::random_device randomDevice; + std::uniform_int_distribution distribution(0, std::numeric_limits::max()); + std::vector key(len); + for (int32_t i = 0; i < len; i++) { + key[i] = static_cast(distribution(randomDevice)); + } + return key; } -bool RdbSecurityManager::SaveSecretKeyToFile(RdbSecurityManager::KeyFileType keyFile, const std::vector &key) +bool RdbSecurityManager::SaveSecretKeyToFile(RdbSecurityManager::KeyFileType keyFile) { - LOG_INFO("SaveSecretKeyToFile begin."); - if (!CheckRootKeyExists()) { - LOG_ERROR("Root key not exists!"); - return false; - } - RdbSecretKeyData keyData; - keyData.timeValue = std::chrono::system_clock::to_time_t(std::chrono::system_clock::system_clock::now()); - keyData.distributed = 0; - keyData.secretKey = EncryptWorkKey(key); - - if (keyData.secretKey.size() == 0) { - return false; - } - - if (!RdbSecurityManager::InitPath(dbKeyDir_)) { - return false; - } - - std::string keyPath; - if (keyFile == KeyFileType::PUB_KEY_FILE) { - keyPath = keyPath_; - } else { - keyPath = keyBakPath_; - } - - return SaveSecretKeyToDisk(keyPath, keyData); + LOG_INFO("SaveSecretKeyToFile begin."); + if (!CheckRootKeyExists()) { + LOG_ERROR("Root key not exists!"); + return false; + } + std::vector key = GenerateRandomNum(RDB_KEY_SIZE); + RdbSecretKeyData keyData; + keyData.timeValue = std::chrono::system_clock::to_time_t(std::chrono::system_clock::system_clock::now()); + keyData.distributed = 0; + keyData.secretKey = EncryptWorkKey(key); + + if (keyData.secretKey.empty()) { + LOG_ERROR("Key size is 0"); + key.assign(key.size(), 0); + return false; + } + + key.assign(key.size(), 0); + if (!RdbSecurityManager::InitPath(dbKeyDir_)) { + LOG_ERROR("InitPath err."); + return false; + } + + std::string keyPath; + GetKeyPath(keyFile, keyPath); + + return SaveSecretKeyToDisk(keyPath, keyData); } bool RdbSecurityManager::SaveSecretKeyToDisk(const std::string &path, RdbSecretKeyData &keyData) { - LOG_INFO("SaveSecretKeyToDisk begin."); - std::lock_guard lock(mutex_); - std::vector key; - key.push_back(keyData.distributed); - key.insert(key.end(), reinterpret_cast(&keyData.timeValue), reinterpret_cast(&keyData.timeValue) + sizeof(keyData.timeValue)); - key.insert(key.end(), keyData.secretKey.begin(), keyData.secretKey.end()); - - bool ret = SaveBufferToFile(path, key); - if (!ret) { - LOG_ERROR("SaveBufferToFile failed!"); - return false; - } - - return true; + LOG_INFO("SaveSecretKeyToDisk begin."); + std::lock_guard lock(mutex_); + std::vector key; + key.push_back(keyData.distributed); + key.insert(key.end(), reinterpret_cast(&keyData.timeValue), + reinterpret_cast(&keyData.timeValue) + sizeof(keyData.timeValue)); + key.insert(key.end(), keyData.secretKey.begin(), keyData.secretKey.end()); + + bool ret = SaveBufferToFile(path, key); + if (!ret) { + LOG_ERROR("SaveBufferToFile failed!"); + return false; + } + + return true; } int RdbSecurityManager::GenerateRootKey() { - LOG_INFO("RDB GenerateRootKey begin."); - struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), rootKeyAlias_.data() }; - struct HksParamSet *params = nullptr; - int32_t ret = HksInitParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksInitParamSet()-client failed with error %{public}d", ret); - return ret; - } - - struct HksParam hksParam[] = { - { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, - { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 }, - { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT }, - { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, - { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, - { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, - }; - - ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksAddParams-client failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return ret; - } - - ret = HksBuildParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksBuildParamSet-client failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return ret; - } - - ret = HksGenerateKey(&rootKeyName, params, nullptr); - HksFreeParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksGenerateKey-client failed with error %{public}d", ret); - } - LOG_INFO("RDB root key generated successful."); - return ret; + LOG_INFO("RDB GenerateRootKey begin."); + struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), rootKeyAlias_.data() }; + struct HksParamSet *params = nullptr; + int32_t ret = HksInitParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksInitParamSet()-client failed with error %{public}d", ret); + return ret; + } + + struct HksParam hksParam[] = { + { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, + { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 }, + { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT }, + { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, + { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, + { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, + }; + + ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksAddParams-client failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return ret; + } + + ret = HksBuildParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksBuildParamSet-client failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return ret; + } + + ret = HksGenerateKey(&rootKeyName, params, nullptr); + HksFreeParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksGenerateKey-client failed with error %{public}d", ret); + } + LOG_INFO("RDB root key generated successful."); + return ret; } std::vector RdbSecurityManager::EncryptWorkKey(const std::vector &key) { - struct HksBlob blobAad = { uint32_t(aad_.size()), aad_.data() }; - struct HksBlob blobNonce = { uint32_t(nonce_.size()), nonce_.data() }; - struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), rootKeyAlias_.data() }; - struct HksBlob plainKey = { uint32_t(key.size()), const_cast(key.data()) }; - struct HksParamSet *params = nullptr; - int32_t ret = HksInitParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksInitParamSet() failed with error %{public}d", ret); - return {}; - } - struct HksParam hksParam[] = { - { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, - { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT }, - { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, - { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, - { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, - { .tag = HKS_TAG_NONCE, .blob = blobNonce }, - { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, - }; - ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksAddParams failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return {}; - } - - ret = HksBuildParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return {}; - } - - uint8_t cipherBuf[256] = { 0 }; - struct HksBlob cipherText = { sizeof(cipherBuf), cipherBuf }; - ret = HksEncryptThreeStage(&rootKeyName, params, &plainKey, &cipherText); - (void)HksFreeParamSet(¶ms); - if (ret != HKS_SUCCESS) { - (void)memset_s(cipherBuf, sizeof(cipherBuf), 0, sizeof(cipherBuf)); - LOG_ERROR("HksEncrypt failed with error %{public}d", ret); - return {}; - } - - std::vector encryptedKey(cipherText.data, cipherText.data + cipherText.size); - (void)memset_s(cipherBuf, sizeof(cipherBuf), 0, sizeof(cipherBuf)); - - return encryptedKey; + struct HksBlob blobAad = { uint32_t(aad_.size()), aad_.data() }; + struct HksBlob blobNonce = { uint32_t(nonce_.size()), nonce_.data() }; + struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), rootKeyAlias_.data() }; + struct HksBlob plainKey = { uint32_t(key.size()), const_cast(key.data()) }; + struct HksParamSet *params = nullptr; + int32_t ret = HksInitParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksInitParamSet() failed with error %{public}d", ret); + return {}; + } + struct HksParam hksParam[] = { + { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, + { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT }, + { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, + { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, + { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, + { .tag = HKS_TAG_NONCE, .blob = blobNonce }, + { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, + }; + ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksAddParams failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return {}; + } + + ret = HksBuildParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return {}; + } + + uint8_t cipherBuf[256] = { 0 }; + struct HksBlob cipherText = { sizeof(cipherBuf), cipherBuf }; + ret = HksEncryptThreeStage(&rootKeyName, params, &plainKey, &cipherText); + (void)HksFreeParamSet(¶ms); + if (ret != HKS_SUCCESS) { + (void)memset_s(cipherBuf, sizeof(cipherBuf), 0, sizeof(cipherBuf)); + LOG_ERROR("HksEncrypt failed with error %{public}d", ret); + return {}; + } + + std::vector encryptedKey(cipherText.data, cipherText.data + cipherText.size); + (void)memset_s(cipherBuf, sizeof(cipherBuf), 0, sizeof(cipherBuf)); + + return encryptedKey; } bool RdbSecurityManager::DecryptWorkKey(std::vector &source, std::vector &key) { - uint8_t aead_[AEAD_LEN] = { 0 }; - struct HksBlob blobAad = { uint32_t(aad_.size()), &(aad_[0]) }; - struct HksBlob blobNonce = { uint32_t(nonce_.size()), &(nonce_[0]) }; - struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), &(rootKeyAlias_[0]) }; - struct HksBlob encryptedKeyBlob = { uint32_t(source.size() - AEAD_LEN), source.data() }; - struct HksBlob blobAead = { AEAD_LEN, aead_ }; - if (memcpy_s(aead_, AEAD_LEN, source.data() + source.size() - AEAD_LEN, AEAD_LEN) != 0) { - return false; - } - - struct HksParamSet *params = nullptr; - int32_t ret = HksInitParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksInitParamSet() failed with error %{public}d", ret); - return false; - } - struct HksParam hksParam[] = { - { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, - { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_DECRYPT }, - { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, - { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, - { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, - { .tag = HKS_TAG_NONCE, .blob = blobNonce }, - { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, - { .tag = HKS_TAG_AE_TAG, .blob = blobAead }, - }; - ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksAddParams failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return false; - } - - ret = HksBuildParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return false; - } - - uint8_t plainBuf[512] = { 0 }; - struct HksBlob plainKeyBlob = { sizeof(plainBuf), plainBuf }; - ret = HksDecryptThreeStage(&rootKeyName, params, &encryptedKeyBlob, &plainKeyBlob); - (void)HksFreeParamSet(¶ms); - if (ret != HKS_SUCCESS) { - (void)memset_s(plainBuf, sizeof(plainBuf), 0, sizeof(plainBuf)); - LOG_ERROR("HksDecrypt failed with error %{public}d", ret); - return false; - } - - key.assign(plainKeyBlob.data, plainKeyBlob.data + plainKeyBlob.size); - (void)memset_s(plainBuf, sizeof(plainBuf), 0, sizeof(plainBuf)); - return true; + uint8_t aead_[AEAD_LEN] = { 0 }; + struct HksBlob blobAad = { uint32_t(aad_.size()), &(aad_[0]) }; + struct HksBlob blobNonce = { uint32_t(nonce_.size()), &(nonce_[0]) }; + struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), &(rootKeyAlias_[0]) }; + struct HksBlob encryptedKeyBlob = { uint32_t(source.size() - AEAD_LEN), source.data() }; + struct HksBlob blobAead = { AEAD_LEN, aead_ }; + if (memcpy_s(aead_, AEAD_LEN, source.data() + source.size() - AEAD_LEN, AEAD_LEN) != 0) { + return false; + } + + struct HksParamSet *params = nullptr; + int32_t ret = HksInitParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksInitParamSet() failed with error %{public}d", ret); + return false; + } + struct HksParam hksParam[] = { + { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, + { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_DECRYPT }, + { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, + { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, + { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, + { .tag = HKS_TAG_NONCE, .blob = blobNonce }, + { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, + { .tag = HKS_TAG_AE_TAG, .blob = blobAead }, + }; + ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksAddParams failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return false; + } + + ret = HksBuildParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return false; + } + + uint8_t plainBuf[512] = { 0 }; + struct HksBlob plainKeyBlob = { sizeof(plainBuf), plainBuf }; + ret = HksDecryptThreeStage(&rootKeyName, params, &encryptedKeyBlob, &plainKeyBlob); + (void)HksFreeParamSet(¶ms); + if (ret != HKS_SUCCESS) { + (void)memset_s(plainBuf, sizeof(plainBuf), 0, sizeof(plainBuf)); + LOG_ERROR("HksDecrypt failed with error %{public}d", ret); + return false; + } + + key.assign(plainKeyBlob.data, plainKeyBlob.data + plainKeyBlob.size); + (void)memset_s(plainBuf, sizeof(plainBuf), 0, sizeof(plainBuf)); + return true; } void RdbSecurityManager::Init(const std::string &bundleName, const std::string &path) { - rootKeyAlias_ = GenerateRootKeyAlias(bundleName); - nonce_ = std::vector(RDB_HKS_BLOB_TYPE_NONCE, RDB_HKS_BLOB_TYPE_NONCE + strlen(RDB_HKS_BLOB_TYPE_NONCE)); - aad_ = std::vector(RDB_HKS_BLOB_TYPE_AAD, RDB_HKS_BLOB_TYPE_AAD + strlen(RDB_HKS_BLOB_TYPE_AAD)); - - ParsePath(path); - if (CheckRootKeyExists()) { - return; - } - constexpr uint32_t RETRY_MAX_TIMES = 5; - uint32_t retryCount = 0; - constexpr int RETRY_TIME_INTERVAL_MILLISECOND = 1 * 1000 * 1000; - while (retryCount < RETRY_MAX_TIMES) { - auto ret = GenerateRootKey(); - if (ret == HKS_SUCCESS) { - break; - } - retryCount++; - LOG_ERROR("RDB generate root key failed, try count:%{public}u", retryCount); - usleep(RETRY_TIME_INTERVAL_MILLISECOND); - } + rootKeyAlias_ = GenerateRootKeyAlias(bundleName); + nonce_ = std::vector(RDB_HKS_BLOB_TYPE_NONCE, RDB_HKS_BLOB_TYPE_NONCE + strlen(RDB_HKS_BLOB_TYPE_NONCE)); + aad_ = std::vector(RDB_HKS_BLOB_TYPE_AAD, RDB_HKS_BLOB_TYPE_AAD + strlen(RDB_HKS_BLOB_TYPE_AAD)); + + ParsePath(path); + if (CheckRootKeyExists()) { + return; + } + constexpr uint32_t RETRY_MAX_TIMES = 5; + uint32_t retryCount = 0; + constexpr int RETRY_TIME_INTERVAL_MILLISECOND = 1 * 1000 * 1000; + while (retryCount < RETRY_MAX_TIMES) { + auto ret = GenerateRootKey(); + if (ret == HKS_SUCCESS) { + break; + } + retryCount++; + LOG_ERROR("RDB generate root key failed, try count:%{public}u", retryCount); + usleep(RETRY_TIME_INTERVAL_MILLISECOND); + } } bool RdbSecurityManager::CheckRootKeyExists() { - LOG_INFO("RDB checkRootKeyExist begin."); - struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), rootKeyAlias_.data() }; - struct HksParamSet *params = nullptr; - int32_t ret = HksInitParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksInitParamSet()-client failed with error %{public}d", ret); - return ret; - } - - struct HksParam hksParam[] = { - { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, - { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 }, - { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT }, - { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, - { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, - { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, - }; - - ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksAddParams failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return ret; - } - - ret = HksBuildParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); - HksFreeParamSet(¶ms); - return ret; - } - - ret = HksKeyExist(&rootKeyName, params); - HksFreeParamSet(¶ms); - if (ret != HKS_SUCCESS) { - LOG_ERROR("HksEncrypt failed with error %{public}d", ret); - } - return ret == HKS_SUCCESS; + LOG_INFO("RDB checkRootKeyExist begin."); + struct HksBlob rootKeyName = { uint32_t(rootKeyAlias_.size()), rootKeyAlias_.data() }; + struct HksParamSet *params = nullptr; + int32_t ret = HksInitParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksInitParamSet()-client failed with error %{public}d", ret); + return ret; + } + + struct HksParam hksParam[] = { + { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, + { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 }, + { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT }, + { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, + { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, + { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, + }; + + ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksAddParams failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return ret; + } + + ret = HksBuildParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksBuildParamSet failed with error %{public}d", ret); + HksFreeParamSet(¶ms); + return ret; + } + + ret = HksKeyExist(&rootKeyName, params); + HksFreeParamSet(¶ms); + if (ret != HKS_SUCCESS) { + LOG_ERROR("HksEncrypt failed with error %{public}d", ret); + } + return ret == HKS_SUCCESS; } bool RdbSecurityManager::InitPath(const std::string &path) { - constexpr mode_t DEFAULT_UMASK = 0002; - if (access(path.c_str(), F_OK) == 0) { - return true; - } - umask(DEFAULT_UMASK); - if (mkdir(path.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) != 0 && errno != EEXIST) { - LOG_ERROR("mkdir error:%{public}d, dbDir:%{public}s", errno, path.c_str()); - return false; - } - return true; + constexpr mode_t DEFAULT_UMASK = 0002; + if (access(path.c_str(), F_OK) == 0) { + return true; + } + umask(DEFAULT_UMASK); + if (mkdir(path.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) != 0 && errno != EEXIST) { + LOG_ERROR("mkdir error:%{public}d, dbDir:%{public}s", errno, SqliteUtils::Anonymous(path).c_str()); + return false; + } + return true; } -bool RdbSecurityManager::LoadSecretKeyFromDisk(const std::string &keyPath, RdbSecretKeyData &keyData) +RdbPassword RdbSecurityManager::LoadSecretKeyFromFile(KeyFileType keyFile) { - LOG_INFO("LoadSecretKeyFromDisk begin."); - std::vector content; - if (!LoadBufferFromFile(keyPath, content)) { - LOG_ERROR("LoadBufferFromFile failed!"); - return false; - } - - std::vector distribute; - auto iter = content.begin(); - distribute.push_back(*iter); - iter++; - uint8_t distributeStatus = TransferByteArrayToType(distribute); - - std::vector createTime; - for (int i = 0; i < static_cast(sizeof(time_t) / sizeof(uint8_t)); i++) { - createTime.push_back(*iter); - iter++; - } + std::string keyPath; + GetKeyPath(keyFile, keyPath); + if (!FileExists(keyPath)) { + LOG_ERROR("Key file not exists."); + return {}; + } + + RdbSecretKeyData keyData; + if (!LoadSecretKeyFromDisk(keyPath, keyData)) { + LOG_ERROR("Load key failed."); + return {}; + } + + std::vector key; + if (!DecryptWorkKey(keyData.secretKey, key)) { + LOG_ERROR("Decrypt key failed!"); + return {}; + } + + RdbPassword rdbPasswd; + rdbPasswd.isKeyExpired = IsKeyExpired(keyData.timeValue); + rdbPasswd.SetValue(key.data(), key.size()); + key.assign(key.size(), 0); + return rdbPasswd; +} - keyData.distributed = distributeStatus; - keyData.timeValue = TransferByteArrayToType(createTime); - keyData.secretKey.insert(keyData.secretKey.end(), iter, content.end()); - content.assign(content.size(), 0); - return true; +bool RdbSecurityManager::LoadSecretKeyFromDisk(const std::string &keyPath, RdbSecretKeyData &keyData) +{ + LOG_INFO("LoadSecretKeyFromDisk begin."); + std::vector content; + if (!LoadBufferFromFile(keyPath, content)) { + LOG_ERROR("LoadBufferFromFile failed!"); + return false; + } + + std::vector distribute; + auto iter = content.begin(); + distribute.push_back(*iter); + iter++; + uint8_t distributeStatus = TransferByteArrayToType(distribute); + + std::vector createTime; + for (int i = 0; i < static_cast(sizeof(time_t) / sizeof(uint8_t)); i++) { + createTime.push_back(*iter); + iter++; + } + + keyData.distributed = distributeStatus; + keyData.timeValue = TransferByteArrayToType(createTime); + keyData.secretKey.insert(keyData.secretKey.end(), iter, content.end()); + content.assign(content.size(), 0); + return true; } RdbPassword RdbSecurityManager::GetRdbPassword(KeyFileType keyFile) { - LOG_INFO("GetRdbPassword Begin."); - std::string keyPath; - if (keyFile == KeyFileType::PUB_KEY_FILE) { - keyPath = keyPath_; - } else { - keyPath = keyBakPath_; - } - RdbSecretKeyData keyData; - if (!LoadSecretKeyFromDisk(keyPath, keyData)) { - return {}; - } - std::vector key; - if (!DecryptWorkKey(keyData.secretKey, key)) { - LOG_ERROR("GetRdbPassword failed!"); - return {}; - } - - RdbPassword password; - password.SetValue(key.data(), key.size()); - key.assign(key.size(), 0); - return password; + LOG_INFO("GetRdbPassword Begin."); + if (!CheckKeyDataFileExists(keyFile)) { + if (!SaveSecretKeyToFile(keyFile)) { + LOG_ERROR("Failed to save key."); + return {}; + } + } + + return LoadSecretKeyFromFile(keyFile); } std::vector RdbSecurityManager::GenerateRootKeyAlias(const std::string &bundleName) { - bundleName_ = bundleName; - if (bundleName_.empty()) { - LOG_ERROR("BundleName is empty!"); - return {}; - } - std::vector rootKeyAlias = - std::vector(RDB_ROOT_KEY_ALIAS_PREFIX, RDB_ROOT_KEY_ALIAS_PREFIX + strlen(RDB_ROOT_KEY_ALIAS_PREFIX)); - rootKeyAlias.insert(rootKeyAlias.end(), bundleName.begin(), bundleName.end()); - return rootKeyAlias; + bundleName_ = bundleName; + if (bundleName_.empty()) { + LOG_ERROR("BundleName is empty!"); + return {}; + } + std::vector rootKeyAlias = + std::vector(RDB_ROOT_KEY_ALIAS_PREFIX, RDB_ROOT_KEY_ALIAS_PREFIX + strlen(RDB_ROOT_KEY_ALIAS_PREFIX)); + rootKeyAlias.insert(rootKeyAlias.end(), bundleName.begin(), bundleName.end()); + return rootKeyAlias; } void RdbSecurityManager::DelRdbSecretDataFile(const std::string &path) { - LOG_INFO("Delete all key files begin."); - std::lock_guard lock(mutex_); - ParsePath(path); - SqliteDatabaseUtils::DeleteFile(keyPath_); - SqliteDatabaseUtils::DeleteFile(keyBakPath_); + LOG_INFO("Delete all key files begin."); + std::lock_guard lock(mutex_); + ParsePath(path); + SqliteDatabaseUtils::DeleteFile(keyPath_); + SqliteDatabaseUtils::DeleteFile(newKeyPath_); } -bool RdbSecurityManager::IsKeyOutOfdate(const time_t &createTime) const +bool RdbSecurityManager::IsKeyExpired(const time_t &createTime) { - std::chrono::system_clock::time_point createTimeChrono = std::chrono::system_clock::from_time_t(createTime); - return ((createTimeChrono + std::chrono::hours(HOURS_PER_YEAR)) < std::chrono::system_clock::now()); + auto timePoint = std::chrono::system_clock::from_time_t(createTime); + return ((timePoint + std::chrono::hours(HOURS_PER_YEAR)) < std::chrono::system_clock::now()); } RdbSecurityManager &RdbSecurityManager::GetInstance() { - static RdbSecurityManager instance; - return instance; + static RdbSecurityManager instance; + return instance; } static std::string RemoveSuffix(const std::string &name) { - std::string suffix(".db"); - auto pos = name.rfind(suffix); - if (pos == std::string::npos || pos < name.length() - suffix.length()) { - return name; - } - return { name, 0, pos }; + std::string suffix(".db"); + auto pos = name.rfind(suffix); + if (pos == std::string::npos || pos < name.length() - suffix.length()) { + return name; + } + return { name, 0, pos }; } void RdbSecurityManager::ParsePath(const std::string &path) { - dbDir_ = ExtractFilePath(path); - const std::string dbName = ExtractFileName(path); - dbName_ = RemoveSuffix(dbName); - dbKeyDir_ = dbDir_ + std::string("key/"); - keyPath_ = dbKeyDir_ + dbName_ + std::string(RdbSecurityManager::SUFFIX_PUB_KEY); - keyBakPath_ = dbKeyDir_ + dbName_ + std::string(RdbSecurityManager::SUFFIX_PUB_KEY_BAK); + dbDir_ = ExtractFilePath(path); + const std::string dbName = ExtractFileName(path); + dbName_ = RemoveSuffix(dbName); + dbKeyDir_ = dbDir_ + std::string("key/"); + keyPath_ = dbKeyDir_ + dbName_ + std::string(RdbSecurityManager::SUFFIX_PUB_KEY); + newKeyPath_ = dbKeyDir_ + dbName_ + std::string(RdbSecurityManager::SUFFIX_PUB_KEY_NEW); } bool RdbSecurityManager::CheckKeyDataFileExists(RdbSecurityManager::KeyFileType fileType) { - if (fileType == KeyFileType::PUB_KEY_FILE) { - return FileExists(keyPath_); - } else { - return FileExists(keyBakPath_); - } + if (fileType == KeyFileType::PUB_KEY_FILE) { + return FileExists(keyPath_); + } else { + return FileExists(newKeyPath_); + } } int RdbSecurityManager::GetKeyDistributedStatus(KeyFileType keyFile, bool &status) { - LOG_INFO("GetKeyDistributedStatus start."); - std::string keyPath; - if (keyFile == KeyFileType::PUB_KEY_FILE) { - keyPath = keyPath_; - } else { - keyPath = keyBakPath_; - } + LOG_INFO("GetKeyDistributedStatus start."); + std::string keyPath; + GetKeyPath(keyFile, keyPath); - RdbSecretKeyData keyData; - if (!LoadSecretKeyFromDisk(keyPath, keyData)) { - return E_ERROR; - } + RdbSecretKeyData keyData; + if (!LoadSecretKeyFromDisk(keyPath, keyData)) { + return E_ERROR; + } - status = (keyData.distributed == DISTRIBUTED); - return E_OK; + status = (keyData.distributed == DISTRIBUTED); + return E_OK; } int RdbSecurityManager::SetKeyDistributedStatus(KeyFileType keyFile, bool status) { - LOG_INFO("SetKeyDistributedStatus start."); - std::string keyPath; - if (keyFile == KeyFileType::PUB_KEY_FILE) { - keyPath = keyPath_; - } else { - keyPath = keyBakPath_; - } - RdbSecretKeyData keyData; - if (!LoadSecretKeyFromDisk(keyPath, keyData)) { - return E_ERROR; - } - - keyData.distributed = (status ? DISTRIBUTED : UNDISTRIBUTED); - if (!SaveSecretKeyToDisk(keyPath, keyData)) { - return E_ERROR; - } - - return E_OK; + LOG_INFO("SetKeyDistributedStatus start."); + std::string keyPath; + GetKeyPath(keyFile, keyPath); + RdbSecretKeyData keyData; + if (!LoadSecretKeyFromDisk(keyPath, keyData)) { + return E_ERROR; + } + + keyData.distributed = (status ? DISTRIBUTED : UNDISTRIBUTED); + if (!SaveSecretKeyToDisk(keyPath, keyData)) { + return E_ERROR; + } + + return E_OK; +} + +void RdbSecurityManager::GetKeyPath(RdbSecurityManager::KeyFileType keyType, std::string &keyPath) +{ + if (keyType == KeyFileType::PUB_KEY_FILE) { + keyPath = keyPath_; + } else { + keyPath = newKeyPath_; + } +} + +void RdbSecurityManager::DelRdbSecretDataFile(RdbSecurityManager::KeyFileType keyFile) +{ + std::string keyPath; + GetKeyPath(keyFile, keyPath); + SqliteDatabaseUtils::DeleteFile(keyPath); +} + +void RdbSecurityManager::UpdateKeyFile() +{ + if (!SqliteDatabaseUtils::RenameFile(newKeyPath_, keyPath_)) { + LOG_ERROR("Rename key file failed."); + return; + } } } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp b/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp index 3554b6a95904da628a4cb02eed65a996715b3a4a..42bfe9a94f18ebfae50d0e5d4e9ea38e42905603 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_service_proxy.cpp @@ -20,9 +20,35 @@ #include "log_print.h" namespace OHOS::DistributedRdb { +#define IPC_SEND(code, reply, ...) \ +({ \ + int32_t __status = RDB_OK; \ + do { \ + MessageParcel request; \ + if (!request.WriteInterfaceToken(GetDescriptor())) { \ + __status = RDB_ERROR; \ + break; \ + } \ + if (!ITypesUtil::Marshal(request, ##__VA_ARGS__)) { \ + __status = RDB_ERROR; \ + break; \ + } \ + MessageOption option; \ + auto result = remote_->SendRequest((code), request, reply, option); \ + if (result != 0) { \ + __status = RDB_ERROR; \ + break; \ + } \ + \ + ITypesUtil::Unmarshal(reply, __status); \ + } while (0); \ + __status; \ +}) + RdbServiceProxy::RdbServiceProxy(const sptr &object) : IRemoteProxy(object) { + remote_ = Remote(); } void RdbServiceProxy::OnSyncComplete(uint32_t seqNum, const SyncResult &result) @@ -48,41 +74,28 @@ void RdbServiceProxy::OnDataChange(const std::string& storeName, const std::vect std::string RdbServiceProxy::ObtainDistributedTableName(const std::string &device, const std::string &table) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return ""; - } - if (!ITypesUtil::Marshal(data, device, table)) { - ZLOGE("write to message parcel failed"); - return ""; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_CMD_OBTAIN_TABLE, data, reply, option) != 0) { - ZLOGE("send request failed"); + int32_t status = IPC_SEND(RDB_SERVICE_CMD_OBTAIN_TABLE, reply, device, table); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, device:%{public}.6s, table:%{public}s", status, device.c_str(), table.c_str()); return ""; } return reply.ReadString(); } -int32_t RdbServiceProxy::InitNotifier(const RdbSyncerParam& param) +int32_t RdbServiceProxy::InitNotifier(const std::string &bundleName) { - notifier_ = new (std::nothrow) RdbNotifierStub( - [this] (uint32_t seqNum, const SyncResult& result) { - OnSyncComplete(seqNum, result); - }, - [this] (const std::string& storeName, const std::vector& devices) { - OnDataChange(storeName, devices); - } - ); + notifier_ = new (std::nothrow) + RdbNotifierStub([this](uint32_t seqNum, const SyncResult &result) { OnSyncComplete(seqNum, result); }, + [this](const std::string &storeName, const std::vector &devices) { + OnDataChange(storeName, devices); + }); if (notifier_ == nullptr) { ZLOGE("create notifier failed"); return RDB_ERROR; } - if (InitNotifier(param, notifier_->AsObject().GetRefPtr()) != RDB_OK) { + if (InitNotifier(bundleName, notifier_->AsObject().GetRefPtr()) != RDB_OK) { notifier_ = nullptr; return RDB_ERROR; } @@ -91,27 +104,14 @@ int32_t RdbServiceProxy::InitNotifier(const RdbSyncerParam& param) return RDB_OK; } -int32_t RdbServiceProxy::InitNotifier(const RdbSyncerParam ¶m, const sptr notifier) +int32_t RdbServiceProxy::InitNotifier(const std::string& bundleName, const sptr ¬ifier) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param, notifier)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_CMD_INIT_NOTIFIER, data, reply, option) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; + int32_t status = IPC_SEND(RDB_SERVICE_CMD_INIT_NOTIFIER, reply, bundleName, notifier); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s", status, bundleName.c_str()); } - - int32_t res = RDB_ERROR; - return reply.ReadInt32(res) ? res : RDB_ERROR; + return status; } uint32_t RdbServiceProxy::GetSeqNum() @@ -122,21 +122,12 @@ uint32_t RdbServiceProxy::GetSeqNum() int32_t RdbServiceProxy::DoSync(const RdbSyncerParam& param, const SyncOption &option, const RdbPredicates &predicates, SyncResult& result) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param, option, predicates)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption opt; - if (Remote()->SendRequest(RDB_SERVICE_CMD_SYNC, data, reply, opt) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; + int32_t status = IPC_SEND(RDB_SERVICE_CMD_SYNC, reply, param, option, predicates); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", + status, param.bundleName_.c_str(), param.storeName_.c_str()); + return status; } if (!ITypesUtil::Unmarshal(reply, result)) { @@ -165,25 +156,13 @@ int32_t RdbServiceProxy::DoSync(const RdbSyncerParam& param, const SyncOption &o int32_t RdbServiceProxy::DoAsync(const RdbSyncerParam& param, uint32_t seqNum, const SyncOption &option, const RdbPredicates &predicates) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param, seqNum, option, predicates)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption opt; - if (Remote()->SendRequest(RDB_SERVICE_CMD_ASYNC, data, reply, opt) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; + int32_t status = IPC_SEND(RDB_SERVICE_CMD_ASYNC, reply, param, seqNum, option, predicates); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s, seqNum:%{public}u", + status, param.bundleName_.c_str(), param.storeName_.c_str(), seqNum); } - - int32_t res = RDB_ERROR; - return reply.ReadInt32(res) ? res : RDB_ERROR; + return status; } int32_t RdbServiceProxy::DoAsync(const RdbSyncerParam& param, const SyncOption &option, @@ -208,25 +187,13 @@ int32_t RdbServiceProxy::DoAsync(const RdbSyncerParam& param, const SyncOption & int32_t RdbServiceProxy::SetDistributedTables(const RdbSyncerParam& param, const std::vector &tables) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param, tables)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_CMD_SET_DIST_TABLE, data, reply, option) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; + int32_t status = IPC_SEND(RDB_SERVICE_CMD_SET_DIST_TABLE, reply, param, tables); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", + status, param.bundleName_.c_str(), param.storeName_.c_str()); } - - int32_t res = RDB_ERROR; - return reply.ReadInt32(res) ? res : RDB_ERROR; + return status; } int32_t RdbServiceProxy::Sync(const RdbSyncerParam& param, const SyncOption &option, @@ -276,25 +243,13 @@ int32_t RdbServiceProxy::Subscribe(const RdbSyncerParam ¶m, const SubscribeO int32_t RdbServiceProxy::DoSubscribe(const RdbSyncerParam ¶m) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_CMD_SUBSCRIBE, data, reply, option) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; + int32_t status = IPC_SEND(RDB_SERVICE_CMD_SUBSCRIBE, reply, param); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", + status, param.bundleName_.c_str(), param.storeName_.c_str()); } - - int32_t res = RDB_ERROR; - return reply.ReadInt32(res) ? res : RDB_ERROR; + return status; } int32_t RdbServiceProxy::UnSubscribe(const RdbSyncerParam ¶m, const SubscribeOption &option, @@ -314,50 +269,23 @@ int32_t RdbServiceProxy::UnSubscribe(const RdbSyncerParam ¶m, const Subscrib int32_t RdbServiceProxy::DoUnSubscribe(const RdbSyncerParam ¶m) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_CMD_UNSUBSCRIBE, data, reply, option) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; + int32_t status = IPC_SEND(RDB_SERVICE_CMD_UNSUBSCRIBE, reply, param); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", + status, param.bundleName_.c_str(), param.storeName_.c_str()); } - - int32_t res = RDB_ERROR; - return reply.ReadInt32(res) ? res : RDB_ERROR; + return status; } int32_t RdbServiceProxy::RemoteQuery(const RdbSyncerParam& param, const std::string& device, const std::string& sql, const std::vector& selectionArgs, sptr& resultSet) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param, device, sql, selectionArgs)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_CMD_REMOTE_QUERY, data, reply, option) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; - } - - int32_t status = reply.ReadInt32(); - if (status != RdbStatus::RDB_OK) { - ZLOGE("remote query failed, server side status is %{public}d", status); + int32_t status = IPC_SEND(RDB_SERVICE_CMD_REMOTE_QUERY, reply, param, device, sql, selectionArgs); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s, device:%{public}.6s", + status, param.bundleName_.c_str(), param.storeName_.c_str(), device.c_str()); return status; } @@ -389,55 +317,36 @@ void RdbServiceProxy::ImportObservers(ObserverMap &observers) int32_t RdbServiceProxy::CreateRDBTable( const RdbSyncerParam ¶m, const std::string &writePermission, const std::string &readPermission) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param, writePermission, readPermission)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_CREATE_RDB_TABLE, data, reply, option) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; - } - - int32_t status = reply.ReadInt32(); - if (status != RdbStatus::RDB_OK) { - ZLOGE("remote query failed, server side status is %{public}d", status); - return status; - } - return RDB_OK; + int32_t status = IPC_SEND(RDB_SERVICE_CREATE_RDB_TABLE, reply, param, writePermission, readPermission); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s," + "writePermission:%{public}.6s, readPermission:%{public}.6s", + status, param.bundleName_.c_str(), param.storeName_.c_str(), + writePermission.c_str(), readPermission.c_str()); + } + return status; } int32_t RdbServiceProxy::DestroyRDBTable(const RdbSyncerParam ¶m) { - MessageParcel data; - if (!data.WriteInterfaceToken(IRdbService::GetDescriptor())) { - ZLOGE("write descriptor failed"); - return RDB_ERROR; - } - if (!ITypesUtil::Marshal(data, param)) { - ZLOGE("write to message parcel failed"); - return RDB_ERROR; - } - MessageParcel reply; - MessageOption option; - if (Remote()->SendRequest(RDB_SERVICE_DESTROY_RDB_TABLE, data, reply, option) != 0) { - ZLOGE("send request failed"); - return RDB_ERROR; + int32_t status = IPC_SEND(RDB_SERVICE_DESTROY_RDB_TABLE, reply, param); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", + status, param.bundleName_.c_str(), param.storeName_.c_str()); } + return status; +} - int32_t status = reply.ReadInt32(); - if (status != RdbStatus::RDB_OK) { - ZLOGE("remote query failed, server side status is %{public}d", status); - return status; +int32_t RdbServiceProxy::GetSchema(const std::string &bundleName, const std::string &storeName) +{ + MessageParcel reply; + int32_t status = IPC_SEND(RDB_SERVICE_CMD_GET_SCHEMA, reply, bundleName, storeName); + if (status != RDB_OK) { + ZLOGE("status:%{public}d, bundleName:%{public}s, storeName:%{public}s", status, bundleName.c_str(), + storeName.c_str()); } - return RDB_OK; + return status; } } // namespace OHOS::DistributedRdb diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp index b922dda1e359e447bc69d2bb13f5e75c1c60caa3..23b6117484f055c9586b7b2e1cf4748f0662c2db 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_config.cpp @@ -45,6 +45,7 @@ RdbStoreConfig::RdbStoreConfig(const std::string &name, StorageMode storageMode, syncMode(syncMode), readOnly(isReadOnly), databaseFileType(databaseFileType), + encryptKey_(encryptKey), securityLevel(securityLevel), isCreateNecessary_(isCreateNecessary), autoCheck(autoCheck), @@ -54,7 +55,10 @@ RdbStoreConfig::RdbStoreConfig(const std::string &name, StorageMode storageMode, { } -RdbStoreConfig::~RdbStoreConfig() = default; +RdbStoreConfig::~RdbStoreConfig() +{ + ClearEncryptKey(); +} /** * Obtains the database name. @@ -372,4 +376,19 @@ void RdbStoreConfig::SetReadConSize(int readConSize) { readConSize_= readConSize; } + +void RdbStoreConfig::SetEncryptKey(const std::vector &encryptKey) +{ + encryptKey_ = encryptKey; +} + +std::vector RdbStoreConfig::GetEncryptKey() const +{ + return encryptKey_; +} + +void RdbStoreConfig::ClearEncryptKey() +{ + encryptKey_.assign(encryptKey_.size(), 0); +} } // namespace OHOS::NativeRdb diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp index 44664c97023f1e20904cfa70885d92ab04a75634..5c09002fd5344a514cad17df103f9e708d60e879 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_impl.cpp @@ -36,9 +36,12 @@ #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) #include "iresult_set.h" -#include "rdb_manager.h" +#include "rdb_device_manager_adapter.h" +#include "rdb_manager_impl.h" +#include "relational_store_manager.h" #include "rdb_security_manager.h" #include "result_set_proxy.h" +#include "runtime_config.h" #include "sqlite_shared_result_set.h" #endif @@ -62,6 +65,7 @@ std::shared_ptr RdbStoreImpl::Open(const RdbStoreConfig &config, int & int RdbStoreImpl::InnerOpen(const RdbStoreConfig &config) { + LOG_INFO("open %{public}s.", SqliteUtils::Anonymous(config.GetPath()).c_str()); int errCode = E_OK; connectionPool = SqliteConnectionPool::Create(config, errCode); if (connectionPool == nullptr) { @@ -84,19 +88,30 @@ int RdbStoreImpl::InnerOpen(const RdbStoreConfig &config) syncerParam_.type_ = config.GetDistributedType(); syncerParam_.isEncrypt_ = config.IsEncrypt(); syncerParam_.password_ = {}; + + std::shared_ptr service = nullptr; + errCode = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(config.GetBundleName(), service); + if (errCode != E_OK) { + LOG_ERROR("RdbStoreImpl::InnerOpen get service failed, err is %{public}d.", errCode); + return E_OK; + } + + errCode = service->GetSchema(config.GetBundleName(), config.GetName()); + if (errCode != E_OK) { + LOG_ERROR("RdbStoreImpl::InnerOpen GetSchema failed, err is %{public}d.", errCode); + return E_OK; + } + // open uri share if (!config.GetUri().empty()) { - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { - LOG_ERROR("RdbStoreImpl::InnerOpen get service failed"); - return -1; - } - if (service->CreateRDBTable(syncerParam_, config.GetWritePermission(), config.GetReadPermission()) != E_OK) { + errCode = service->CreateRDBTable(syncerParam_, config.GetWritePermission(), config.GetReadPermission()); + if (errCode != E_OK) { LOG_ERROR("RdbStoreImpl::InnerOpen service CreateRDBTable failed"); - return -1; + return E_OK; } isShared_ = true; } + #endif return E_OK; } @@ -110,12 +125,11 @@ RdbStoreImpl::RdbStoreImpl() RdbStoreImpl::~RdbStoreImpl() { delete connectionPool; - threadMap.clear(); - idleSessions.clear(); #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) if (isShared_) { - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { + std::shared_ptr service = nullptr; + int errCode = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(syncerParam_.bundleName_, service); + if (errCode != E_OK) { LOG_ERROR("RdbStoreImpl::~RdbStoreImpl get service failed"); return; } @@ -147,17 +161,24 @@ int RdbStoreImpl::BatchInsert(int64_t &outInsertNum, const std::string &table, return E_OK; } // prepare batch data & sql - std::map valuesMap; + std::vector>> vecVectorObj; for (auto iter = initialBatchValues.begin(); iter != initialBatchValues.end(); iter++) { - (*iter).GetAll(valuesMap); - vecVectorObj.push_back(GetInsertParams(valuesMap, table)); - valuesMap.clear(); + auto values = (*iter).GetAll(); + vecVectorObj.push_back(GetInsertParams(values, table)); } // prepare BeginTransaction - connectionPool->AcquireTransaction(); + int errCode = connectionPool->AcquireTransaction(); + if (errCode != E_OK) { + return errCode; + } + SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + if (connection->IsInTransaction()) { connectionPool->ReleaseTransaction(); connectionPool->ReleaseConnection(connection); @@ -166,7 +187,7 @@ int RdbStoreImpl::BatchInsert(int64_t &outInsertNum, const std::string &table, } BaseTransaction transaction(0); connection->SetInTransaction(true); - int errCode = connection->ExecuteSql(transaction.GetTransactionStr()); + errCode = connection->ExecuteSql(transaction.GetTransactionStr()); if (errCode != E_OK) { LOG_ERROR("BeginTransaction with error code %{public}d.", errCode); connection->SetInTransaction(false); @@ -237,22 +258,26 @@ int RdbStoreImpl::InsertWithConflictResolution(int64_t &outRowId, const std::str std::stringstream sql; sql << "INSERT" << conflictClause << " INTO " << table << '('; - std::map valuesMap; - initialValues.GetAll(valuesMap); std::vector bindArgs; - for (auto iter = valuesMap.begin(); iter != valuesMap.end(); iter++) { - sql << ((iter == valuesMap.begin()) ? "" : ","); - sql << iter->first; // columnName - bindArgs.push_back(iter->second); // columnValue + const char *split = ""; + for (auto &[key, val] : initialValues.values_) { + sql << split; + sql << key; // columnName + bindArgs.push_back(val); // columnValue + split = ","; } sql << ") VALUES ("; - for (size_t i = 0; i < valuesMap.size(); i++) { + for (size_t i = 0; i < initialValues.Size(); i++) { sql << ((i == 0) ? "?" : ",?"); } sql << ')'; SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + errCode = connection->ExecuteForLastInsertedRowId(outRowId, sql.str(), bindArgs); connectionPool->ReleaseConnection(connection); @@ -293,13 +318,13 @@ int RdbStoreImpl::UpdateWithConflictResolution(int &changedRows, const std::stri std::stringstream sql; sql << "UPDATE" << conflictClause << " " << table << " SET "; - std::map valuesMap; - values.GetAll(valuesMap); std::vector bindArgs; - for (auto iter = valuesMap.begin(); iter != valuesMap.end(); iter++) { - sql << ((iter == valuesMap.begin()) ? "" : ","); - sql << iter->first << "=?"; // columnName - bindArgs.push_back(iter->second); // columnValue + const char * split = ""; + for (auto &[key, val] : values.values_) { + sql << split; + sql << key << "=?"; // columnName + bindArgs.push_back(val); // columnValue + split = ","; } if (whereClause.empty() == false) { @@ -311,6 +336,10 @@ int RdbStoreImpl::UpdateWithConflictResolution(int &changedRows, const std::stri } SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + errCode = connection->ExecuteForChangedRowCount(changedRows, sql.str(), bindArgs); connectionPool->ReleaseConnection(connection); @@ -342,6 +371,10 @@ int RdbStoreImpl::Delete(int &deletedRows, const std::string &table, const std:: } SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = connection->ExecuteForChangedRowCount(deletedRows, sql.str(), bindArgs); connectionPool->ReleaseConnection(connection); @@ -353,7 +386,6 @@ std::unique_ptr RdbStoreImpl::Query( const AbsRdbPredicates &predicates, const std::vector columns) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - LOG_DEBUG("RdbStoreImpl::Query on called."); std::vector selectionArgs = predicates.GetWhereArgs(); std::string sql = SqliteSqlBuilder::BuildQueryString(predicates, columns); return QuerySql(sql, selectionArgs); @@ -363,21 +395,20 @@ std::unique_ptr RdbStoreImpl::QueryByStep( const AbsRdbPredicates &predicates, const std::vector columns) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - LOG_DEBUG("RdbStoreImpl::QueryByStep on called."); std::vector selectionArgs = predicates.GetWhereArgs(); std::string sql = SqliteSqlBuilder::BuildQueryString(predicates, columns); return QueryByStep(sql, selectionArgs); } std::shared_ptr RdbStoreImpl::RemoteQuery(const std::string &device, - const AbsRdbPredicates &predicates, const std::vector &columns) + const AbsRdbPredicates &predicates, const std::vector &columns, int &errCode) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - LOG_DEBUG("RdbStoreImpl::RemoteQuery on called."); std::vector selectionArgs = predicates.GetWhereArgs(); std::string sql = SqliteSqlBuilder::BuildQueryString(predicates, columns); - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { + std::shared_ptr service = nullptr; + errCode = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(syncerParam_.bundleName_, service); + if (errCode != E_OK) { LOG_ERROR("RdbStoreImpl::RemoteQuery get service failed"); return nullptr; } @@ -500,6 +531,10 @@ int RdbStoreImpl::ExecuteForLastInsertedRowId(int64_t &outValue, const std::stri const std::vector &bindArgs) { SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = connection->ExecuteForLastInsertedRowId(outValue, sql, bindArgs); connectionPool->ReleaseConnection(connection); return errCode; @@ -510,6 +545,10 @@ int RdbStoreImpl::ExecuteForChangedRowCount(int64_t &outValue, const std::string { int changeRow = 0; SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = connection->ExecuteForChangedRowCount(changeRow, sql, bindArgs); connectionPool->ReleaseConnection(connection); outValue = changeRow; @@ -522,7 +561,7 @@ int RdbStoreImpl::ExecuteForChangedRowCount(int64_t &outValue, const std::string int RdbStoreImpl::Backup(const std::string databasePath, const std::vector destEncryptKey) { if (databasePath.empty()) { - LOG_ERROR("Backup:Empty databasePath."); + LOG_ERROR("Empty databasePath."); return E_INVALID_FILE_PATH; } std::string backupFilePath; @@ -530,13 +569,13 @@ int RdbStoreImpl::Backup(const std::string databasePath, const std::vector bindArgs; bindArgs.push_back(ValueObject(backupFilePath)); @@ -598,6 +637,10 @@ int RdbStoreImpl::BeginExecuteSql(const std::string &sql, SqliteConnection **con bool assumeReadOnly = SqliteUtils::IsSqlReadOnly(type); bool isReadOnly = false; *connection = connectionPool->AcquireConnection(assumeReadOnly); + if (*connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = (*connection)->Prepare(sql, isReadOnly); if (errCode != 0) { connectionPool->ReleaseConnection(*connection); @@ -607,6 +650,10 @@ int RdbStoreImpl::BeginExecuteSql(const std::string &sql, SqliteConnection **con if (isReadOnly == (*connection)->IsWriteConnection()) { connectionPool->ReleaseConnection(*connection); *connection = connectionPool->AcquireConnection(isReadOnly); + if (*connection == nullptr) { + return E_CON_OVER_LIMIT; + } + if (!isReadOnly && !(*connection)->IsWriteConnection()) { LOG_ERROR("StoreSession BeginExecutea : read connection can not execute write operation"); connectionPool->ReleaseConnection(*connection); @@ -625,6 +672,10 @@ bool RdbStoreImpl::IsHoldingConnection() int RdbStoreImpl::GiveConnectionTemporarily(int64_t milliseconds) { SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + if (connection->IsInTransaction()) { return E_STORE_SESSION_NOT_GIVE_CONNECTION_TEMPORARILY; } @@ -713,6 +764,10 @@ int RdbStoreImpl::BeginTransaction() DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); BaseTransaction transaction(connectionPool->getTransactionStack().size()); SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = connection->ExecuteSql(transaction.GetTransactionStr()); connectionPool->ReleaseConnection(connection); if (errCode != E_OK) { @@ -740,6 +795,10 @@ int RdbStoreImpl::RollBack() connectionPool->getTransactionStack().top().SetChildFailure(true); } SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = connection->ExecuteSql(transaction.GetRollbackStr()); connectionPool->ReleaseConnection(connection); if (connectionPool->getTransactionStack().empty()) { @@ -770,6 +829,10 @@ int RdbStoreImpl::Commit() } SqliteConnection *connection = connectionPool->AcquireConnection(false); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = connection->ExecuteSql(sqlStr); connectionPool->ReleaseConnection(connection); connection->SetInTransaction(false); @@ -795,7 +858,13 @@ int RdbStoreImpl::FreeTransaction(SqliteConnection *connection, const std::strin bool RdbStoreImpl::IsInTransaction() { - return connectionPool->AcquireConnection(false)->IsInTransaction(); + bool res = true; + auto connection = connectionPool->AcquireConnection(false); + if (connection != nullptr) { + res = connection->IsInTransaction(); + connectionPool->ReleaseConnection(connection); + } + return res; } int RdbStoreImpl::CheckAttach(const std::string &sql) @@ -815,6 +884,10 @@ int RdbStoreImpl::CheckAttach(const std::string &sql) bool isRead = SqliteDatabaseUtils::BeginExecuteSql(GlobalExpr::PRAGMA_JOUR_MODE_EXP); SqliteConnection *connection = connectionPool->AcquireConnection(isRead); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = connection->ExecuteGetString(journalMode, GlobalExpr::PRAGMA_JOUR_MODE_EXP, std::vector()); connectionPool->ReleaseConnection(connection); @@ -863,13 +936,13 @@ bool RdbStoreImpl::PathToRealPath(const std::string &path, std::string &realPath } #else if (realpath(path.c_str(), tmpPath) == NULL) { - LOG_ERROR("path to realpath error"); + LOG_ERROR("path (%{public}s) to realpath error", SqliteUtils::Anonymous(path).c_str()); return false; } #endif realPath = tmpPath; if (access(realPath.c_str(), F_OK) != 0) { - LOG_ERROR("check realpath (%{public}s) error", realPath.c_str()); + LOG_ERROR("check realpath (%{public}s) error", SqliteUtils::Anonymous(realPath).c_str()); return false; } return true; @@ -1001,12 +1074,12 @@ std::unique_ptr RdbStoreImpl::QueryByStep(const std::string &sql, } #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) -bool RdbStoreImpl::SetDistributedTables(const std::vector &tables) +int RdbStoreImpl::SetDistributedTables(const std::vector &tables) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); if (tables.empty()) { LOG_WARN("The distributed tables to be set is empty."); - return true; + return E_OK; } if (isEncrypt_) { bool status = false; @@ -1019,16 +1092,17 @@ bool RdbStoreImpl::SetDistributedTables(const std::vector &tables) } } - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { - return false; + std::shared_ptr service = nullptr; + int errCode = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(syncerParam_.bundleName_, service); + if (errCode != E_OK) { + return errCode; } int32_t errorCode = service->SetDistributedTables(syncerParam_, tables); if (errorCode != E_OK) { LOG_ERROR("Fail to set distributed tables, error=%{public}d", errorCode); syncerParam_.password_.assign(syncerParam_.password_.size(), 0); syncerParam_.password_.clear(); - return false; + return errorCode; } if (isEncrypt_) { @@ -1037,53 +1111,66 @@ bool RdbStoreImpl::SetDistributedTables(const std::vector &tables) RdbSecurityManager::GetInstance().SetKeyDistributedStatus( RdbSecurityManager::KeyFileType::PUB_KEY_FILE, true); } - return true; + return E_OK; } -std::string RdbStoreImpl::ObtainDistributedTableName(const std::string &device, const std::string &table) +std::string RdbStoreImpl::ObtainDistributedTableName(const std::string &device, const std::string &table, int &errCode) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { + + std::string uuid; + DeviceManagerAdaptor::RdbDeviceManagerAdaptor &deviceManager = + DeviceManagerAdaptor::RdbDeviceManagerAdaptor::GetInstance(syncerParam_.bundleName_); + errCode = deviceManager.GetEncryptedUuidByNetworkId(device, uuid); + if (errCode != E_OK) { + LOG_ERROR("GetUuid is failed"); return ""; } - auto distTable = service->ObtainDistributedTableName(device, table); - return distTable; + + auto translateCall = [uuid](const std::string &oriDevId, const DistributedDB::StoreInfo &info) { + return uuid; + }; + DistributedDB::RuntimeConfig::SetTranslateToDeviceIdCallback(translateCall); + + return DistributedDB::RelationalStoreManager::GetDistributedTableName(uuid, table); } -bool RdbStoreImpl::Sync(const SyncOption &option, const AbsRdbPredicates &predicate, const SyncCallback &callback) +int RdbStoreImpl::Sync(const SyncOption &option, const AbsRdbPredicates &predicate, const SyncCallback &callback) { DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__)); - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { - return false; + std::shared_ptr service = nullptr; + int errCode = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(syncerParam_.bundleName_, service); + if (errCode != E_OK) { + LOG_ERROR("GetRdbService is failed, err is %{public}d.", errCode); + return errCode; } - if (service->Sync(syncerParam_, option, predicate.GetDistributedPredicates(), callback) != 0) { - LOG_ERROR("failed"); - return false; + errCode = service->Sync(syncerParam_, option, predicate.GetDistributedPredicates(), callback); + if (errCode != E_OK) { + LOG_ERROR("Sync is failed, err is %{public}d.", errCode); + return errCode; } - LOG_INFO("success"); - return true; + return E_OK; } -bool RdbStoreImpl::Subscribe(const SubscribeOption &option, RdbStoreObserver *observer) +int RdbStoreImpl::Subscribe(const SubscribeOption &option, RdbStoreObserver *observer) { - LOG_INFO("enter"); - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { - return false; + std::shared_ptr service = nullptr; + int errCode = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(syncerParam_.bundleName_, service); + if (errCode != E_OK) { + return errCode; } - return service->Subscribe(syncerParam_, option, observer) == 0; + return service->Subscribe(syncerParam_, option, observer); } -bool RdbStoreImpl::UnSubscribe(const SubscribeOption &option, RdbStoreObserver *observer) +int RdbStoreImpl::UnSubscribe(const SubscribeOption &option, RdbStoreObserver *observer) { LOG_INFO("enter"); - auto service = DistributedRdb::RdbManager::GetRdbService(syncerParam_); - if (service == nullptr) { - return false; + std::shared_ptr service = nullptr; + int errCode = DistributedRdb::RdbManagerImpl::GetInstance().GetRdbService(syncerParam_.bundleName_, service); + if (errCode != E_OK) { + return errCode; } - return service->UnSubscribe(syncerParam_, option, observer) == 0; + return service->UnSubscribe(syncerParam_, option, observer); } bool RdbStoreImpl::DropDeviceData(const std::vector &devices, const DropOption &option) diff --git a/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp b/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp index a5e8bb479d91fbef5392a85ef8e308c9d7d61d48..86b5137376e02de94cfdea810f663cd4aee967b6 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_store_manager.cpp @@ -28,7 +28,7 @@ namespace OHOS { namespace NativeRdb { -RdbStoreNode::RdbStoreNode(const std::shared_ptr &rdbStore) : rdbStore_(rdbStore) {} +RdbStoreNode::RdbStoreNode(const std::shared_ptr &rdbStore) : rdbStore_(rdbStore), timerId_(0) {} RdbStoreNode &RdbStoreNode::operator=(const std::shared_ptr &store) { diff --git a/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp b/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp index 2521f2739548b3d3ba402d006b173bc739a2f9cf..bc423e6f09a9c01e6d462aba897eec921577e13b 100644 --- a/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp +++ b/relational_store/frameworks/native/rdb/src/rdb_types_util.cpp @@ -28,6 +28,15 @@ bool Unmarshalling(SyncerParam &output, MessageParcel &data) output.level_, output.type_, output.isAutoSync_, output.isEncrypt_, output.password_); } +template<> bool Marshalling(const CloudParam &input, MessageParcel &data) +{ + return ITypesUtil::Marshal(data, input.bundleName, input.storeName); +} +template<> bool Unmarshalling(CloudParam &output, MessageParcel &data) +{ + return ITypesUtil::Unmarshal(data, output.bundleName, output.storeName); +} + template<> bool Marshalling(const SyncOption &input, MessageParcel &data) { @@ -81,11 +90,21 @@ template<> bool ITypesUtil::Unmarshalling(ValueObject &output, MessageParcel &da template<> bool ITypesUtil::Marshalling(const ValuesBucket &input, MessageParcel &data) { - return ITypesUtil::Marshal(data, input.valuesMap); + return ITypesUtil::Marshal(data, input.values_); } template<> bool ITypesUtil::Unmarshalling(ValuesBucket &output, MessageParcel &data) { - return ITypesUtil::Marshal(data, output.valuesMap); + return ITypesUtil::Unmarshal(data, output.values_); +} +template<> +bool ITypesUtil::Marshalling(const Asset &input, MessageParcel &data) +{ + return ITypesUtil::Marshal(data, input.version, input.name, input.size, input.modifyTime, input.uri); +} +template<> +bool ITypesUtil::Unmarshalling(Asset &output, MessageParcel &data) +{ + return ITypesUtil::Unmarshal(data, output.version, output.name, output.size, output.modifyTime, output.uri); +} } -} \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/result_set_proxy.cpp b/relational_store/frameworks/native/rdb/src/result_set_proxy.cpp index 91558f05167cadccbf4872b6043bd1c8320c4f76..1dfdb58028878e8ff4e9c892249e705d85a5169c 100644 --- a/relational_store/frameworks/native/rdb/src/result_set_proxy.cpp +++ b/relational_store/frameworks/native/rdb/src/result_set_proxy.cpp @@ -239,6 +239,11 @@ int ResultSetProxy::IsColumnNull(int columnIndex, bool &isNull) return E_OK; } +int ResultSetProxy::GetRow(RowEntity &rowEntity) +{ + return E_NOT_SUPPORT; +} + bool ResultSetProxy::IsClosed() const { MessageParcel data, reply; diff --git a/relational_store/frameworks/native/rdb/src/share_block.cpp b/relational_store/frameworks/native/rdb/src/share_block.cpp index 2015e00192d1f610871cac77da14dbf114f3c0de..32b75c3cf5d6e40656446f99ce636f1e9aff0a62 100644 --- a/relational_store/frameworks/native/rdb/src/share_block.cpp +++ b/relational_store/frameworks/native/rdb/src/share_block.cpp @@ -116,7 +116,6 @@ void FillSharedBlockOpt(SharedBlockInfo *info) while (!gotException) { int err = sqlite3_step(info->statement); if (err == SQLITE_DONE) { - LOG_WARN("Processed all rows after optimization."); break; } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) { LOG_WARN("Database locked, retrying"); diff --git a/relational_store/frameworks/native/rdb/src/sqlite_config.cpp b/relational_store/frameworks/native/rdb/src/sqlite_config.cpp index dc7afbf42366ac4a35f087c01f392b1c1779755b..00c914bffba992c78c9926fc40ea0e909c39d275 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_config.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_config.cpp @@ -31,6 +31,7 @@ SqliteConfig::SqliteConfig(const RdbStoreConfig &config) } #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) isEncrypt = config.IsEncrypt(); + encryptKey_ = config.GetEncryptKey(); isCreateNecessary = config.IsCreateNecessary(); #endif @@ -41,7 +42,12 @@ SqliteConfig::SqliteConfig(const RdbStoreConfig &config) this->readConSize_ = config.GetReadConSize(); } -SqliteConfig::~SqliteConfig() = default; +SqliteConfig::~SqliteConfig() +{ +#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) + ClearEncryptKey(); +#endif +} std::string SqliteConfig::GetPath() const { @@ -124,7 +130,7 @@ void SqliteConfig::SetReadConSize(int readConSize) } #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) -bool SqliteConfig::IsEncrypt() const +bool SqliteConfig::IsAutoEncrypt() const { return isEncrypt; } @@ -143,6 +149,21 @@ void SqliteConfig::SetCreateNecessary(bool CreateNecessary) { this->isCreateNecessary = CreateNecessary; } + +void SqliteConfig::SetEncryptKey(const std::vector &encryptKey) +{ + encryptKey_ = encryptKey; +} + +std::vector SqliteConfig::GetEncryptKey() const +{ + return encryptKey_; +} + +void SqliteConfig::ClearEncryptKey() +{ + encryptKey_.assign(encryptKey_.size(), 0); +} #endif } // namespace NativeRdb } // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp index 06724dc3255a54ff4640d3b3f58b964858c446fa..49014e8c39327df592d96ca8580c21979a7826b1 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_connection.cpp @@ -45,11 +45,16 @@ namespace NativeRdb { #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) // error status const int ERROR_STATUS = -1; +using RdbKeyFile = RdbSecurityManager::KeyFileType; #endif SqliteConnection *SqliteConnection::Open(const SqliteConfig &config, bool isWriteConnection, int &errCode) { - auto connection = new SqliteConnection(isWriteConnection); + auto connection = new (std::nothrow) SqliteConnection(isWriteConnection); + if (connection == nullptr) { + LOG_ERROR("SqliteConnection::Open new failed, connection is nullptr"); + return nullptr; + } errCode = connection->InnerOpen(config); if (errCode != E_OK) { delete connection; @@ -123,9 +128,11 @@ int SqliteConnection::InnerOpen(const SqliteConfig &config) return errCode; } - errCode = sqlite3_wal_checkpoint_v2(dbHandle, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr); - if (errCode != SQLITE_OK) { - LOG_WARN("sqlite checkpoint errCode is %{public}d", errCode); + if (isWriteConnection) { + errCode = sqlite3_wal_checkpoint_v2(dbHandle, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr); + if (errCode != SQLITE_OK) { + LOG_WARN("sqlite checkpoint errCode is %{public}d", errCode); + } } filePath = dbPath; @@ -145,14 +152,12 @@ int SqliteConnection::Config(const SqliteConfig &config) return errCode; } -#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) - errCode = ManageKey(config); + errCode = SetEncryptAlgo(config); if (errCode != E_OK) { return errCode; } -#endif - errCode = SetEncryptAlgo(config); + errCode = SetEncryptKey(config); if (errCode != E_OK) { return errCode; } @@ -217,31 +222,68 @@ int SqliteConnection::SetPageSize(const SqliteConfig &config) int SqliteConnection::SetEncryptAlgo(const SqliteConfig &config) { int errCode = E_OK; - if (config.GetEncryptAlgo().compare(GlobalExpr::ENCRYPT_ALGO) == 0) { +#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) + if (!config.IsAutoEncrypt() && config.GetEncryptKey().empty()) { return errCode; } - - // first to get the value, then to set algo +#endif std::string sqlStr = "PRAGMA codec_hmac_algo=" + config.GetEncryptAlgo(); errCode = ExecuteSql(sqlStr); if (errCode != E_OK) { LOG_ERROR("SqliteConnection SetEncryptAlgorithm fail, err = %{public}d", errCode); + return errCode; } + + sqlStr = "PRAGMA codec_rekey_hmac_algo=" + config.GetEncryptAlgo(); + errCode = ExecuteSql(sqlStr); + if (errCode != E_OK) { + LOG_ERROR("SqliteConnection set rekey Algo fail, err = %{public}d", errCode); + return errCode; + } + return errCode; } -int SqliteConnection::SetEncryptKey(const std::vector &encryptKey) +int SqliteConnection::SetEncryptKey(const SqliteConfig &config) { - if (encryptKey.empty()) { +#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) + std::vector key; + RdbPassword rdbPwd; + if (!config.GetEncryptKey().empty() && !config.IsAutoEncrypt()) { + key = config.GetEncryptKey(); + } else if (config.IsAutoEncrypt()) { + rdbPwd = RdbSecurityManager::GetInstance().GetRdbPassword(RdbKeyFile::PUB_KEY_FILE); + key = std::vector(rdbPwd.GetData(), rdbPwd.GetData() + rdbPwd.GetSize()); + } else { return E_OK; } - int errCode = sqlite3_key(dbHandle, static_cast(encryptKey.data()), encryptKey.size()); + int errCode = sqlite3_key(dbHandle, static_cast(key.data()), static_cast(key.size())); + key.assign(key.size(), 0); if (errCode != SQLITE_OK) { LOG_ERROR("SqliteConnection SetEncryptKey fail, err = %{public}d", errCode); return SQLiteError::ErrNo(errCode); } + if (rdbPwd.isKeyExpired) { + rdbPwd = RdbSecurityManager::GetInstance().GetRdbPassword(RdbKeyFile::PUB_KEY_FILE_NEW_KEY); + if (!rdbPwd.IsValid()) { + RdbSecurityManager::GetInstance().DelRdbSecretDataFile(RdbKeyFile::PUB_KEY_FILE_NEW_KEY); + LOG_ERROR("new key is not valid."); + return E_OK; + } + key = std::vector(rdbPwd.GetData(), rdbPwd.GetData() + rdbPwd.GetSize()); + errCode = sqlite3_rekey(dbHandle, static_cast(key.data()), static_cast(key.size())); + key.assign(key.size(), 0); + if (errCode != SQLITE_OK) { + LOG_ERROR("ReKey failed, err = %{public}d", errCode); + RdbSecurityManager::GetInstance().DelRdbSecretDataFile(RdbKeyFile::PUB_KEY_FILE_NEW_KEY); + return E_OK; + } + + RdbSecurityManager::GetInstance().UpdateKeyFile(); + } +#endif return E_OK; } @@ -253,7 +295,6 @@ int SqliteConnection::SetPersistWal() LOG_ERROR("failed"); return E_SET_PERSIST_WAL; } - LOG_INFO("success"); return E_OK; } @@ -264,7 +305,6 @@ int SqliteConnection::SetBusyTimeout(int timeout) LOG_ERROR("set buys timeout failed, errCode=%{public}d", errCode); return errCode; } - LOG_INFO("success"); return E_OK; } @@ -740,52 +780,6 @@ int SqliteConnection::ExecuteForSharedBlock(int &rowNum, std::string sql, const errCode = statement.ResetStatementAndClearBindings(); return errCode; } - -int SqliteConnection::ManageKey(const SqliteConfig &config) -{ - if (!config.IsEncrypt()) { - return E_OK; - } - bool isKeyFileExists = - RdbSecurityManager::GetInstance().CheckKeyDataFileExists(RdbSecurityManager::KeyFileType::PUB_KEY_FILE); - if (!isKeyFileExists) { - if (InitKey() != E_OK) { - return E_ERROR; - } - } - - return GetKeyFromFile(); -} - -int SqliteConnection::InitKey() -{ - LOG_INFO("Init pub_key file"); - std::vector key = RdbSecurityManager::GetInstance().GenerateRandomNum(RdbSecurityManager::RDB_KEY_SIZE); - if (!RdbSecurityManager::GetInstance().SaveSecretKeyToFile(RdbSecurityManager::KeyFileType::PUB_KEY_FILE, key)) { - LOG_ERROR("Init key SaveSecretKeyToFile failed!"); - key.assign(key.size(), 0); - return E_ERROR; - } - key.assign(key.size(), 0); - return E_OK; -} - -int SqliteConnection::GetKeyFromFile() -{ - LOG_INFO("Get key from pub_key file"); - RdbPassword key = RdbSecurityManager::GetInstance().GetRdbPassword(RdbSecurityManager::KeyFileType::PUB_KEY_FILE); - if (key.GetSize() == 0) { - return E_ERROR; - } - auto keyTemp = std::vector(key.GetData(), key.GetData() + key.GetSize()); - if (SetEncryptKey(keyTemp) != E_OK) { - keyTemp.assign(keyTemp.size(), 0); - return E_ERROR; - } - - keyTemp.assign(keyTemp.size(), 0); - return E_OK; -} #endif void SqliteConnection::SetInTransaction(bool transaction) @@ -805,7 +799,7 @@ int SqliteConnection::LimitWalSize() } std::string walName = sqlite3_filename_wal(sqlite3_db_filename(dbHandle, "main")); - if (SqliteUtils::GetFileSize(walName) < GlobalExpr::DB_WAL_SIZE_LIMIT) { + if (SqliteUtils::GetFileSize(walName) <= GlobalExpr::DB_WAL_SIZE_LIMIT) { return E_OK; } @@ -815,8 +809,9 @@ int SqliteConnection::LimitWalSize() } int fileSize = SqliteUtils::GetFileSize(walName); - if (fileSize >= GlobalExpr::DB_WAL_SIZE_LIMIT) { - LOG_ERROR("the WAL file size over default limit, size: %{public}d", fileSize); + if (fileSize > GlobalExpr::DB_WAL_SIZE_LIMIT) { + LOG_ERROR("the WAL file size over default limit, %{public}s size is %{public}d", + SqliteUtils::Anonymous(walName).c_str(), fileSize); return E_WAL_SIZE_OVER_LIMIT; } diff --git a/relational_store/frameworks/native/rdb/src/sqlite_connection_pool.cpp b/relational_store/frameworks/native/rdb/src/sqlite_connection_pool.cpp index fde0b47352fb130bf57d2bab6ecfc9fcaff9526d..9cae45d76bc758672a7fede89faa56c8b69e6ad1 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_connection_pool.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_connection_pool.cpp @@ -32,9 +32,15 @@ namespace OHOS { namespace NativeRdb { +constexpr std::chrono::seconds WAIT_CONNECT_TIMEOUT(2); + SqliteConnectionPool *SqliteConnectionPool::Create(const RdbStoreConfig &storeConfig, int &errCode) { - auto pool = new SqliteConnectionPool(storeConfig); + auto pool = new (std::nothrow) SqliteConnectionPool(storeConfig); + if (pool == nullptr) { + LOG_ERROR("SqliteConnectionPool::Create new failed, pool is nullptr"); + return nullptr; + } errCode = pool->Init(); if (errCode != E_OK) { delete pool; @@ -114,10 +120,8 @@ void SqliteConnectionPool::CloseAllConnections() SqliteConnection *SqliteConnectionPool::AcquireConnection(bool isReadOnly) { if (isReadOnly && readConnectionCount != 0) { - LOG_DEBUG("AcquireReadConnection"); return AcquireReadConnection(); } else { - LOG_DEBUG("AcquireWriteConnection"); return AcquireWriteConnection(); } } @@ -133,21 +137,24 @@ void SqliteConnectionPool::ReleaseConnection(SqliteConnection *connection) SqliteConnection *SqliteConnectionPool::AcquireWriteConnection() { - LOG_DEBUG("begin"); std::unique_lock lock(writeMutex); - writeCondition.wait(lock, [&] { return !writeConnectionUsed; }); - writeConnectionUsed = true; - LOG_DEBUG("end"); - return writeConnection; + if (writeCondition.wait_for(lock, WAIT_CONNECT_TIMEOUT, [this] { return !writeConnectionUsed; })) { + writeConnectionUsed = true; + return writeConnection; + } + LOG_WARN("writeConnection is %{public}d", writeConnectionUsed); + return nullptr; } -void SqliteConnectionPool::AcquireTransaction() +int SqliteConnectionPool::AcquireTransaction() { - LOG_DEBUG("AcquireTransaction begin"); std::unique_lock lock(transMutex); - transCondition.wait(lock, [&] { return !transactionUsed; }); - transactionUsed = true; - LOG_DEBUG("AcquireTransaction end"); + if (transCondition.wait_for(lock, WAIT_CONNECT_TIMEOUT, [this] { return !transactionUsed; })) { + transactionUsed = true; + return E_OK; + } + LOG_WARN("transactionUsed is %{public}d", transactionUsed); + return E_TRANSACTION_IN_EXECUTE; } void SqliteConnectionPool::ReleaseTransaction() @@ -175,11 +182,15 @@ void SqliteConnectionPool::ReleaseWriteConnection() SqliteConnection *SqliteConnectionPool::AcquireReadConnection() { std::unique_lock lock(readMutex); - readCondition.wait(lock, [&] { return idleReadConnectionCount > 0; }); - SqliteConnection *connection = readConnections.back(); - readConnections.pop_back(); - idleReadConnectionCount--; - return connection; + if (readCondition.wait_for(lock, WAIT_CONNECT_TIMEOUT, [this] { return idleReadConnectionCount > 0; })) { + SqliteConnection *connection = readConnections.back(); + readConnections.pop_back(); + idleReadConnectionCount--; + return connection; + } + LOG_WARN("readConnectionCount is %{public}d, idleReadConnectionCount is %{public}d", readConnectionCount, + idleReadConnectionCount); + return nullptr; } /** diff --git a/relational_store/frameworks/native/rdb/src/sqlite_database_utils.cpp b/relational_store/frameworks/native/rdb/src/sqlite_database_utils.cpp index 712d7870ee23255210efc4f510ad46c95846b3b4..47af023fef0af42346b1ff66075d0ef425c5c53c 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_database_utils.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_database_utils.cpp @@ -24,11 +24,12 @@ #ifdef WINDOWS_PLATFORM #include #endif -#include #include +#include #include "logger.h" #include "rdb_errno.h" +#include "sqlite_utils.h" #ifdef WINDOWS_PLATFORM #define REALPATH(relPath, absPath, ...) (_fullpath(absPath, relPath, ##__VA_ARGS__)) @@ -100,14 +101,15 @@ std::string SqliteDatabaseUtils::StrToUpper(std::string s) void SqliteDatabaseUtils::DeleteFile(std::string &fileName) { if (access(fileName.c_str(), F_OK) != 0) { - LOG_ERROR("File %{private}s does not exist", fileName.c_str()); + LOG_ERROR("access %{public}s errno is %{public}d", SqliteUtils::Anonymous(fileName).c_str(), errno); return; } - if (!remove(fileName.c_str())) { - LOG_ERROR("FileName= %{private}s has been deleted", fileName.c_str()); + + if (remove(fileName.c_str()) != 0) { + LOG_ERROR("remove %{public}s errno is %{public}d", SqliteUtils::Anonymous(fileName).c_str(), errno); return; } - LOG_INFO("Failed to delete File %{private}s", fileName.c_str()); + LOG_INFO("remove %{public}s", SqliteUtils::Anonymous(fileName).c_str()); } /** @@ -116,15 +118,15 @@ void SqliteDatabaseUtils::DeleteFile(std::string &fileName) bool SqliteDatabaseUtils::RenameFile(std::string &oldFileName, std::string &newFileName) { if (access(oldFileName.c_str(), F_OK) != 0) { - LOG_ERROR("File %{private}s does not exist", oldFileName.c_str()); + LOG_ERROR("access %{public}s errno is %{public}d", SqliteUtils::Anonymous(oldFileName).c_str(), errno); return false; } - if (rename(oldFileName.c_str(), newFileName.c_str())) { - LOG_ERROR("Rename oldFileName = %{private}s to newFileName %{private}s", oldFileName.c_str(), - newFileName.c_str()); - return true; + if (rename(oldFileName.c_str(), newFileName.c_str()) != 0) { + LOG_ERROR("Rename %{public}s to %{public}s errno %{public}d", SqliteUtils::Anonymous(oldFileName).c_str(), + SqliteUtils::Anonymous(newFileName).c_str(), errno); + return false; } - return false; + return true; } /** diff --git a/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp b/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp index 1db136a2db38f7046b4ac203a750855e202b4a2d..886012b04047fbd51f25b35e256d2241e4d57acc 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_shared_result_set.cpp @@ -68,6 +68,10 @@ int SqliteSharedResultSet::GetAllColumnNames(std::vector &columnNam } SqliteConnection *connection = connectionPool_->AcquireConnection(true); + if (connection == nullptr) { + return E_CON_OVER_LIMIT; + } + int errCode = PrepareStep(connection); if (errCode) { connectionPool_->ReleaseConnection(connection); @@ -168,6 +172,9 @@ void SqliteSharedResultSet::FillSharedBlock(int requiredPos) bool isRead = SqliteDatabaseUtils::BeginExecuteSql(qrySql); SqliteConnection* connection = connectionPool_->AcquireConnection(isRead); + if (connection == nullptr) { + return; + } if (rowNum == NO_COUNT) { connection->ExecuteForSharedBlock(rowNum, qrySql, bindArgs, GetBlock(), requiredPos, requiredPos, true); @@ -214,13 +221,5 @@ void SqliteSharedResultSet::Finalize() Close(); } } - -int SqliteSharedResultSet::CheckSession() -{ - if (std::this_thread::get_id() != tid) { - return E_STEP_RESULT_SET_CROSS_THREADS; - } - return E_OK; -} } // namespace NativeRdb } // namespace OHOS \ No newline at end of file diff --git a/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp b/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp index 4781b5ed8a4f02b4d7ae8272009ac38cbb505146..836bbe40d3bd3d8528e8c66c2029f31b5f0ccbf7 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_sql_builder.cpp @@ -62,12 +62,12 @@ std::string SqliteSqlBuilder::BuildUpdateString(const ValuesBucket &values, cons .append(" ") .append(tableName) .append(" SET "); - std::map valuesMap; - values.GetAll(valuesMap); - for (auto iter = valuesMap.begin(); iter != valuesMap.end(); iter++) { - sql.append((iter == valuesMap.begin()) ? "" : ","); - sql.append(iter->first).append("=?"); - bindArgs.push_back(iter->second); + const char *split = ""; + for (auto &[key, val] : values.values_) { + sql.append(split); + sql.append(key).append("=?"); + bindArgs.push_back(val); + split = ","; } if (!whereArgs.empty()) { @@ -307,12 +307,12 @@ std::string SqliteSqlBuilder::PredicatesNormalize(const std::string &source, int } auto index = source.rfind("(*"); - if (index != -1) { + if (index != std::string::npos) { return source; } index = source.rfind("."); - if (index == -1) { + if (index == std::string::npos) { return StringUtils::SurroundWithQuote(source, "`"); } diff --git a/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp b/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp index ee454238cf15e4a802307fbf5ab3b5181b81327b..31ace28f4d8a5a22012b0494fb950c3614a70edb 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_statement.cpp @@ -15,10 +15,11 @@ #include "sqlite_statement.h" -#include #include +#include #include "logger.h" +#include "parser.h" #include "rdb_errno.h" #include "sqlite_errno.h" @@ -43,7 +44,7 @@ int SqliteStatement::Prepare(sqlite3 *dbHandle, const std::string &newSql) sqlite3_stmt *stmt = nullptr; int errCode = sqlite3_prepare_v2(dbHandle, newSql.c_str(), newSql.length(), &stmt, nullptr); if (errCode != SQLITE_OK) { - LOG_ERROR("SqliteStatement::Prepare failed err = %{public}d", errCode); + LOG_ERROR("prepare_v2 ret is %{public}d", errCode); if (stmt != nullptr) { sqlite3_finalize(stmt); } @@ -71,7 +72,7 @@ int SqliteStatement::Finalize() columnCount = 0; numParameters = 0; if (errCode != SQLITE_OK) { - LOG_ERROR("SqliteStatement::Finalize failed err = %{public}d", errCode); + LOG_ERROR("finalize ret is %{public}d", errCode); return SQLiteError::ErrNo(errCode); } return E_OK; @@ -98,6 +99,7 @@ int SqliteStatement::BindArguments(const std::vector &bindArgs) con } if (count > numParameters) { + LOG_ERROR("bind args count(%{public}d) > numParameters(%{public}d)", count, numParameters); return E_INVALID_BIND_ARGS_COUNT; } @@ -148,6 +150,7 @@ int SqliteStatement::InnerBindArguments(const std::vector &bindArgs } if (errCode != SQLITE_OK) { + LOG_ERROR("bind ret is %{public}d", errCode); return SQLiteError::ErrNo(errCode); } @@ -165,13 +168,13 @@ int SqliteStatement::ResetStatementAndClearBindings() const int errCode = sqlite3_reset(stmtHandle); if (errCode != SQLITE_OK) { - LOG_ERROR("Reset statement failed. %{public}d", errCode); + LOG_ERROR("reset ret is %{public}d", errCode); return SQLiteError::ErrNo(errCode); } errCode = sqlite3_clear_bindings(stmtHandle); if (errCode != SQLITE_OK) { - LOG_ERROR("Reset clear bindings failed. %{public}d", errCode); + LOG_ERROR("clear_bindings ret is %{public}d", errCode); return SQLiteError::ErrNo(errCode); } @@ -187,6 +190,7 @@ int SqliteStatement::Step() const int SqliteStatement::GetColumnCount(int &count) const { if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); return E_INVALID_STATEMENT; } count = columnCount; @@ -199,6 +203,7 @@ int SqliteStatement::GetColumnCount(int &count) const int SqliteStatement::GetNumParameters(int &numParams) const { if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); return E_INVALID_STATEMENT; } numParams = numParameters; @@ -208,15 +213,18 @@ int SqliteStatement::GetNumParameters(int &numParams) const int SqliteStatement::GetColumnName(int index, std::string &columnName) const { if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); return E_INVALID_STATEMENT; } if (index >= columnCount) { + LOG_ERROR("index (%{public}d) >= columnCount (%{public}d)", index, columnCount); return E_INVALID_COLUMN_INDEX; } const char *name = sqlite3_column_name(stmtHandle, index); if (name == nullptr) { + LOG_ERROR("column_name is null."); return E_ERROR; } columnName = std::string(name); @@ -226,10 +234,12 @@ int SqliteStatement::GetColumnName(int index, std::string &columnName) const int SqliteStatement::GetColumnType(int index, int &columnType) const { if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); return E_INVALID_STATEMENT; } if (index >= columnCount) { + LOG_ERROR("index (%{public}d) >= columnCount (%{public}d)", index, columnCount); return E_INVALID_COLUMN_INDEX; } @@ -243,6 +253,7 @@ int SqliteStatement::GetColumnType(int index, int &columnType) const columnType = type; return E_OK; default: + LOG_ERROR("invalid type %{public}d.", type); return E_ERROR; } } @@ -250,15 +261,18 @@ int SqliteStatement::GetColumnType(int index, int &columnType) const int SqliteStatement::GetColumnBlob(int index, std::vector &value) const { if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); return E_INVALID_STATEMENT; } if (index >= columnCount) { + LOG_ERROR("index (%{public}d) >= columnCount (%{public}d)", index, columnCount); return E_INVALID_COLUMN_INDEX; } int type = sqlite3_column_type(stmtHandle, index); if (type != SQLITE_BLOB && type != SQLITE_TEXT && type != SQLITE_NULL) { + LOG_ERROR("invalid type %{public}d.", type); return E_INVALID_COLUMN_TYPE; } @@ -319,10 +333,12 @@ int SqliteStatement::GetColumnString(int index, std::string &value) const int SqliteStatement::GetColumnLong(int index, int64_t &value) const { if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); return E_INVALID_STATEMENT; } if (index >= columnCount) { + LOG_ERROR("index (%{public}d) >= columnCount (%{public}d)", index, columnCount); return E_INVALID_COLUMN_INDEX; } char *errStr = nullptr; @@ -348,10 +364,12 @@ int SqliteStatement::GetColumnLong(int index, int64_t &value) const int SqliteStatement::GetColumnDouble(int index, double &value) const { if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); return E_INVALID_STATEMENT; } if (index >= columnCount) { + LOG_ERROR("index (%{public}d) >= columnCount (%{public}d)", index, columnCount); return E_INVALID_COLUMN_INDEX; } char *ptr = nullptr; @@ -369,11 +387,69 @@ int SqliteStatement::GetColumnDouble(int index, double &value) const } else if (type == SQLITE_BLOB) { return E_INVALID_COLUMN_TYPE; } else { + LOG_ERROR("invalid type %{public}d.", type); return E_ERROR; } return E_OK; } +int SqliteStatement::GetColumn(int index, ValueObject &value) const +{ + if (stmtHandle == nullptr) { + LOG_ERROR("invalid statement."); + return E_INVALID_STATEMENT; + } + + if (index >= columnCount) { + LOG_ERROR("index (%{public}d) >= columnCount (%{public}d)", index, columnCount); + return E_INVALID_COLUMN_INDEX; + } + + int type = sqlite3_column_type(stmtHandle, index); + switch (type) { + case SQLITE_FLOAT: + value = sqlite3_column_double(stmtHandle, index); + return E_OK; + case SQLITE_INTEGER: + value = static_cast(sqlite3_column_int64(stmtHandle, index)); + return E_OK; + case SQLITE_TEXT: + value = reinterpret_cast(sqlite3_column_text(stmtHandle, index)); + return E_OK; + case SQLITE_NULL: + return E_OK; + default: + break; + } + const char *decl = sqlite3_column_decltype(stmtHandle, index); + if (type != SQLITE_BLOB || decl == nullptr) { + LOG_ERROR("invalid type %{public}d.", type); + return E_ERROR; + } + int size = sqlite3_column_bytes(stmtHandle, index); + auto blob = static_cast(sqlite3_column_blob(stmtHandle, index)); + std::string declType = decl; + if (declType == ValueObject::DeclType()) { + Asset asset; + Parser::ParserRawData(blob, size, asset); + value = std::move(asset); + return E_OK; + } + if (declType == ValueObject::DeclType()) { + Assets assets; + Parser::ParserRawData(blob, size, assets); + value = std::move(assets); + return E_OK; + } + std::vector rawData; + if (size > 0 || blob != nullptr) { + rawData.resize(size); + rawData.assign(blob, blob + size); + } + value = std::move(rawData); + return E_OK; +} + bool SqliteStatement::IsReadOnly() const { return readOnly; diff --git a/relational_store/frameworks/native/rdb/src/sqlite_utils.cpp b/relational_store/frameworks/native/rdb/src/sqlite_utils.cpp index 64516dac9ee5c5ff3e005071c95be6cbdf016257..b03226c56c715185f22ba74e9eaacbdab82892f1 100644 --- a/relational_store/frameworks/native/rdb/src/sqlite_utils.cpp +++ b/relational_store/frameworks/native/rdb/src/sqlite_utils.cpp @@ -42,6 +42,12 @@ const int SqliteUtils::STATEMENT_PRAGMA = 8; const int SqliteUtils::STATEMENT_DDL = 9; const int SqliteUtils::STATEMENT_OTHER = 99; +constexpr int32_t HEAD_SIZE = 3; +constexpr int32_t END_SIZE = 3; +constexpr int32_t MIN_SIZE = HEAD_SIZE + END_SIZE + 3; +constexpr const char *REPLACE_CHAIN = "***"; +constexpr const char *DEFAULT_ANONYMOUS = "******"; + const std::map SqliteUtils::SQL_TYPE_MAP = { { "SEL", SqliteUtils::STATEMENT_SELECT }, { "INS", SqliteUtils::STATEMENT_UPDATE }, @@ -117,6 +123,19 @@ int SqliteUtils::RenameFile(const std::string srcFile, const std::string destFil return rename(srcFile.c_str(), destFile.c_str()); } +std::string SqliteUtils::Anonymous(const std::string &srcFile) +{ + if (srcFile.length() <= HEAD_SIZE) { + return DEFAULT_ANONYMOUS; + } + + if (srcFile.length() < MIN_SIZE) { + return (srcFile.substr(0, HEAD_SIZE) + REPLACE_CHAIN); + } + + return (srcFile.substr(0, HEAD_SIZE) + REPLACE_CHAIN + srcFile.substr(srcFile.length() - END_SIZE, END_SIZE)); +} + int SqliteUtils::GetFileSize(const std::string fileName) { if (fileName.empty() || access(fileName.c_str(), F_OK) != 0) { diff --git a/relational_store/frameworks/native/rdb/src/step_result_set.cpp b/relational_store/frameworks/native/rdb/src/step_result_set.cpp index 88b0610aac2c104b8406bc56ae8162ffd4186c67..cc41d6c653214f9978f3400c1471af41782a1407 100644 --- a/relational_store/frameworks/native/rdb/src/step_result_set.cpp +++ b/relational_store/frameworks/native/rdb/src/step_result_set.cpp @@ -47,13 +47,12 @@ StepResultSet::StepResultSet(SqliteConnectionPool *pool, const std::string &sql, StepResultSet::~StepResultSet() { Close(); - connectionPool_->ReleaseConnection(connection_); - connection_ = nullptr; } int StepResultSet::GetAllColumnNames(std::vector &columnNames) { if (isClosed) { + LOG_ERROR("resultSet closed"); return E_STEP_RESULT_CLOSED; } @@ -64,12 +63,14 @@ int StepResultSet::GetAllColumnNames(std::vector &columnNames) int errCode = PrepareStep(); if (errCode) { + LOG_ERROR("PrepareStep ret %{public}d", errCode); return errCode; } int columnCount = 0; errCode = sqliteStatement->GetColumnCount(columnCount); if (errCode) { + LOG_ERROR("GetColumnCount ret %{public}d", errCode); return errCode; } @@ -79,6 +80,7 @@ int StepResultSet::GetAllColumnNames(std::vector &columnNames) errCode = sqliteStatement->GetColumnName(i, columnName); if (errCode) { columnNames.clear(); + LOG_ERROR("GetColumnName ret %{public}d", errCode); return errCode; } columnNames.push_back(columnName); @@ -90,15 +92,18 @@ int StepResultSet::GetAllColumnNames(std::vector &columnNames) int StepResultSet::GetColumnType(int columnIndex, ColumnType &columnType) { if (isClosed) { + LOG_ERROR("resultSet closed"); return E_STEP_RESULT_CLOSED; } if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); return E_STEP_RESULT_QUERY_NOT_EXECUTED; } int sqliteType; int errCode = sqliteStatement->GetColumnType(columnIndex, sqliteType); if (errCode) { + LOG_ERROR("GetColumnType ret %{public}d", errCode); return errCode; } @@ -146,11 +151,13 @@ int StepResultSet::GetRowCount(int &count) */ int StepResultSet::GoToRow(int position) { - if (!connection_) { - return E_ERROR; + if (connection_ == nullptr) { + LOG_ERROR("Failed as too many connections"); + return E_CON_OVER_LIMIT; } // If the moved position is less than zero, reset the result and return an error if (position < 0) { + LOG_ERROR("position %{public}d.", position); Reset(); return E_ERROR; } @@ -164,6 +171,7 @@ int StepResultSet::GoToRow(int position) while (position != rowPos_) { int errCode = GoToNextRow(); if (errCode) { + LOG_ERROR("GoToNextRow ret %{public}d", errCode); return errCode; } } @@ -178,6 +186,7 @@ int StepResultSet::GoToNextRow() { int errCode = PrepareStep(); if (errCode) { + LOG_ERROR("PrepareStep ret %{public}d", errCode); return errCode; } @@ -187,7 +196,7 @@ int StepResultSet::GoToNextRow() while (errCode == SQLITE_LOCKED || errCode == SQLITE_BUSY) { // The table is locked, retry if (retryCount > STEP_QUERY_RETRY_MAX_TIMES) { - LOG_ERROR("StepResultSet::GoToNextRow retrycount exceeded"); + LOG_ERROR("Step in busy ret is %{public}d", errCode); return E_STEP_RESULT_QUERY_EXCEEDED; } else { // Sleep to give the thread holding the lock a chance to finish @@ -206,7 +215,7 @@ int StepResultSet::GoToNextRow() FinishStep(); return E_STEP_RESULT_IS_AFTER_LAST; } else { - LOG_ERROR("StepResultSet::GoToNextRow step err = %{public}d", errCode); + LOG_ERROR("step ret is %{public}d", errCode); FinishStep(); return SQLiteError::ErrNo(errCode); } @@ -220,12 +229,10 @@ int StepResultSet::Close() isClosed = true; int errCode = FinishStep(); rdb = nullptr; - return errCode; -} -int StepResultSet::CheckSession() -{ - return E_OK; + connectionPool_->ReleaseConnection(connection_); + connection_ = nullptr; + return errCode; } /** @@ -234,6 +241,7 @@ int StepResultSet::CheckSession() int StepResultSet::PrepareStep() { if (isClosed) { + LOG_ERROR("resultSet closed"); return E_STEP_RESULT_CLOSED; } @@ -241,8 +249,13 @@ int StepResultSet::PrepareStep() return E_OK; } + if (connection_ == nullptr) { + LOG_ERROR("too many connections"); + return E_CON_OVER_LIMIT; + } + if (!SqliteDatabaseUtils::IsReadOnlySql(sql)) { - LOG_ERROR("StoreSession BeginStepQuery fail : not select sql !"); + LOG_ERROR("not a select sql!"); return E_EXECUTE_IN_STEP_QUERY; } @@ -250,6 +263,7 @@ int StepResultSet::PrepareStep() sqliteStatement = connection_->BeginStepQuery(errCode, sql, selectionArgs); if (sqliteStatement == nullptr) { connection_->EndStepQuery(); + LOG_ERROR("BeginStepQuery ret is %{public}d", errCode); return errCode; } @@ -261,22 +275,19 @@ int StepResultSet::PrepareStep() */ int StepResultSet::FinishStep() { - int errCode = CheckSession(); - if (errCode != E_OK) { - return errCode; - } - if (sqliteStatement == nullptr) { return E_OK; } sqliteStatement = nullptr; rowPos_ = INIT_POS; - if (connection_ != nullptr) { - errCode = connection_->EndStepQuery(); + if (connection_ == nullptr) { + return E_OK; } + + int errCode = connection_->EndStepQuery(); if (errCode != E_OK) { - LOG_ERROR("StepResultSet::FinishStep err = %d", errCode); + LOG_ERROR("ret is %d", errCode); } return errCode; } @@ -324,6 +335,7 @@ int StepResultSet::IsAtFirstRow(bool &result) const int StepResultSet::GetBlob(int columnIndex, std::vector &blob) { if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); return E_STEP_RESULT_QUERY_NOT_EXECUTED; } @@ -333,12 +345,13 @@ int StepResultSet::GetBlob(int columnIndex, std::vector &blob) int StepResultSet::GetString(int columnIndex, std::string &value) { if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); return E_STEP_RESULT_QUERY_NOT_EXECUTED; } int errCode = sqliteStatement->GetColumnString(columnIndex, value); if (errCode != E_OK) { - LOG_ERROR("StepResultSet::GetString is err=%{public}d", errCode); + LOG_ERROR("ret is %{public}d", errCode); return errCode; } return E_OK; @@ -347,12 +360,14 @@ int StepResultSet::GetString(int columnIndex, std::string &value) int StepResultSet::GetInt(int columnIndex, int &value) { if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); return E_STEP_RESULT_QUERY_NOT_EXECUTED; } int64_t columnValue; int errCode = sqliteStatement->GetColumnLong(columnIndex, columnValue); if (errCode != E_OK) { + LOG_ERROR("ret is %{public}d", errCode); return errCode; } value = static_cast(columnValue); @@ -362,10 +377,12 @@ int StepResultSet::GetInt(int columnIndex, int &value) int StepResultSet::GetLong(int columnIndex, int64_t &value) { if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); return E_STEP_RESULT_QUERY_NOT_EXECUTED; } int errCode = sqliteStatement->GetColumnLong(columnIndex, value); if (errCode != E_OK) { + LOG_ERROR("ret is %{public}d", errCode); return errCode; } return E_OK; @@ -374,10 +391,37 @@ int StepResultSet::GetLong(int columnIndex, int64_t &value) int StepResultSet::GetDouble(int columnIndex, double &value) { if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); return E_STEP_RESULT_QUERY_NOT_EXECUTED; } int errCode = sqliteStatement->GetColumnDouble(columnIndex, value); if (errCode != E_OK) { + LOG_ERROR("ret is %{public}d", errCode); + return errCode; + } + return E_OK; +} + +int StepResultSet::GetAsset(int32_t col, ValueObject::Asset &value) +{ + return GetValue(col, value); +} + +int StepResultSet::GetAssets(int32_t col, ValueObject::Assets &value) +{ + return GetValue(col, value); +} + +int StepResultSet::GetModifyTime(std::string &modifyTime) +{ + if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); + return E_STEP_RESULT_QUERY_NOT_EXECUTED; + } + auto index = std::find(columnNames_.begin(), columnNames_.end(), "modifyTime"); + int errCode = sqliteStatement->GetColumnString(index - columnNames_.begin(), modifyTime); + if (errCode != E_OK) { + LOG_ERROR("ret is %{public}d", errCode); return errCode; } return E_OK; @@ -388,6 +432,7 @@ int StepResultSet::IsColumnNull(int columnIndex, bool &isNull) ColumnType columnType; int errCode = GetColumnType(columnIndex, columnType); if (errCode != E_OK) { + LOG_ERROR("ret is %{public}d", errCode); return errCode; } isNull = (columnType == ColumnType::TYPE_NULL); @@ -401,5 +446,25 @@ bool StepResultSet::IsClosed() const { return isClosed; } + +template +int StepResultSet::GetValue(int32_t col, T &value) +{ + if (rowPos_ == INIT_POS) { + LOG_ERROR("query not executed."); + return E_STEP_RESULT_QUERY_NOT_EXECUTED; + } + ValueObject object; + int errCode = sqliteStatement->GetColumn(col, object); + if (errCode != E_OK) { + LOG_ERROR("ret is %{public}d", errCode); + return errCode; + } + if (object.value.index() != ValueObject::TYPE_INDEX) { + return E_INVALID_COLUMN_TYPE; + } + value = object; + return E_OK; +} } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/frameworks/native/rdb/src/value_object.cpp b/relational_store/frameworks/native/rdb/src/value_object.cpp index 5da153205f26bf35ee28e0d457386b4c13c8ceed..ebc505361171ea9563c712ed370880bb4ad6441e 100644 --- a/relational_store/frameworks/native/rdb/src/value_object.cpp +++ b/relational_store/frameworks/native/rdb/src/value_object.cpp @@ -15,6 +15,8 @@ #include "value_object.h" +#include + #include "rdb_errno.h" #include "sqlite_utils.h" @@ -24,24 +26,24 @@ ValueObject::ValueObject() { } -ValueObject::ValueObject(ValueObject::Type valueObject) noexcept : value(std::move(valueObject)) +ValueObject::ValueObject(ValueObject::Type val) noexcept : value(std::move(val)) { } -ValueObject::ValueObject(ValueObject &&valueObject) noexcept +ValueObject::ValueObject(ValueObject &&val) noexcept { - if (this == &valueObject) { + if (this == &val) { return; } - value = std::move(valueObject.value); + value = std::move(val.value); } -ValueObject::ValueObject(const ValueObject &valueObject) +ValueObject::ValueObject(const ValueObject &val) { - if (this == &valueObject) { + if (this == &val) { return; } - value = valueObject.value; + value = val.value; } ValueObject::~ValueObject() @@ -55,39 +57,50 @@ ValueObject::ValueObject(int val) : value(static_cast(val)) ValueObject::ValueObject(int64_t val) : value(val) { } -ValueObject::ValueObject(double val) + +ValueObject::ValueObject(double val) : value(val) +{ +} + +ValueObject::ValueObject(bool val) : value(val) +{ +} + +ValueObject::ValueObject(const std::string &val) : value(val) +{ +} + +ValueObject::ValueObject(const char *val) : ValueObject(std::string(val)) { - value = val; } -ValueObject::ValueObject(bool val) + +ValueObject::ValueObject(const std::vector &val) : value(val) { - value = val; } -ValueObject::ValueObject(const std::string &val) + +ValueObject::ValueObject(ValueObject::Asset val) : value(std::move(val)) { - value = val; } -ValueObject::ValueObject(const std::vector &val) + +ValueObject::ValueObject(ValueObject::Assets val) : value(std::move(val)) { - std::vector blob = val; - value = blob; } -ValueObject &ValueObject::operator=(ValueObject &&valueObject) noexcept +ValueObject &ValueObject::operator=(ValueObject &&val) noexcept { - if (this == &valueObject) { + if (this == &val) { return *this; } - value = std::move(valueObject.value); + value = std::move(val.value); return *this; } -ValueObject &ValueObject::operator=(const ValueObject &valueObject) +ValueObject &ValueObject::operator=(const ValueObject &val) { - if (this == &valueObject) { + if (this == &val) { return *this; } - value = valueObject.value; + value = val.value; return *this; } @@ -129,7 +142,18 @@ int ValueObject::GetBlob(std::vector &val) const return Get(val); } -template int ValueObject::Get(T &output) const +int ValueObject::GetAsset(Asset &val) const +{ + return Get(val); +} + +int ValueObject::GetAssets(Assets &val) const +{ + return Get(val); +} + +template +int ValueObject::Get(T &output) const { const T *v = std::get_if(&value); if (v == nullptr) { diff --git a/relational_store/frameworks/native/rdb/src/values_bucket.cpp b/relational_store/frameworks/native/rdb/src/values_bucket.cpp index e3f589ff62570b934b9ff814c2fe166027e7cf33..488647615c3978b7c5eb442c445ed39231f761b1 100644 --- a/relational_store/frameworks/native/rdb/src/values_bucket.cpp +++ b/relational_store/frameworks/native/rdb/src/values_bucket.cpp @@ -21,7 +21,7 @@ ValuesBucket::ValuesBucket() { } -ValuesBucket::ValuesBucket(std::map &valuesMap) : valuesMap(valuesMap) +ValuesBucket::ValuesBucket(std::map values) : values_(std::move(values)) { } @@ -31,63 +31,68 @@ ValuesBucket::~ValuesBucket() void ValuesBucket::PutString(const std::string &columnName, const std::string &value) { - valuesMap.insert(std::make_pair(columnName, ValueObject(value))); + values_.insert(std::make_pair(columnName, ValueObject(value))); } void ValuesBucket::PutInt(const std::string &columnName, int value) { - valuesMap.insert(std::make_pair(columnName, ValueObject(value))); + values_.insert(std::make_pair(columnName, ValueObject(value))); } void ValuesBucket::PutLong(const std::string &columnName, int64_t value) { - valuesMap.insert(std::make_pair(columnName, ValueObject(value))); + values_.insert(std::make_pair(columnName, ValueObject(value))); } void ValuesBucket::PutDouble(const std::string &columnName, double value) { - valuesMap.insert(std::make_pair(columnName, ValueObject(value))); + values_.insert(std::make_pair(columnName, ValueObject(value))); } void ValuesBucket::PutBool(const std::string &columnName, bool value) { - valuesMap.insert(std::make_pair(columnName, ValueObject(value))); + values_.insert(std::make_pair(columnName, ValueObject(value))); } void ValuesBucket::PutBlob(const std::string &columnName, const std::vector &value) { - valuesMap.insert(std::make_pair(columnName, ValueObject(value))); + values_.insert(std::make_pair(columnName, ValueObject(value))); } void ValuesBucket::PutNull(const std::string &columnName) { - valuesMap.insert(std::make_pair(columnName, ValueObject())); + values_.insert(std::make_pair(columnName, ValueObject())); +} + +void ValuesBucket::Put(const std::string &columnName, ValueObject value) +{ + values_.insert_or_assign(columnName, std::move(value)); } void ValuesBucket::Delete(const std::string &columnName) { - valuesMap.erase(columnName); + values_.erase(columnName); } void ValuesBucket::Clear() { - valuesMap.clear(); + values_.clear(); } int ValuesBucket::Size() const { - return valuesMap.size(); + return values_.size(); } bool ValuesBucket::IsEmpty() const { - return valuesMap.empty(); + return values_.empty(); } bool ValuesBucket::HasColumn(const std::string &columnName) const { - auto iter = valuesMap.find(columnName); - if (iter == valuesMap.end()) { + auto iter = values_.find(columnName); + if (iter == values_.end()) { return false; } return true; @@ -95,17 +100,17 @@ bool ValuesBucket::HasColumn(const std::string &columnName) const bool ValuesBucket::GetObject(const std::string &columnName, ValueObject &value) const { - auto iter = valuesMap.find(columnName); - if (iter == valuesMap.end()) { + auto iter = values_.find(columnName); + if (iter == values_.end()) { return false; } value = iter->second; return true; } -void ValuesBucket::GetAll(std::map &outValuesMap) const +std::map ValuesBucket::GetAll() const { - outValuesMap = valuesMap; + return values_; } } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/frameworks/native/rdb_data_ability_adapter/src/rdb_data_ability_utils.cpp b/relational_store/frameworks/native/rdb_data_ability_adapter/src/rdb_data_ability_utils.cpp index e1466be8e7dbd552031563c05249ce5f887f1855..082ebe53a476ebcbdd5b95de101a030ef58b2c21 100644 --- a/relational_store/frameworks/native/rdb_data_ability_adapter/src/rdb_data_ability_utils.cpp +++ b/relational_store/frameworks/native/rdb_data_ability_adapter/src/rdb_data_ability_utils.cpp @@ -14,8 +14,9 @@ */ #include "rdb_data_ability_utils.h" -#include "result_set_utils.h" +#include "parser.h" +#include "result_set_utils.h" using namespace OHOS::RdbDataAbilityAdapter; using namespace OHOS::DataShare; using namespace OHOS::NativeRdb; @@ -28,13 +29,13 @@ RdbDataAbilityUtils::~RdbDataAbilityUtils() { } -DataShareValuesBucket RdbDataAbilityUtils::ToDataShareValuesBucket(const ValuesBucket &valuesBucket) +DataShareValuesBucket RdbDataAbilityUtils::ToDataShareValuesBucket(ValuesBucket valuesBucket) { std::map values; - std::map valuesMap; - valuesBucket.GetAll(valuesMap); - for (auto &[key, value] : valuesMap) { - values.insert({key, value}); + for (auto &[key, value] : valuesBucket.values_) { + DataShareValueObject::Type dsValue; + Parser::Convert(std::move(value.value), dsValue); + values.insert(std::make_pair(key, std::move(dsValue))); } return DataShareValuesBucket(std::move(values)); } diff --git a/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp b/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp index c4b3602ff54078ef13974cacce8a9b5328d3bb6d..bac02d0adc1fac30d7021b86dcd132b0684ab732 100644 --- a/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp +++ b/relational_store/frameworks/native/rdb_data_share_adapter/src/rdb_utils.cpp @@ -15,20 +15,21 @@ #include "rdb_utils.h" +#include "parser.h" #include "rdb_logger.h" - using namespace OHOS::RdbDataShareAdapter; using namespace OHOS::DataShare; using namespace OHOS::NativeRdb; constexpr RdbUtils::OperateHandler RdbUtils::HANDLERS[LAST_TYPE]; -ValuesBucket RdbUtils::ToValuesBucket(const DataShareValuesBucket &valuesBucket) +ValuesBucket RdbUtils::ToValuesBucket(DataShareValuesBucket valuesBucket) { std::map valuesMap; - auto values = valuesBucket.valuesMap; - for (auto &[key, value] : values) { - valuesMap.insert(std::pair(key, ValueObject(value))); + for (auto &[key, dsValue] : valuesBucket.valuesMap) { + ValueObject::Type value; + Parser::Convert(std::move(dsValue), value); + valuesMap.insert(std::pair(key, std::move(value))); } return ValuesBucket(valuesMap); } diff --git a/relational_store/frameworks/native/rdb_device_manager_adapter/include/rdb_device_manager_adapter.h b/relational_store/frameworks/native/rdb_device_manager_adapter/include/rdb_device_manager_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..984d1193c4221fc7f630bda726d6e6db7ea9b0fe --- /dev/null +++ b/relational_store/frameworks/native/rdb_device_manager_adapter/include/rdb_device_manager_adapter.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 RDB_DEVICE_MANAGER_ADAPTER_H +#define RDB_DEVICE_MANAGER_ADAPTER_H + +#include "device_manager.h" +#include "device_manager_callback.h" + +namespace OHOS { +namespace DeviceManagerAdaptor { +class RdbDeviceManagerAdaptor { +public: + static RdbDeviceManagerAdaptor &GetInstance(const std::string &packageName); + int GetEncryptedUuidByNetworkId(const std::string &networkId, std::string &uuid); + +private: + RdbDeviceManagerAdaptor(const std::string &packageName); + ~RdbDeviceManagerAdaptor(); + + void Init(); + void UnInit(); + + std::string packageName_; +}; + +class InitDeviceManagerCallback final : public DistributedHardware::DmInitCallback { +public: + InitDeviceManagerCallback() {}; + ~InitDeviceManagerCallback() {}; + void OnRemoteDied() override {}; +}; +} // namespace DeviceManagerAdaptor +} // namespace OHOS +#endif // RDB_DEVICE_MANAGER_ADAPTER_H diff --git a/relational_store/frameworks/native/rdb_device_manager_adapter/src/rdb_device_manager_adapter.cpp b/relational_store/frameworks/native/rdb_device_manager_adapter/src/rdb_device_manager_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ec5f2d964d06a30a78d34546215bda82768162e --- /dev/null +++ b/relational_store/frameworks/native/rdb_device_manager_adapter/src/rdb_device_manager_adapter.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ + +#define LOG_TAG "RdbDeviceManagerAdaptor" + +#include + +#include "rdb_device_manager_adapter.h" + +namespace OHOS { +namespace DeviceManagerAdaptor { +using namespace OHOS::DistributedHardware; +constexpr int32_t DM_OK = 0; +constexpr int32_t DM_ERROR = -1; +RdbDeviceManagerAdaptor::RdbDeviceManagerAdaptor(const std::string &packageName) + :packageName_(packageName) +{ + Init(); +} + +RdbDeviceManagerAdaptor::~RdbDeviceManagerAdaptor() +{ + UnInit(); +} + +RdbDeviceManagerAdaptor& RdbDeviceManagerAdaptor::GetInstance(const std::string &packageName) +{ + static RdbDeviceManagerAdaptor instance(packageName); + return instance; +} + +void RdbDeviceManagerAdaptor::Init() +{ + auto callback = std::make_shared(); + DeviceManager::GetInstance().InitDeviceManager(packageName_, callback); +} + +void RdbDeviceManagerAdaptor::UnInit() +{ + DeviceManager::GetInstance().UnInitDeviceManager(packageName_); +} + +int RdbDeviceManagerAdaptor::GetEncryptedUuidByNetworkId(const std::string &networkId, std::string &uuid) +{ + int ret = DeviceManager::GetInstance().GetEncryptedUuidByNetworkId(packageName_, networkId, uuid); + if (ret != DM_OK) { + return DM_ERROR; + } + return DM_OK; +} +} // namespace DeviceManagerAdaptor +} // namespace OHOS \ No newline at end of file diff --git a/relational_store/interfaces/inner_api/appdatafwk/include/shared_block.h b/relational_store/interfaces/inner_api/appdatafwk/include/shared_block.h index 46729315920e5ed1725ebf4f407194cf76e65902..766550ebaf61b95327b9ad48ee1b69c680366a6c 100644 --- a/relational_store/interfaces/inner_api/appdatafwk/include/shared_block.h +++ b/relational_store/interfaces/inner_api/appdatafwk/include/shared_block.h @@ -51,6 +51,10 @@ public: CELL_UNIT_TYPE_STRING = 3, /** Indicates the current Cell Unit data type is BLOB at the specified row and column.*/ CELL_UNIT_TYPE_BLOB = 4, + /** Indicates the current Cell Unit data type is Asset at the specified row and column.*/ + CELL_UNIT_TYPE_ASSET = 5, + /** Indicates the current Cell Unit data type is Assets at the specified row and column.*/ + CELL_UNIT_TYPE_ASSETS = 6, }; /** @@ -146,6 +150,16 @@ public: */ RDB_API_EXPORT int PutDouble(uint32_t row, uint32_t column, double value); + /** + * @brief Put Asset data to the shared block. + */ + RDB_API_EXPORT int PutAsset(uint32_t row, uint32_t column, const void *value, size_t size); + + /** + * @brief Put Assets data to the shared block. + */ + RDB_API_EXPORT int PutAssets(uint32_t row, uint32_t column, const void *value, size_t size); + /** * @brief Put Null data to the shared block. */ diff --git a/relational_store/interfaces/inner_api/cloud_data/BUILD.gn b/relational_store/interfaces/inner_api/cloud_data/BUILD.gn index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..248fab0db4efc61b3b04683b7c8ae16859cfb0e8 100644 --- a/relational_store/interfaces/inner_api/cloud_data/BUILD.gn +++ b/relational_store/interfaces/inner_api/cloud_data/BUILD.gn @@ -0,0 +1,67 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# 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. +import("//build/ohos.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +config("cloud_data_config") { + visibility = [ ":*" ] + + include_dirs = [ + "include", + "${cloud_data_native_path}/include", + "${relational_store_innerapi_path}/rdb/include", + "//utils/system/safwk/native/include", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + "//foundation/distributeddatamgr/kv_store/frameworks/common", + ] + + defines = [ + "RELATIONAL_STORE", + "SQLITE_HAS_CODEC", + ] +} + +base_sources = [ + "${cloud_data_native_path}/src/cloud_manager.cpp", + "${cloud_data_native_path}/src/cloud_service_proxy.cpp", + "${cloud_data_native_path}/src/cloud_types_util.cpp", +] + +ohos_shared_library("cloud_data") { + part_name = "relational_store" + sources = base_sources + + configs = [ ":cloud_data_config" ] + + deps = [ + "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb:distributeddb", + "//third_party/sqlite:sqlite", + ] + ldflags = [ "-Wl,--exclude-libs,ALL" ] + cflags_cc = [ "-fvisibility=hidden" ] + + sources += [] + + public_deps = [ "${relational_store_innerapi_path}/appdatafwk:native_appdatafwk" ] + + external_deps = [ + "c_utils:utils", + "hilog_native:libhilog", + "hitrace_native:hitrace_meter", + "ipc:ipc_core", + "samgr:samgr_proxy", + ] + + innerapi_tags = [ "platformsdk" ] + subsystem_name = "distributeddatamgr" +} diff --git a/relational_store/interfaces/inner_api/cloud_data/include/cloud_manager.h b/relational_store/interfaces/inner_api/cloud_data/include/cloud_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..132016bfdc33a560c90f0b9a97ba772c9b841a29 --- /dev/null +++ b/relational_store/interfaces/inner_api/cloud_data/include/cloud_manager.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_MANAGER_IMPL_H +#define OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_MANAGER_IMPL_H +#include +#include + +#include "cloud_service.h" +#include "rdb_visibility.h" +namespace OHOS::CloudData { +class RDB_API_EXPORT CloudManager { +public: + static CloudManager &GetInstance(); + std::shared_ptr GetCloudService(); + +private: + CloudManager() = default; + ~CloudManager() = default; + std::mutex mutex_; + std::shared_ptr cloudService_; +}; +} // namespace OHOS::CloudData +#endif // OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_MANAGER_IMPL_H diff --git a/relational_store/interfaces/inner_api/cloud_data/include/cloud_service.h b/relational_store/interfaces/inner_api/cloud_data/include/cloud_service.h new file mode 100644 index 0000000000000000000000000000000000000000..c180cf9938650fa70a3469bdde5625aa6f679a30 --- /dev/null +++ b/relational_store/interfaces/inner_api/cloud_data/include/cloud_service.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_SERVICE_H +#define OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_SERVICE_H +#include +#include +#include +#include "rdb_visibility.h" +namespace OHOS::CloudData { +class RDB_API_EXPORT CloudService { +public: + enum TransId : int32_t + { + TRANS_HEAD, + TRANS_ENABLE_CLOUD = TRANS_HEAD, + TRANS_DISABLE_CLOUD, + TRANS_CHANGE_APP_SWITCH, + TRANS_CLEAN, + TRANS_NOTIFY_DATA_CHANGE, + TRANS_BUTT, + }; + enum Action : int32_t + { + CLEAR_CLOUD_INFO, + CLEAR_CLOUD_DATA_AND_INFO, + CLEAR_CLOUD_BUTT + }; + + enum Switch : int32_t + { + SWITCH_ON, + SWITCH_OFF + }; + + enum Status : int32_t + { + SUCCESS = 0, + ERROR, + INVALID_ARGUMENT, + SERVER_UNAVAILABLE, + IPC_ERROR, + IPC_PARCEL_ERROR + }; + + virtual ~CloudService() = default; + virtual int32_t EnableCloud(const std::string &id, const std::map &switches) = 0; + virtual int32_t DisableCloud(const std::string &id) = 0; + virtual int32_t ChangeAppSwitch(const std::string &id, const std::string &bundleName, int32_t appSwitch) = 0; + virtual int32_t Clean(const std::string &id, const std::map &actions) = 0; + virtual int32_t NotifyDataChange(const std::string &id, const std::string &bundleName) = 0; + + static constexpr const char *SERVICE_NAME = "cloud"; +}; +} // namespace OHOS::CloudData +#endif // OHOS_DISTRIBUTED_DATA_CLOUD_CLOUD_SERVICE_H diff --git a/relational_store/interfaces/inner_api/js/@ohos.base.d.ts b/relational_store/interfaces/inner_api/js/@ohos.base.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbcb9af2825ad61d1573126aa95a8399f71aaed4 --- /dev/null +++ b/relational_store/interfaces/inner_api/js/@ohos.base.d.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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. + */ + +/** + * Defines the basic callback. + * @syscap SystemCapability.Base + * @typedef Callback + * @since 6 + */ +export interface Callback { + /** + * Defines the callback info. + * @param { T } data + * @since 6 + */ + (data: T): void; +} + +/** + * Defines the basic error callback. + * @syscap SystemCapability.Base + * @typedef ErrorCallback + * @since 6 + */ +export interface ErrorCallback { + /** + * Defines the basic error callback. + * @param { T } err + * @since 6 + */ + (err: T): void; +} + +/** + * Defines the basic async callback. + * @syscap SystemCapability.Base + * @typedef AsyncCallback + * @since 6 + */ +export interface AsyncCallback { + /** + * Defines the callback data. + * @param { BusinessError } err + * @param { T } data + * @since 6 + */ + (err: BusinessError, data: T): void; +} + +/** + * Defines the error interface. + * @syscap SystemCapability.Base + * @typedef BusinessError + * @since 6 + */ +export interface BusinessError extends Error { + /** + * Defines the basic error code. + * @type { number } code + * @since 6 + */ + code: number; + /** + * Defines the additional information for business + * @type { ?T } data + * @since 9 + */ + data?: T; +} diff --git a/relational_store/interfaces/inner_api/js/@ohos.data.ValuesBucket.d.ts b/relational_store/interfaces/inner_api/js/@ohos.data.ValuesBucket.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..47ea98195c5bd06c2a34367bb8bf37ad4a87b1f3 --- /dev/null +++ b/relational_store/interfaces/inner_api/js/@ohos.data.ValuesBucket.d.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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. + */ + +/** + * Indicates possible value types + * + * @syscap SystemCapability.DistributedDataManager.DataShare.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ +export class Asset { + name: string; + uri: string; + createTime: string; + modifyTime: string; + size: string; +} + +/** + * Indicates possible value types + * + * @syscap SystemCapability.DistributedDataManager.DataShare.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ +export type ValueType = number | string | boolean; + +/** + * Values in buckets are stored in key-value pairs + * + * @syscap SystemCapability.DistributedDataManager.DataShare.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ +export type ValuesBucket = { + [key: string]: ValueType | Uint8Array | Asset | Asset null; +}; diff --git a/relational_store/interfaces/inner_api/js/@ohos.data.rdb.d.ts b/relational_store/interfaces/inner_api/js/@ohos.data.rdb.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0aaf667808897ae6be84d412cfeee595898e4aee --- /dev/null +++ b/relational_store/interfaces/inner_api/js/@ohos.data.rdb.d.ts @@ -0,0 +1,934 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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. + */ + +import { AsyncCallback, Callback } from './@ohos.base'; +import { ResultSet as _ResultSet } from './data/rdb/resultSet'; +import Context from './application/BaseContext'; + +/** + * Provides methods for rdbStore create and delete. + * + * @namespace rdb + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore + */ +declare namespace rdb { + /** + * Obtains an RDB store. + * You can set parameters of the RDB store as required. In general, this method is recommended + * to obtain a rdb store. + * + * @param { Context } context - Indicates the context of application or capability. + * @param { StoreConfig } config - Indicates the {@link StoreConfig} configuration of the database related to this RDB store. + * @param { number } version - Indicates the database version for upgrade or downgrade. + * @param { AsyncCallback } callback - the RDB store {@link RdbStore}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.getRdbStore + */ + function getRdbStore(context: Context, config: StoreConfig, version: number, callback: AsyncCallback): void; + + /** + * Obtains an RDB store. + * You can set parameters of the RDB store as required. In general, this method is recommended + * to obtain a rdb store. + * + * @param { Context } context - Indicates the context of application or capability. + * @param { StoreConfig } config - Indicates the {@link StoreConfig} configuration of the database related to this RDB store. + * @param { number } version - Indicates the database version for upgrade or downgrade. + * @returns { Promise } the RDB store {@link RdbStore}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.getRdbStore + */ + function getRdbStore(context: Context, config: StoreConfig, version: number): Promise; + + /** + * Deletes the database with a specified name. + * + * @param { Context } context - Indicates the context of application or capability. + * @param { string } name - Indicates the database name. + * @param { AsyncCallback } callback - the callback of deleteRdbStore. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.deleteRdbStore + */ + function deleteRdbStore(context: Context, name: string, callback: AsyncCallback): void; + /** + * Deletes the database with a specified name. + * + * @param { Context } context - Indicates the context of application or capability. + * @param { string } name - Indicates the database name. + * @returns { Promise } the promise returned by the function. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.deleteRdbStore + */ + function deleteRdbStore(context: Context, name: string): Promise; + + /** + * Indicates the database synchronization mode. + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.SyncMode + */ + enum SyncMode { + /** + * Indicates the data is pushed to remote device from local device. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.SyncMode.SYNC_MODE_PUSH + */ + SYNC_MODE_PUSH = 0, + + /** + * Indicates the data is pulled from remote device to local device. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.SyncMode.SYNC_MODE_PULL + */ + SYNC_MODE_PULL = 1 + } + + /** + * Describes the subscription type. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.SubscribeType + */ + enum SubscribeType { + /** + * Subscription to remote data changes + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.SubscribeType.SUBSCRIBE_TYPE_REMOTE + */ + SUBSCRIBE_TYPE_REMOTE = 0 + } + + /** + * Provides methods for managing the relational database (RDB). + * This class provides methods for creating, querying, updating, and deleting RDBs. + * + * @interface RdbStore + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore + */ + interface RdbStore { + /** + * Inserts a row of data into the target table. + * + * @param { string } table - Indicates the row of data to be inserted into the table. + * @param { ValuesBucket } values - Indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @param { AsyncCallback } callback - the row ID if the operation is successful. returns -1 otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.insert + */ + insert(table: string, values: ValuesBucket, callback: AsyncCallback): void; + + /** + * Inserts a row of data into the target table. + * + * @param { string } table - Indicates the row of data to be inserted into the table. + * @param { ValuesBucket } values - Indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @returns { Promise } return the row ID if the operation is successful. return -1 otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.insert + */ + insert(table: string, values: ValuesBucket): Promise; + + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - Indicates the target table. + * @param { Array } values - Indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @param { AsyncCallback } callback - the number of values that were inserted if the operation is successful. returns -1 otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.batchInsert + */ + batchInsert(table: string, values: Array, callback: AsyncCallback): void; + + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - Indicates the target table. + * @param { Array } values - Indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @returns { Promise } return the number of values that were inserted if the operation is successful. returns -1 otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.batchInsert + */ + batchInsert(table: string, values: Array): Promise; + + /** + * Updates data in the database based on a a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - Indicates Indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - Indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.update + */ + update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback): void; + + /** + * Updates data in the database based on a a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - Indicates Indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - Indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @returns { Promise } return the number of affected rows. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.update + */ + update(values: ValuesBucket, predicates: RdbPredicates): Promise; + + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { RdbPredicates } predicates - the specified delete condition by the instance object of {@link RdbPredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.delete + */ + delete(predicates: RdbPredicates, callback: AsyncCallback): void; + + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { RdbPredicates } predicates - the specified delete condition by the instance object of {@link RdbPredicates}. + * @returns { Promise } return the number of affected rows. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.delete + */ + delete(predicates: RdbPredicates): Promise; + + /** + * Queries data in the database based on specified conditions. + * + * @param { RdbPredicates } predicates - the specified query condition by the instance object of {@link RdbPredicates}. + * @param { Array } columns - the columns to query. If the value is empty array, the query applies to all columns. + * @param { AsyncCallback } callback - the {@link ResultSet} object if the operation is successful. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.query + */ + query(predicates: RdbPredicates, columns: Array, callback: AsyncCallback): void; + + /** + * Queries data in the database based on specified conditions. + * + * @param { RdbPredicates } predicates - the specified query condition by the instance object of {@link RdbPredicates}. + * @param { Array } columns - the columns to query. If the value is null, the query applies to all columns. + * @returns { Promise } return the {@link ResultSet} object if the operation is successful. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.query + */ + query(predicates: RdbPredicates, columns?: Array): Promise; + + /** + * Queries data in the database based on SQL statement. + * + * @param { string } sql - Indicates the SQL statement to execute. + * @param { Array } bindArgs - Indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @param { AsyncCallback } callback + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.querySql + */ + querySql(sql: string, bindArgs: Array, callback: AsyncCallback): void; + + /** + * Queries data in the database based on SQL statement. + * + * @param { string } sql - Indicates the SQL statement to execute. + * @param { Array } bindArgs - Indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @returns { Promise } return the {@link ResultSet} object if the operation is successful. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.querySql + */ + querySql(sql: string, bindArgs?: Array): Promise; + + /** + * Executes an SQL statement that contains specified parameters but returns no value. + * + * @param { string } sql - Indicates the SQL statement to execute. + * @param { Array } bindArgs - Indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @param { AsyncCallback } callback - the callback of executeSql. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.executeSql + */ + executeSql(sql: string, bindArgs: Array, callback: AsyncCallback): void; + + /** + * Executes an SQL statement that contains specified parameters but returns no value. + * + * @param { string } sql - Indicates the SQL statement to execute. + * @param { Array } bindArgs - Indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @returns { Promise } the promise returned by the function. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.executeSql + */ + executeSql(sql: string, bindArgs?: Array): Promise; + + /** + * Begin Transaction before execute your sql. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.beginTransaction + */ + beginTransaction(): void; + + /** + * Commit the the sql you have executed. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.commit + */ + commit(): void; + + /** + * Roll back the sql you have already executed. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.rollBack + */ + rollBack(): void; + + /** + * Set table to be distributed table. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { Array } tables - Indicates the tables name you want to set. + * @param { AsyncCallback } callback - the callback of setDistributedTables. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.setDistributedTables + */ + setDistributedTables(tables: Array, callback: AsyncCallback): void; + + /** + * Set table to be distributed table. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { Array } tables - Indicates the tables name you want to set. + * @returns { Promise } the promise returned by the function. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.setDistributedTables + */ + setDistributedTables(tables: Array): Promise; + + /** + * Obtain distributed table name of specified remote device according to local table name. + * When query remote device database, distributed table name is needed. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { string } device - Indicates the remote device. + * @param { string } table - {string}: the distributed table name. + * @param { AsyncCallback } callback + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.obtainDistributedTableName + */ + obtainDistributedTableName(device: string, table: string, callback: AsyncCallback): void; + + /** + * Obtain distributed table name of specified remote device according to local table name. + * When query remote device database, distributed table name is needed. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { string } device - Indicates the remote device. + * @param { string } table + * @returns { Promise } {string}: the distributed table name. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.obtainDistributedTableName + */ + obtainDistributedTableName(device: string, table: string): Promise; + + /** + * Sync data between devices. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { SyncMode } mode - Indicates the remote device. + * @param { RdbPredicates } predicates - {Array<[string, number]>}: devices sync status array, {string}: device id, {number}: device sync status. + * @param { AsyncCallback> } callback + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.sync + */ + sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback>): void; + + /** + * Sync data between devices. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { SyncMode } mode - Indicates the remote device. + * @param { RdbPredicates } predicates + * @returns { Promise> } {Array<[string, number]>}: devices sync status array, {string}: device id, {number}: device sync status. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.sync + */ + sync(mode: SyncMode, predicates: RdbPredicates): Promise>; + + /** + * Registers an observer for the database. When data in the distributed database changes, + * the callback will be invoked. + * + * @param { 'dataChange' } event - Indicates the event must be string 'dataChange'. + * @param { SubscribeType } type - Indicates the subscription type, which is defined in {@link SubscribeType}.If its value is SUBSCRIBE_TYPE_REMOTE, ohos.permission.DISTRIBUTED_DATASYNC is required. + * @param { Callback> } observer - {Array}: the observer of data change events in the distributed database. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.on + */ + on(event: 'dataChange', type: SubscribeType, observer: Callback>): void; + + /** + * Remove specified observer of specified type from the database. + * + * @param { 'dataChange' } event - Indicates the event must be string 'dataChange'. + * @param { SubscribeType } type - Indicates the subscription type, which is defined in {@link SubscribeType}.If its value is SUBSCRIBE_TYPE_REMOTE, ohos.permission.DISTRIBUTED_DATASYNC is required. + * @param { Callback> } observer - {Array}: the data change observer already registered. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbStore.off + */ + off(event: 'dataChange', type: SubscribeType, observer: Callback>): void; + } + + /** + * Indicates possible value types + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ValueType + */ + type ValueType = number | string | boolean; + + /** + * Values in buckets are stored in key-value pairs + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ValuesBucket + */ + type ValuesBucket = { [key: string]: ValueType | Uint8Array | null }; + + /** + * Manages relational database configurations. + * + * @interface StoreConfig + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.StoreConfig + */ + interface StoreConfig { + name: string; + } + + /** + * Manages relational database configurations. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates + */ + class RdbPredicates { + /** + * A parameterized constructor used to create an RdbPredicates instance. + * + * @param { string } name - Indicates the table name of the database. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.constructor + */ + constructor(name: string); + + /** + * Sync data between devices. + * When query database, this function should not be called. + * + * @param { Array } devices - Indicates specified remote devices. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.inDevices + */ + inDevices(devices: Array): RdbPredicates; + + /** + * Specify all remote devices which connect to local device when syncing distributed database. + * When query database, this function should not be called. + * + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 8 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.inAllDevices + */ + inAllDevices(): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is ValueType and value is equal + * to a specified value. + * This method is similar to = of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @param { ValueType } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.equalTo + */ + equalTo(field: string, value: ValueType): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is ValueType and value is not equal to + * a specified value. + * This method is similar to != of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @param { ValueType } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.notEqualTo + */ + notEqualTo(field: string, value: ValueType): RdbPredicates; + + /** + * Adds a left parenthesis to the RdbPredicates. + * This method is similar to ( of the SQL statement and needs to be used together with endWrap(). + * + * @returns { RdbPredicates } - the {@link RdbPredicates} with the left parenthesis. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.beginWrap + */ + beginWrap(): RdbPredicates; + + /** + * Adds a right parenthesis to the RdbPredicates. + * This method is similar to ) of the SQL statement and needs to be used together + * with beginWrap(). + * + * @returns { RdbPredicates } - the {@link RdbPredicates} with the right parenthesis. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.endWrap + */ + endWrap(): RdbPredicates; + + /** + * Adds an or condition to the RdbPredicates. + * This method is similar to or of the SQL statement. + * + * @returns { RdbPredicates } Returns the {@link RdbPredicates} with the or condition. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.or + */ + or(): RdbPredicates; + + /** + * Adds an and condition to the RdbPredicates. + * This method is similar to or of the SQL statement. + * + * @returns { RdbPredicates } Returns the {@link RdbPredicates} with the or condition. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.and + */ + and(): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is string and value + * contains a specified value. + * This method is similar to contains of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @param { string } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.contains + */ + contains(field: string, value: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is string and value starts + * with a specified string. + * This method is similar to value% of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @param { string } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.beginsWith + */ + beginsWith(field: string, value: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is string and value + * ends with a specified string. + * This method is similar to %value of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @param { string } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.endsWith + */ + endsWith(field: string, value: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the fields whose value is null. + * This method is similar to is null of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.isNull + */ + isNull(field: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the specified fields whose value is not null. + * This method is similar to is not null of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.isNotNull + */ + isNotNull(field: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the fields whose data type is string and value is + * similar to a specified string. + * This method is similar to like of the SQL statement. + * + * @param { string } field - Indicates the column name in the database table. + * @param { string } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} that match the specified field. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.like + */ + like(field: string, value: string): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is string and the value contains + * a wildcard. + * Different from like, the input parameters of this method are case-sensitive. + * + * @param { string } field - Indicates the column name in the database table. + * @param { string } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.glob + */ + glob(field: string, value: string): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is string and the value contains + * a wildcard. + * + * @param { string } field - Indicates the column name. + * @param { ValueType } low - Indicates the minimum value. + * @param { ValueType } high - Indicates the maximum value. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.between + */ + between(field: string, low: ValueType, high: ValueType): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is int and value is + * out of a given range. + * + * @param { string } field - Indicates the column name in the database table. + * @param { ValueType } low - Indicates the minimum value. + * @param { ValueType } high - Indicates the maximum value to. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.notBetween + */ + notBetween(field: string, low: ValueType, high: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be greater than the specified value. + * + * @param { string } field - Indicates the column name in the database table. + * @param { ValueType } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.greaterThan + */ + greaterThan(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be smaller than the specified value. + * + * @param { string } field - Indicates the column name in the database table. + * @param { ValueType } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.lessThan + */ + lessThan(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be greater than or equal to the specified value. + * + * @param { string } field - Indicates the column name in the database table. + * @param { ValueType } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.greaterThanOrEqualTo + */ + greaterThanOrEqualTo(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be smaller than or equal to the specified value. + * + * @param { string } field - Indicates the column name in the database table. + * @param { ValueType } value - Indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.lessThanOrEqualTo + */ + lessThanOrEqualTo(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the ascending order of the return list. When there are several orders, + * the one close to the head has the highest priority. + * + * @param { string } field - Indicates the column name for sorting the return list. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.orderByAsc + */ + orderByAsc(field: string): RdbPredicates; + + /** + * Restricts the descending order of the return list. When there are several orders, + * the one close to the head has the highest priority. + * + * @param { string } field - Indicates the column name for sorting the return list. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.orderByDesc + */ + orderByDesc(field: string): RdbPredicates; + + /** + * Restricts each row of the query result to be unique. + * + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.distinct + */ + distinct(): RdbPredicates; + + /** + * Restricts the max number of return records. + * + * @param { number } value - Indicates the max length of the return list. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.limitAs + */ + limitAs(value: number): RdbPredicates; + + /** + * Configure RdbPredicates to specify the start position of the returned result. + * Use this method together with limit(int). + * + * @param { number } rowOffset - Indicates the start position of the returned result. The value is a positive integer. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.offsetAs + */ + offsetAs(rowOffset: number): RdbPredicates; + + /** + * Configure RdbPredicates to group query results by specified columns. + * + * @param { Array } fields - Indicates the specified columns by which query results are grouped. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.groupBy + */ + groupBy(fields: Array): RdbPredicates; + + /** + * Configure RdbPredicates to specify the index column. + * Before using this method, you need to create an index column. + * + * @param { string } field - Indicates the name of the index column. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.indexedBy + */ + indexedBy(field: string): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is ValueType array and values + * are within a given range. + * + * @param { string } field - Indicates the column name in the database table. + * @param { Array } value - Indicates the values to match with {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.in + */ + in(field: string, value: Array): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is ValueType array and values + * are out of a given range. + * + * @param { string } field - Indicates the column name in the database table. + * @param { Array } value - Indicates the values to match with {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.RdbPredicates.notIn + */ + notIn(field: string, value: Array): RdbPredicates; + } + + export type ResultSet = _ResultSet; +} + +export default rdb; diff --git a/relational_store/interfaces/inner_api/js/@ohos.data.relationalStore.d.ts b/relational_store/interfaces/inner_api/js/@ohos.data.relationalStore.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..67d3017fde535eb971b60687e5243e8f9cc4f203 --- /dev/null +++ b/relational_store/interfaces/inner_api/js/@ohos.data.relationalStore.d.ts @@ -0,0 +1,1868 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import { AsyncCallback, Callback } from './@ohos.base'; +import Context from './application/BaseContext'; +import dataSharePredicates from './@ohos.data.dataSharePredicates'; + +/** + * Provides methods for rdbStore create and delete. + * + * @namespace relationalStore + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ +declare namespace relationalStore { + /** + * Obtains a RDB store. + * You can set parameters of the RDB store as required. In general, this method is recommended + * to obtain a rdb store. + * + * @param { Context } context - indicates the context of application or capability. + * @param { StoreConfig } config - indicates the {@link StoreConfig} configuration of the database related to this RDB store. + * @param { AsyncCallback } callback - the RDB store {@link RdbStore}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 14800010 - if failed open database by invalid database name. + * @throws { BusinessError } 14800011 - if failed open database by database corrupted. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + function getRdbStore(context: Context, config: StoreConfig, callback: AsyncCallback): void; + + /** + * Obtains a RDB store. + * You can set parameters of the RDB store as required. In general, this method is recommended + * to obtain a rdb store. + * + * @param { Context } context - indicates the context of application or capability. + * @param { StoreConfig } config - indicates the {@link StoreConfig} configuration of the database related to this RDB store. + * @returns { Promise } the RDB store {@link RdbStore}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 14800010 - if failed open database by invalid database name. + * @throws { BusinessError } 14800011 - if failed open database by database corrupted. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + function getRdbStore(context: Context, config: StoreConfig): Promise; + + /** + * Deletes the database with a specified name. + * + * @param { Context } context - indicates the context of application or capability. + * @param { string } name - indicates the database name. + * @param { AsyncCallback } callback - the callback of deleteRdbStore. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 14800010 - if failed delete database by invalid database name. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + function deleteRdbStore(context: Context, name: string, callback: AsyncCallback): void; + + /** + * Deletes the database with a specified name. + * + * @param { Context } context - indicates the context of application or capability. + * @param { string } name - indicates the database name. + * @returns { Promise } the promise returned by the function. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 14800010 - if failed delete database by invalid database name. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + function deleteRdbStore(context: Context, name: string): Promise; + + /** + * Manages relational database configurations. + * + * @interface StoreConfig + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + interface StoreConfig { + /** + * The database name. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + name: string; + + /** + * Specifies the security level of the database. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + securityLevel: SecurityLevel; + + /** + * Specifies whether the database is encrypted. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + encrypt?: boolean; + } + /** + * the cloud sync progress + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + enum Progress { + SYNC_BEGIN, + SYNC_IN_PROGRESS, + SYNC_FINISH, + } + + /** + * Describes the {@code RdbStore} type. + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + interface Statistic { + total: number; + success: number; + failed: number; + untreated: number; + } + /** + * Describes the {@code RdbStore} type. + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + interface ProgressDetail { + schedule : Progress; + code: number; + upload: Statistic; + download: Statistic; + } + + /** + * Describes the {@code RdbStore} type. + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + enum SecurityLevel { + /** + * S1: means the db is low level security + * There are some low impact, when the data is leaked. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + S1 = 1, + + /** + * S2: means the db is middle level security + * There are some major impact, when the data is leaked. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + S2 = 2, + + /** + * S3: means the db is high level security + * There are some severity impact, when the data is leaked. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + S3 = 3, + + /** + * S4: means the db is critical level security + * There are some critical impact, when the data is leaked. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + S4 = 4 + } + + /** + * Indicates possible value types + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + interface Asset { + name: string; + uri: string; + createTime: string; + modifyTime: string; + size: string; + } + + /** + * Indicates possible value types + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + type ValueType = number | string | boolean | Uint8Array | Asset | Asset[]; + + /** + * Values in buckets are stored in key-value pairs + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + type ValuesBucket = { [key:string]: ValueType | null; } + + /** + * Indicates the database synchronization mode. + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + enum SyncMode { + /** + * Indicates the data is pushed to remote device from local device. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + SYNC_MODE_PUSH = 0, + + /** + * Indicates the data is pulled from remote device to local device. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + SYNC_MODE_PULL = 1, + + /** + * Indicates the data is pulled from remote device to local device. + * + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + SYNC_MODE_TIME_FIRST, + + /** + * Indicates force push the native data to the cloud. + * + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + SYNC_MODE_NATIVE_FIRST, + + /** + * Indicates the data is pulled from remote device to local device. + * + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + SYNC_MODE_CLOUD_FIRST, + } + + /** + * Describes the subscription type. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + enum SubscribeType { + /** + * Subscription to remote data changes + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + SUBSCRIBE_TYPE_REMOTE = 0, + /** + * Subscription to cloud data changes + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + SUBSCRIBE_TYPE_CLOUD, + } + + /** + * Describes the distributed type of the tables. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + enum DistributedType { + /** + * distributed a range the devices + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + DISTRIBUTED_DEVICE, + + /** + * distributed by cloud + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + DISTRIBUTED_CLOUD + } + + /** + * Describes the conflict resolutions to insert data into the table. + * + * @enum { number } + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + enum ConflictResolution { + /** + * Implements no action when conflict occurs. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + ON_CONFLICT_NONE = 0, + + /** + * Implements rollback operation when conflict occurs. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + ON_CONFLICT_ROLLBACK = 1, + + /** + * Implements abort operation when conflict occurs. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + ON_CONFLICT_ABORT = 2, + + /** + * Implements fail operation when conflict occurs. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + ON_CONFLICT_FAIL = 3, + + /** + * Implements ignore operation when conflict occurs. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + ON_CONFLICT_IGNORE = 4, + + /** + * Implements replace operation operator when conflict occurs. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + ON_CONFLICT_REPLACE = 5 + } + + /** + * Provides methods for managing the relational database (RDB). + * This class provides methods for creating, querying, updating, and deleting RDBs. + * + * @interface RdbStore + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + interface RdbStore { + /** + * Obtains the RdbStore version. The version number must be an integer greater than 0. + * + * @throws { BusinessError } 401 - parameter error. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + version: number; + + /** + * Inserts a row of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @param { AsyncCallback } callback - the row ID if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Inserts a row of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @param { AsyncCallback } callback - the row ID if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + insert(table: string, values: ValuesBucket, callback: AsyncCallback): void; + + /** + * Inserts a row of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @param { ConflictResolution } conflict - indicates the {@link ConflictResolution} to insert data into the table. + * @param { AsyncCallback } callback - the row ID if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + insert(table: string, values: ValuesBucket, conflict: ConflictResolution, callback: AsyncCallback): void; + + /** + * Inserts a row of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @returns { Promise } the row ID if the operation is successful. return -1 otherwise. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Inserts a row of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @returns { Promise } the row ID if the operation is successful. return -1 otherwise. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + insert(table: string, values: ValuesBucket): Promise; + + /** + * Inserts a row of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data {@link ValuesBucket} to be inserted into the table. + * @param { ConflictResolution } conflict - indicates the {@link ConflictResolution} to insert data into the table. + * @returns { Promise } the row ID if the operation is successful. return -1 otherwise. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + insert(table: string, values: ValuesBucket, conflict: ConflictResolution): Promise; + + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { Array } values - indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @param { AsyncCallback } callback - the number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { Array } values - indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @param { AsyncCallback } callback - the number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + batchInsert(table: string, values: Array, callback: AsyncCallback): void; + + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { Array } values - indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @returns { Promise } the number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Inserts a batch of data into the target table. + * + * @param { string } table - indicates the target table. + * @param { Array } values - indicates the rows of data {@link ValuesBucket} to be inserted into the table. + * @returns { Promise } the number of values that were inserted if the operation is successful. returns -1 otherwise. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + batchInsert(table: string, values: Array): Promise; + + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + update(values: ValuesBucket, predicates: RdbPredicates, callback: AsyncCallback): void; + + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @param { ConflictResolution } conflict - indicates the {@link ConflictResolution} to insert data into the table. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + update( + values: ValuesBucket, + predicates: RdbPredicates, + conflict: ConflictResolution, + callback: AsyncCallback + ): void; + + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + update(values: ValuesBucket, predicates: RdbPredicates): Promise; + + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { RdbPredicates } predicates - indicates the specified update condition by the instance object of {@link RdbPredicates}. + * @param { ConflictResolution } conflict - indicates the {@link ConflictResolution} to insert data into the table. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + update(values: ValuesBucket, predicates: RdbPredicates, conflict: ConflictResolution): Promise; + + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { dataSharePredicates.DataSharePredicates } predicates - indicates the specified update condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { dataSharePredicates.DataSharePredicates } predicates - indicates the specified update condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 10 + */ + update( + table: string, + values: ValuesBucket, + predicates: dataSharePredicates.DataSharePredicates, + callback: AsyncCallback + ): void; + + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { dataSharePredicates.DataSharePredicates } predicates - indicates the specified update condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ + /** + * Updates data in the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { ValuesBucket } values - indicates the row of data to be updated in the database.The key-value pairs are associated with column names of the database table. + * @param { dataSharePredicates.DataSharePredicates } predicates - indicates the specified update condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 10 + */ + update(table: string, values: ValuesBucket, predicates: dataSharePredicates.DataSharePredicates): Promise; + + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { RdbPredicates } predicates - the specified delete condition by the instance object of {@link RdbPredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { RdbPredicates } predicates - the specified delete condition by the instance object of {@link RdbPredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + delete(predicates: RdbPredicates, callback: AsyncCallback): void; + + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { RdbPredicates } predicates - the specified delete condition by the instance object of {@link RdbPredicates}. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { RdbPredicates } predicates - the specified delete condition by the instance object of {@link RdbPredicates}. + * @returns { Promise } return the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + delete(predicates: RdbPredicates): Promise; + + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { dataSharePredicates.DataSharePredicates } predicates - the specified delete condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { dataSharePredicates.DataSharePredicates } predicates - the specified delete condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @param { AsyncCallback } callback - the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 10 + */ + delete(table: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback): void; + + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { dataSharePredicates.DataSharePredicates } predicates - the specified delete condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ + /** + * Deletes data from the database based on a specified instance object of RdbPredicates. + * + * @param { string } table - indicates the target table. + * @param { dataSharePredicates.DataSharePredicates } predicates - the specified delete condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @returns { Promise } the number of affected rows. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 10 + */ + delete(table: string, predicates: dataSharePredicates.DataSharePredicates): Promise; + + /** + * Queries data in the database based on specified conditions. + * + * @param { RdbPredicates } predicates - the specified query condition by the instance object of {@link RdbPredicates}. + * @param { Array } columns - the columns to query. If the value is empty array, the query applies to all columns. + * @param { AsyncCallback } callback - the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + query(predicates: RdbPredicates, columns: Array, callback: AsyncCallback): void; + + /** + * Queries data in the database based on specified conditions. + * + * @param { RdbPredicates } predicates - the specified query condition by the instance object of {@link RdbPredicates}. + * @param { Array } columns - the columns to query. If the value is null, the query applies to all columns. + * @returns { Promise } the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + query(predicates: RdbPredicates, columns?: Array): Promise; + + /** + * Queries data in the database based on specified conditions. + * + * @param { string } table - indicates the target table. + * @param { dataSharePredicates.DataSharePredicates } predicates - the specified query condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @param { Array } columns - the columns to query. If the value is empty array, the query applies to all columns. + * @param { AsyncCallback } callback - the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ + query( + table: string, + predicates: dataSharePredicates.DataSharePredicates, + columns: Array, + callback: AsyncCallback + ): void; + + /** + * Queries data in the database based on specified conditions. + * + * @param { string } table - indicates the target table. + * @param { dataSharePredicates.DataSharePredicates } predicates - the specified query condition by the instance object of {@link dataSharePredicates.DataSharePredicates}. + * @param { Array } columns - the columns to query. If the value is null, the query applies to all columns. + * @returns { Promise } the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 202 - if permission verification failed, application which is not a system application uses system API. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @systemapi + * @StageModelOnly + * @since 9 + */ + query( + table: string, + predicates: dataSharePredicates.DataSharePredicates, + columns?: Array + ): Promise; + + /** + * Queries data in the database based on SQL statement. + * + * @param { string } sql - indicates the SQL statement to execute. + * @param { Array } bindArgs - indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @param { AsyncCallback } callback - the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + querySql(sql: string, bindArgs: Array, callback: AsyncCallback): void; + + /** + * Queries data in the database based on SQL statement. + * + * @param { string } sql - indicates the SQL statement to execute. + * @param { Array } bindArgs - indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @returns { Promise } the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + querySql(sql: string, bindArgs?: Array): Promise; + + /** + * Executes a SQL statement that contains specified parameters but returns no value. + * + * @param { string } sql - indicates the SQL statement to execute. + * @param { Array } bindArgs - indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @param { AsyncCallback } callback - the callback of executeSql. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Executes a SQL statement that contains specified parameters but returns no value. + * + * @param { string } sql - indicates the SQL statement to execute. + * @param { Array } bindArgs - indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @param { AsyncCallback } callback - the callback of executeSql. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + executeSql(sql: string, bindArgs: Array, callback: AsyncCallback): void; + + /** + * Executes a SQL statement that contains specified parameters but returns no value. + * + * @param { string } sql - indicates the SQL statement to execute. + * @param { Array } bindArgs - indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @returns { Promise } the promise returned by the function. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * Executes a SQL statement that contains specified parameters but returns no value. + * + * @param { string } sql - indicates the SQL statement to execute. + * @param { Array } bindArgs - indicates the {@link ValueType} values of the parameters in the SQL statement. The values are strings. + * @returns { Promise } the promise returned by the function. + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + executeSql(sql: string, bindArgs?: Array): Promise; + + /** + * BeginTransaction before execute your sql. + * + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + /** + * BeginTransaction before execute your sql. + * + * @throws { BusinessError } 14800047 - if the WAL file size exceeds the default limit. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + beginTransaction(): void; + + /** + * Commit the the sql you have executed. + * + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + commit(): void; + + /** + * Roll back the sql you have already executed. + * + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + rollBack(): void; + + /** + * Backs up a database in a specified name. + * + * @param { string } destName - indicates the name that saves the database backup. + * @param { AsyncCallback } callback - the callback of backup. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + backup(destName: string, callback: AsyncCallback): void; + + /** + * Backs up a database in a specified name. + * + * @param { string } destName - indicates the name that saves the database backup. + * @returns { Promise } the promise returned by the function. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + backup(destName: string): Promise; + + /** + * Restores a database from a specified database file. + * + * @param { string } srcName - indicates the name that saves the database file. + * @param { AsyncCallback } callback - the callback of restore. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + restore(srcName: string, callback: AsyncCallback): void; + + /** + * Restores a database from a specified database file. + * + * @param { string } srcName - indicates the name that saves the database file. + * @returns { Promise } the promise returned by the function. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + restore(srcName: string): Promise; + + /** + * Set table to be distributed table. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { Array } tables - indicates the tables name you want to set. + * @param { AsyncCallback } callback - the callback of setDistributedTables. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + setDistributedTables(tables: Array, callback: AsyncCallback): void; + + /** + * Set table to be distributed table. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { Array } tables - indicates the tables name you want to set. + * @param { number } mode - indicates the tables distributed type {@link DistributedType}. + * @param { AsyncCallback } callback - the callback of setDistributedTables. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 10 + */ + setDistributedTables(tables: Array, type: number, callback: AsyncCallback): void; + + /** + * Set table to be distributed table. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { Array } tables - indicates the tables name you want to set. + * @param { number } mode - indicates the tables distributed type {@link DistributedType}. + * @returns { Promise } the promise returned by the function. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + setDistributedTables(tables: Array, type?: number): Promise; + + /** + * Obtain distributed table name of specified remote device according to local table name. + * When query remote device database, distributed table name is needed. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { string } device - indicates the remote device. + * @param { string } table - {string}: the distributed table name. + * @param { AsyncCallback } callback + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + obtainDistributedTableName(device: string, table: string, callback: AsyncCallback): void; + + /** + * Obtain distributed table name of specified remote device according to local table name. + * When query remote device database, distributed table name is needed. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { string } device - indicates the remote device. + * @param { string } table + * @returns { Promise } {string}: the distributed table name. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + obtainDistributedTableName(device: string, table: string): Promise; + + /** + * Sync data between devices. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { SyncMode } mode - indicates the database synchronization mode. + * @param { RdbPredicates } predicates - the specified sync condition by the instance object of {@link RdbPredicates}. + * @param { AsyncCallback> } callback - {Array<[string, number]>}: devices sync status array, {string}: device id, {number}: device sync status. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + sync(mode: SyncMode, predicates: RdbPredicates, callback: AsyncCallback>): void; + + /** + * Sync data between devices. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { SyncMode } mode - indicates the database synchronization mode. + * @param { RdbPredicates } predicates - the specified sync condition by the instance object of {@link RdbPredicates}. + * @returns { Promise> } {Array<[string, number]>}: devices sync status array, {string}: device id, {number}: device sync status. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + sync(mode: SyncMode, predicates: RdbPredicates): Promise>; + + /** + * Sync data to cloud. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { number } mode - indicates the database synchronization mode. + * @param { Callback } progress - the specified sync condition by the instance object of {@link ProgressDetail}. + * @param { AsyncCallback } callback - {Array<[string, number]>}: devices sync status array, {string}: device id, {number}: device sync status. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + cloudSync(mode: SyncMode, progress: Callback, callback: AsyncCallback): void; + + /** + * Sync data to cloud. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { number } mode - indicates the database synchronization mode. + * @param { Callback } progress - the specified sync condition by the instance object of {@link ProgressDetail}. + * @returns { Promise } : devices sync status array, {string}: device id, {number}: device sync status. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + cloudSync(mode: SyncMode, progress: Callback): Promise; + + /** + * Sync data to cloud. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { number } mode - indicates the database synchronization mode. + * @param { string[] } tables - indicates the database synchronization mode. + * @param { Callback } progress - the specified sync condition by the instance object of {@link ProgressDetail}. + * @param { AsyncCallback } callback - {Array<[string, number]>}: devices sync status array, {string}: device id, {number}: device sync status. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + cloudSync(mode: SyncMode, tables: string[], progress: Callback, callback: AsyncCallback): void; + + /** + * Sync data to cloud. + * + * @permission ohos.permission.DISTRIBUTED_DATASYNC + * @param { number } mode - indicates the database synchronization mode. + * @param { string[] } tables - indicates the database synchronization mode. + * @param { Callback } progress - the specified sync condition by the instance object of {@link ProgressDetail}. + * @returns { Promise } : devices sync status array, {string}: device id, {number}: device sync status. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + cloudSync(mode: SyncMode, tables: string[], progress: Callback): Promise; + + /** + * Queries remote data in the database based on specified conditions before Synchronizing Data. + * + * @param { string } device - indicates specified remote device. + * @param { string } table - indicates the target table. + * @param { RdbPredicates } predicates - the specified remote remote query condition by the instance object of {@link RdbPredicates}. + * @param { Array } columns - the columns to remote query. If the value is empty array, the remote query applies to all columns. + * @param { AsyncCallback } callback - the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + remoteQuery( + device: string, + table: string, + predicates: RdbPredicates, + columns: Array, + callback: AsyncCallback + ): void; + + /** + * Queries remote data in the database based on specified conditions before Synchronizing Data. + * + * @param { string } device - indicates specified remote device. + * @param { string } table - indicates the target table. + * @param { RdbPredicates } predicates - the specified remote remote query condition by the instance object of {@link RdbPredicates}. + * @param { Array } columns - the columns to remote query. If the value is empty array, the remote query applies to all columns. + * @returns { Promise } the {@link ResultSet} object if the operation is successful. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + remoteQuery(device: string, table: string, predicates: RdbPredicates, columns: Array): Promise; + + /** + * Registers an observer for the database. When data in the distributed database changes, + * the callback will be invoked. + * + * @param { 'dataChange' } event - indicates the event must be string 'dataChange'. + * @param { SubscribeType } type - indicates the subscription type, which is defined in {@link SubscribeType}.If its value is SUBSCRIBE_TYPE_REMOTE, ohos.permission.DISTRIBUTED_DATASYNC is required. + * @param { Callback> } observer - {Array}: the observer of data change events in the distributed database. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + on(event: 'dataChange', type: SubscribeType, observer: Callback>): void; + + /** + * Remove specified observer of specified type from the database. + * + * @param { 'dataChange' } event - indicates the event must be string 'dataChange'. + * @param { SubscribeType } type - indicates the subscription type, which is defined in {@link SubscribeType}.If its value is SUBSCRIBE_TYPE_REMOTE, ohos.permission.DISTRIBUTED_DATASYNC is required. + * @param { Callback> } observer - {Array}: the data change observer already registered. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @throws { BusinessError } 801 - Capability not supported. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + off(event: 'dataChange', type: SubscribeType, observer: Callback>): void; + } + + /** + * Manages relational database configurations. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + class RdbPredicates { + /** + * A parameterized constructor used to create a RdbPredicates instance. + * + * @param { string } name - indicates the table name of the database. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + constructor(name: string); + + /** + * Specifies remote devices which connect to local device when syncing distributed database. + * When query database, this function should not be called. + * + * @param { Array } devices - indicates specified remote devices. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + inDevices(devices: Array): RdbPredicates; + + /** + * Specifies all remote devices which connect to local device when syncing distributed database. + * When query database, this function should not be called. + * + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + inAllDevices(): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is ValueType and value is equal + * to a specified value. + * This method is similar to = of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @param { ValueType } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + equalTo(field: string, value: ValueType): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is ValueType and value is not equal to + * a specified value. + * This method is similar to != of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @param { ValueType } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + notEqualTo(field: string, value: ValueType): RdbPredicates; + + /** + * Adds a left parenthesis to the RdbPredicates. + * This method is similar to ( of the SQL statement and needs to be used together with endWrap(). + * + * @returns { RdbPredicates } - the {@link RdbPredicates} with the left parenthesis. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + beginWrap(): RdbPredicates; + + /** + * Adds a right parenthesis to the RdbPredicates. + * This method is similar to ) of the SQL statement and needs to be used together with beginWrap(). + * + * @returns { RdbPredicates } - the {@link RdbPredicates} with the right parenthesis. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + endWrap(): RdbPredicates; + + /** + * Adds an or condition to the RdbPredicates. + * This method is similar to or of the SQL statement. + * + * @returns { RdbPredicates } - the {@link RdbPredicates} with the or condition. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + or(): RdbPredicates; + + /** + * Adds an and condition to the RdbPredicates. + * This method is similar to and of the SQL statement. + * + * @returns { RdbPredicates } - the {@link RdbPredicates} with the and condition. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + and(): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is string and value + * contains a specified value. + * This method is similar to contains of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @param { string } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + contains(field: string, value: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is string and value starts + * with a specified string. + * This method is similar to value% of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @param { string } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + beginsWith(field: string, value: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the field whose data type is string and value + * ends with a specified string. + * This method is similar to %value of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @param { string } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + endsWith(field: string, value: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the fields whose value is null. + * This method is similar to is null of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isNull(field: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the specified fields whose value is not null. + * This method is similar to is not null of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @returns { RdbPredicates } - the {@link RdbPredicates} self. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isNotNull(field: string): RdbPredicates; + + /** + * Configure the RdbPredicates to match the fields whose data type is string and value is + * similar to a specified string. + * This method is similar to like of the SQL statement. + * + * @param { string } field - indicates the column name in the database table. + * @param { string } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the {@link RdbPredicates} that match the specified field. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + like(field: string, value: string): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is string and the value contains + * a wildcard. + * Different from like, the input parameters of this method are case-sensitive. + * + * @param { string } field - indicates the column name in the database table. + * @param { string } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + glob(field: string, value: string): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose value is within a given range. + * + * @param { string } field - indicates the column name. + * @param { ValueType } low - indicates the minimum value. + * @param { ValueType } high - indicates the maximum value. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + between(field: string, low: ValueType, high: ValueType): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose value is out of a given range. + * + * @param { string } field - indicates the column name in the database table. + * @param { ValueType } low - indicates the minimum value. + * @param { ValueType } high - indicates the maximum value. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + notBetween(field: string, low: ValueType, high: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be greater than the specified value. + * + * @param { string } field - indicates the column name in the database table. + * @param { ValueType } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + greaterThan(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be smaller than the specified value. + * + * @param { string } field - indicates the column name in the database table. + * @param { ValueType } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + lessThan(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be greater than or equal to the specified value. + * + * @param { string } field - indicates the column name in the database table. + * @param { ValueType } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + greaterThanOrEqualTo(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the value of the field to be smaller than or equal to the specified value. + * + * @param { string } field - indicates the column name in the database table. + * @param { ValueType } value - indicates the value to match with the {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + lessThanOrEqualTo(field: string, value: ValueType): RdbPredicates; + + /** + * Restricts the ascending order of the return list. When there are several orders, + * the one close to the head has the highest priority. + * + * @param { string } field - indicates the column name for sorting the return list. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + orderByAsc(field: string): RdbPredicates; + + /** + * Restricts the descending order of the return list. When there are several orders, + * the one close to the head has the highest priority. + * + * @param { string } field - indicates the column name for sorting the return list. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + orderByDesc(field: string): RdbPredicates; + + /** + * Restricts each row of the query result to be unique. + * + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + distinct(): RdbPredicates; + + /** + * Restricts the max number of return records. + * + * @param { number } value - indicates the max length of the return list. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + limitAs(value: number): RdbPredicates; + + /** + * Configure RdbPredicates to specify the start position of the returned result. + * Use this method together with limit(number). + * + * @param { number } rowOffset - indicates the start position of the returned result. The value is a positive integer. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + offsetAs(rowOffset: number): RdbPredicates; + + /** + * Configure RdbPredicates to group query results by specified columns. + * + * @param { Array } fields - indicates the specified columns by which query results are grouped. + * @returns { RdbPredicates } - the SQL query statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + groupBy(fields: Array): RdbPredicates; + + /** + * Configure RdbPredicates to specify the index column. + * Before using this method, you need to create an index column. + * + * @param { string } field - indicates the name of the index column. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + indexedBy(field: string): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is ValueType array and values + * are within a given range. + * + * @param { string } field - indicates the column name in the database table. + * @param { Array } value - indicates the values to match with {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + in(field: string, value: Array): RdbPredicates; + + /** + * Configure RdbPredicates to match the specified field whose data type is ValueType array and values + * are out of a given range. + * + * @param { string } field - indicates the column name in the database table. + * @param { Array } value - indicates the values to match with {@link RdbPredicates}. + * @returns { RdbPredicates } - the SQL statement with the specified {@link RdbPredicates}. + * @throws { BusinessError } 401 - if the parameter type is incorrect. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + notIn(field: string, value: Array): RdbPredicates; + } + + /** + * Provides methods for accessing a database result set generated by querying the database. + * + * @interface ResultSet + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + interface ResultSet { + /** + * Obtains the names of all columns in a result set. + * The column names are returned as a string array, in which the strings are in the same order + * as the columns in the result set. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + columnNames: Array; + + /** + * Obtains the number of columns in the result set. + * The returned number is equal to the length of the string array returned by the + * columnNames method. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + columnCount: number; + + /** + * Obtains the number of rows in the result set. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + rowCount: number; + + /** + * Obtains the current index of the result set. + * The result set index starts from 0. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + rowIndex: number; + + /** + * Checks whether the cursor is positioned at the first row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isAtFirstRow: boolean; + + /** + * Checks whether the cursor is positioned at the last row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isAtLastRow: boolean; + + /** + * Checks whether the cursor is positioned after the last row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isEnded: boolean; + + /** + * Checks whether the cursor is positioned before the first row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isStarted: boolean; + + /** + * Checks whether the current result set is closed. + * If the result set is closed by calling the close method, true will be returned. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isClosed: boolean; + + /** + * Obtains the column index based on the specified column name. + * The column name is passed as an input parameter. + * + * @param { string } columnName - indicates the name of the specified column in the result set. + * @returns { number } the index of the specified column. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - the parameter check failed. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + getColumnIndex(columnName: string): number; + + /** + * Obtains the column name based on the specified column index. + * The column index is passed as an input parameter. + * + * @param { number } columnIndex - indicates the index of the specified column in the result set. + * @returns { string } the name of the specified column. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - parameter error. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + getColumnName(columnIndex: number): string; + + /** + * Go to the specified row of the result set forwards or backwards by an offset relative to its current position. + * A positive offset indicates moving backwards, and a negative offset indicates moving forwards. + * + * @param { number } offset - indicates the offset relative to the current position. + * @returns { boolean } true if the result set is moved successfully and does not go beyond the range; + * returns false otherwise. + * @throws { BusinessError } 14800012 - the result set is empty or the specified location is invalid. + * @throws { BusinessError } 401 - parameter error. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + goTo(offset: number): boolean; + + /** + * Go to the specified row of the result set. + * + * @param { number } position - indicates the index of the specified row, which starts from 0. + * @returns { boolean } true if the result set is moved successfully; returns false otherwise. + * @throws { BusinessError } 14800012 - the result set is empty or the specified location is invalid. + * @throws { BusinessError } 401 - parameter error. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + goToRow(position: number): boolean; + + /** + * Go to the first row of the result set. + * + * @returns { boolean } true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is empty. + * @throws { BusinessError } 14800012 - the result set is empty or the specified location is invalid. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + goToFirstRow(): boolean; + + /** + * Go to the last row of the result set. + * + * @returns { boolean } true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is empty. + * @throws { BusinessError } 14800012 - the result set is empty or the specified location is invalid. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + goToLastRow(): boolean; + + /** + * Go to the next row of the result set. + * + * @returns { boolean } true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is already in the last row. + * @throws { BusinessError } 14800012 - the result set is empty or the specified location is invalid. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + goToNextRow(): boolean; + + /** + * Go to the previous row of the result set. + * + * @returns { boolean } true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is already in the first row. + * @throws { BusinessError } 14800012 - the result set is empty or the specified location is invalid. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + goToPreviousRow(): boolean; + + /** + * Obtains the value of the specified column in the current row as a byte array. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the Blob type. + * + * @param { number } columnIndex - indicates the specified column index, which starts from 0. + * @returns { Uint8Array } the value of the specified column as a byte array. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - the parameter check failed. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + getBlob(columnIndex: number): Uint8Array; + + /** + * Obtains the value of the specified column in the current row as string. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the string type. + * + * @param { number } columnIndex - indicates the specified column index, which starts from 0. + * @returns { string } the value of the specified column as a string. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - the parameter check failed. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + getString(columnIndex: number): string; + + /** + * Obtains the value of the specified column in the current row as long. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null, the specified column is not of the integer type. + * + * @param { number } columnIndex - indicates the specified column index, which starts from 0. + * @returns { number } the value of the specified column as a long. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - the parameter check failed. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + getLong(columnIndex: number): number; + + /** + * Obtains the value of the specified column in the current row as double. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null, the specified column is not of the double type. + * + * @param { number } columnIndex - indicates the specified column index, which starts from 0. + * @returns { number } the value of the specified column as a double. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - the parameter check failed. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + getDouble(columnIndex: number): number; + + /** + * Obtains the modify time of current row. + * + * @returns { string } the modify time of current row. if it is not the cloud table, the time will be empty. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - the parameter check failed. + * @syscap SystemCapability.DistributedDataManager.CloudSync.Client + * @since 10 + */ + getModifyTime(): string; + + /** + * Checks whether the value of the specified column in the current row is null. + * + * @param { number } columnIndex - indicates the specified column index, which starts from 0. + * @returns { boolean } true if the value of the specified column in the current row is null; + * returns false otherwise. + * @throws { BusinessError } 14800013 - the column value is null or the column type is incompatible. + * @throws { BusinessError } 401 - parameter error. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + isColumnNull(columnIndex: number): boolean; + + /** + * Closes the result set. + * Calling this method on the result set will release all of its resources and makes it ineffective. + * + * @throws { BusinessError } 14800012 - the result set is empty or the specified location is invalid. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 9 + */ + close(): void; + } +} + +export default relationalStore; diff --git a/relational_store/interfaces/inner_api/js/data/rdb/resultSet.d.ts b/relational_store/interfaces/inner_api/js/data/rdb/resultSet.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..351e3abfe0634162ef228f7f97174649bf1fcdbb --- /dev/null +++ b/relational_store/interfaces/inner_api/js/data/rdb/resultSet.d.ts @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * 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. + */ + +import { AsyncCallback } from '../../@ohos.base'; + +/** + * Provides methods for accessing a database result set generated by querying the database. + * + * @interface ResultSet + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet + */ +export interface ResultSet { + /** + * Obtains the names of all columns in a result set. + * The column names are returned as a string array, in which the strings are in the same order + * as the columns in the result set. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.columnNames + */ + columnNames: Array; + + /** + * Obtains the number of columns in the result set. + * The returned number is equal to the length of the string array returned by the + * columnCount method. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.columnCount + */ + columnCount: number; + + /** + * Obtains the number of rows in the result set. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.rowCount + */ + rowCount: number; + + /** + * Obtains the current index of the result set. + * The result set index starts from 0. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.rowIndex + */ + rowIndex: number; + + /** + * Checks whether the result set is positioned at the first row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.isAtFirstRow + */ + isAtFirstRow: boolean; + + /** + * Checks whether the result set is positioned at the last row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.isAtLastRow + */ + isAtLastRow: boolean; + + /** + * Checks whether the result set is positioned after the last row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.isEnded + */ + isEnded: boolean; + + /** + * returns whether the cursor is pointing to the position before the first + * row. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.isStarted + */ + isStarted: boolean; + + /** + * Checks whether the current result set is closed. + * If the result set is closed by calling the close method, true will be returned. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.isClosed + */ + isClosed: boolean; + + /** + * Obtains the column index based on the specified column name. + * The column name is passed as an input parameter. + * + * @param { string } columnName - Indicates the name of the specified column in the result set. + * @returns { number } return the index of the specified column. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.getColumnIndex + */ + getColumnIndex(columnName: string): number; + + /** + * Obtains the column name based on the specified column index. + * The column index is passed as an input parameter. + * + * @param { number } columnIndex - Indicates the index of the specified column in the result set. + * @returns { string } returns the name of the specified column. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.getColumnName + */ + getColumnName(columnIndex: number): string; + + /** + * Go to the specified row of the result set forwards or backwards by an offset relative to its current position. + * A positive offset indicates moving backwards, and a negative offset indicates moving forwards. + * + * @param { number } offset - Indicates the offset relative to the current position. + * @returns { boolean } returns true if the result set is moved successfully and does not go beyond the range; + * returns false otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.goTo + */ + goTo(offset: number): boolean; + + /** + * Go to the specified row of the result set. + * + * @param { number } position - Indicates the index of the specified row, which starts from 0. + * @returns { boolean } returns true if the result set is moved successfully; returns false otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.goToRow + */ + goToRow(position: number): boolean; + + /** + * Go to the first row of the result set. + * + * @returns { boolean } returns true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is empty. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.goToFirstRow + */ + goToFirstRow(): boolean; + + /** + * Go to the last row of the result set. + * + * @returns { boolean } returns true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is empty. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.goToLastRow + */ + goToLastRow(): boolean; + + /** + * Go to the next row of the result set. + * + * @returns { boolean } returns true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is already in the last row. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.goToNextRow + */ + goToNextRow(): boolean; + + /** + * Go to the previous row of the result set. + * + * @returns { boolean } returns true if the result set is moved successfully; + * returns false otherwise, for example, if the result set is already in the first row. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.goToPreviousRow + */ + goToPreviousRow(): boolean; + + /** + * Obtains the value of the specified column in the current row as a byte array. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the Blob type. + * + * @param { number } columnIndex - Indicates the specified column index, which starts from 0. + * @returns { Uint8Array } returns the value of the specified column as a byte array. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.getBlob + */ + getBlob(columnIndex: number): Uint8Array; + + /** + * Obtains the value of the specified column in the current row as string. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the string type. + * + * @param { number } columnIndex - Indicates the specified column index, which starts from 0. + * @returns { string } returns the value of the specified column as a string. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.getString + */ + getString(columnIndex: number): string; + + /** + * Obtains the value of the specified column in the current row as long. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null, the specified column is not of the integer type. + * + * @param { number } columnIndex - Indicates the specified column index, which starts from 0. + * @returns { number } returns the value of the specified column as a long. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.getLong + */ + getLong(columnIndex: number): number; + + /** + * Obtains the value of the specified column in the current row as double. + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null, the specified column is not of the double type. + * + * @param { number } columnIndex - Indicates the specified column index, which starts from 0. + * @returns { number } returns the value of the specified column as a double. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.getDouble + */ + getDouble(columnIndex: number): number; + + /** + * Checks whether the value of the specified column in the current row is null. + * + * @param { number } columnIndex - Indicates the specified column index, which starts from 0. + * @returns { boolean } returns true if the value of the specified column in the current row is null; + * returns false otherwise. + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.isColumnNull + */ + isColumnNull(columnIndex: number): boolean; + /** + * Closes the result set. + * Calling this method on the result set will release all of its resources and makes it ineffective. + * + * @syscap SystemCapability.DistributedDataManager.RelationalStore.Core + * @since 7 + * @deprecated since 9 + * @useinstead ohos.data.relationalStore.ResultSet.close + */ + close(): void; +} diff --git a/relational_store/interfaces/inner_api/rdb/BUILD.gn b/relational_store/interfaces/inner_api/rdb/BUILD.gn index c5a0a05b6a3ad3b2ffbf782b17cd0ffb49529baf..4003c7ef6d720aa44e18cb9c6597faf833597c28 100644 --- a/relational_store/interfaces/inner_api/rdb/BUILD.gn +++ b/relational_store/interfaces/inner_api/rdb/BUILD.gn @@ -29,8 +29,12 @@ config("native_rdb_config") { "include", "//base/security/huks/frameworks/huks_standard/main/common/include", "${relational_store_native_path}/rdb/include", + "${relational_store_native_path}/rdb_device_manager_adapter/include", "//utils/system/safwk/native/include", "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/include/", + "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/interfaces/include/", + "//foundation/distributeddatamgr/kv_store/frameworks/libs/distributeddb/interfaces/include/relational", ] } @@ -104,7 +108,6 @@ base_sources = [ "${relational_store_native_path}/rdb/src/sqlite_statement.cpp", "${relational_store_native_path}/rdb/src/sqlite_utils.cpp", "${relational_store_native_path}/rdb/src/step_result_set.cpp", - "${relational_store_native_path}/rdb/src/store_session.cpp", "${relational_store_native_path}/rdb/src/string_utils.cpp", "${relational_store_native_path}/rdb/src/value_object.cpp", "${relational_store_native_path}/rdb/src/values_bucket.cpp", @@ -148,7 +151,6 @@ ohos_shared_library("native_rdb") { sources += [ "${relational_store_native_path}/rdb/src/abs_shared_result_set.cpp", - "${relational_store_native_path}/rdb/src/rdb_manager.cpp", "${relational_store_native_path}/rdb/src/rdb_manager_impl.cpp", "${relational_store_native_path}/rdb/src/rdb_notifier_stub.cpp", "${relational_store_native_path}/rdb/src/rdb_security_manager.cpp", @@ -159,6 +161,7 @@ ohos_shared_library("native_rdb") { "${relational_store_native_path}/rdb/src/share_block.cpp", "${relational_store_native_path}/rdb/src/shared_block_serializer_info.cpp", "${relational_store_native_path}/rdb/src/sqlite_shared_result_set.cpp", + "${relational_store_native_path}/rdb_device_manager_adapter/src/rdb_device_manager_adapter.cpp", ] public_deps = @@ -166,6 +169,7 @@ ohos_shared_library("native_rdb") { external_deps = [ "c_utils:utils", + "device_manager:devicemanagersdk", "hilog_native:libhilog", "hitrace_native:hitrace_meter", "huks:libhukssdk", @@ -210,7 +214,6 @@ ohos_static_library("native_rdb_static") { sources += [ "${relational_store_native_path}/rdb/src/abs_shared_result_set.cpp", - "${relational_store_native_path}/rdb/src/rdb_manager.cpp", "${relational_store_native_path}/rdb/src/rdb_manager_impl.cpp", "${relational_store_native_path}/rdb/src/rdb_notifier_stub.cpp", "${relational_store_native_path}/rdb/src/rdb_security_manager.cpp", @@ -221,6 +224,7 @@ ohos_static_library("native_rdb_static") { "${relational_store_native_path}/rdb/src/share_block.cpp", "${relational_store_native_path}/rdb/src/shared_block_serializer_info.cpp", "${relational_store_native_path}/rdb/src/sqlite_shared_result_set.cpp", + "${relational_store_native_path}/rdb_device_manager_adapter/src/rdb_device_manager_adapter.cpp", ] public_deps = @@ -228,6 +232,7 @@ ohos_static_library("native_rdb_static") { external_deps = [ "c_utils:utils", + "device_manager:devicemanagersdk", "hilog_native:libhilog", "hitrace_native:hitrace_meter", "huks:libhukssdk", diff --git a/relational_store/interfaces/inner_api/rdb/include/abs_rdb_predicates.h b/relational_store/interfaces/inner_api/rdb/include/abs_rdb_predicates.h index 9ec8ab6393ce000f91725e9feb5daed189e9adba..6416708b0664e1db659a4bf43b66e9c8f8a86199 100644 --- a/relational_store/interfaces/inner_api/rdb/include/abs_rdb_predicates.h +++ b/relational_store/interfaces/inner_api/rdb/include/abs_rdb_predicates.h @@ -176,7 +176,7 @@ public: RDB_API_EXPORT virtual std::string GetJoinClause() const; /** - * @brief Sets the number of joins in the predicates. + * @brief Obtains the number of joins in the predicates. */ RDB_API_EXPORT virtual int GetJoinCount() const; diff --git a/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h b/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h index 708337ffdc8bd163b0670baf5ed778c4833c9a81..9f2a3469576ff71d3d6523a33552ab873502bcf5 100644 --- a/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h +++ b/relational_store/interfaces/inner_api/rdb/include/abs_result_set.h @@ -22,6 +22,7 @@ #include #include "result_set.h" +#include "value_object.h" namespace OHOS { namespace NativeRdb { @@ -111,6 +112,40 @@ public: */ RDB_API_EXPORT int GetDouble(int columnIndex, double &value) override; + /** + * @brief Obtains the value of the specified column in the current row as asset. + * + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the double type. + * + * @param columnIndex Indicates the specified column index, which starts from 0. + * + * @return Returns the value of the specified column as a double. + */ + RDB_API_EXPORT int GetAsset(int32_t col, ValueObject::Asset &value) override; + + /** + * @brief Obtains the value of the specified column in the current row as assets. + * + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the double type. + * + * @param columnIndex Indicates the specified column index, which starts from 0. + * + * @return Returns the value of the specified column as a double. + */ + RDB_API_EXPORT int GetAssets(int32_t col, ValueObject::Assets &value) override; + + /** + * @brief Get the modify time of the cloud data. + * + * @param modifyTime Indicates the data modify utc time. + * + * @return Returns true if the value of the specified column in the current row is null; + * returns false otherwise. + */ + RDB_API_EXPORT int GetModifyTime(std::string &modifyTime) override; + /** * @brief Checks whether the value of the specified column in the current row is null. * @@ -121,6 +156,11 @@ public: */ RDB_API_EXPORT int IsColumnNull(int columnIndex, bool &isNull) override; + /** + * @brief Gets the entire row of data for the current row from the result set. + */ + RDB_API_EXPORT int GetRow(RowEntity &rowEntity) override; + /** * @brief Move the cursor to an absolute position. * diff --git a/relational_store/interfaces/inner_api/rdb/include/abs_shared_result_set.h b/relational_store/interfaces/inner_api/rdb/include/abs_shared_result_set.h index c2a68ce75645f6f4f5725318ccaeae948ce70057..448e91c307413344667a967d3c0f3c82e57ffa70 100644 --- a/relational_store/interfaces/inner_api/rdb/include/abs_shared_result_set.h +++ b/relational_store/interfaces/inner_api/rdb/include/abs_shared_result_set.h @@ -112,6 +112,30 @@ public: */ RDB_API_EXPORT int GetDouble(int columnIndex, double &value) override; + /** + * @brief Obtains the value of the specified column in the current row as asset. + * + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the double type. + * + * @param columnIndex Indicates the specified column index, which starts from 0. + * + * @return Returns the value of the specified column as a double. + */ + RDB_API_EXPORT int GetAsset(int32_t col, ValueObject::Asset &value) override; + + /** + * @brief Obtains the value of the specified column in the current row as assets. + * + * The implementation class determines whether to throw an exception if the value of the specified column + * in the current row is null or the specified column is not of the double type. + * + * @param columnIndex Indicates the specified column index, which starts from 0. + * + * @return Returns the value of the specified column as a double. + */ + RDB_API_EXPORT int GetAssets(int32_t col, ValueObject::Assets &value) override; + /** * @brief Checks whether the value of the specified column in the current row is null. * diff --git a/relational_store/interfaces/inner_api/rdb/include/asset_value.h b/relational_store/interfaces/inner_api/rdb/include/asset_value.h new file mode 100644 index 0000000000000000000000000000000000000000..ad891c37e93353608a5875c9af36ff141fe8116b --- /dev/null +++ b/relational_store/interfaces/inner_api/rdb/include/asset_value.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 OHOS_RELATIONAL_STORE_INNER_API_ASSET_VALUE_H +#define OHOS_RELATIONAL_STORE_INNER_API_ASSET_VALUE_H +#include +#include +namespace OHOS::NativeRdb { +struct AssetValue { + uint32_t version = 0; + std::string name; + std::string uri; + std::string createTime; + std::string modifyTime; + std::string size; + std::string hash; +}; +} +#endif // OHOS_RELATIONAL_STORE_INNER_API_ASSET_VALUE_H diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_common.h b/relational_store/interfaces/inner_api/rdb/include/rdb_common.h index 766d7f0159ccf2e05f318bf1f8d0b6b134959ab6..2c9b1c0eb49973c6ae2442580f8f3ef3c40c4952 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_common.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_common.h @@ -34,5 +34,4 @@ enum class ConflictResolution { }; } } - #endif // NATIVE_RDB_RDB_COMMON_H diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h b/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h index c3ca4d4c3ec0c05026d4c5287e48cbfa3c250f51..113dd59819903d7d29b88dc7fce18f972edca422 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_errno.h @@ -29,6 +29,11 @@ constexpr int E_OK = 0; */ constexpr int E_BASE = 14800000; +/** +* @brief The error when the capability not supported. +*/ +constexpr int E_NOT_SUPPORTED = 801; + /** * @brief The error code for common exceptions. */ @@ -55,9 +60,9 @@ constexpr int E_EMPTY_TABLE_NAME = (E_BASE + 5); constexpr int E_EMPTY_VALUES_BUCKET = (E_BASE + 6); /** -* @brief The error code for the current status is invalid. +* @brief The error code when the sql is not select. */ -constexpr int E_INVALID_STATEMENT = (E_BASE + 7); +constexpr int E_EXECUTE_IN_STEP_QUERY = (E_BASE + 7); /** * @brief The error code for the column index is invalid. @@ -85,9 +90,9 @@ constexpr int E_INVALID_FILE_PATH = (E_BASE + 11); constexpr int E_TRANSACTION_IN_EXECUTE = (E_BASE + 12); /** -* @brief The error code when the sql is not select. +* @brief The error code for the current status is invalid. */ -constexpr int E_EXECUTE_IN_STEP_QUERY = (E_BASE + 13); +constexpr int E_INVALID_STATEMENT = (E_BASE + 13); /** * @brief The error code when execute write operation in read connection. @@ -258,6 +263,11 @@ constexpr int E_ARGS_READ_CON_OVERLOAD = (E_BASE + 46); * @brief The error when the wal file size over default limit. */ static constexpr int E_WAL_SIZE_OVER_LIMIT = (E_BASE + 47); + +/** +* @brief The error when the connection count is used up. +*/ +static constexpr int E_CON_OVER_LIMIT = (E_BASE + 48); } // namespace NativeRdb } // namespace OHOS diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_predicates.h b/relational_store/interfaces/inner_api/rdb/include/rdb_predicates.h index 0c6a7a4ba7297ce91da8b7e5d0b2e1cde0e40956..bdff3871ba99e8d992136393c8837f899a9489f4 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_predicates.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_predicates.h @@ -15,8 +15,6 @@ #ifndef NATIVE_RDB_RDBPREDICATES_H #define NATIVE_RDB_RDBPREDICATES_H - - #include "abs_rdb_predicates.h" #include "rdb_visibility.h" diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_service.h b/relational_store/interfaces/inner_api/rdb/include/rdb_service.h index a72ebf72e7d766f6ecb224db65b8e7298c242dad..9cef9274d502823d79245eb847220df5f03bcfa9 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_service.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_service.h @@ -37,6 +37,7 @@ public: RDB_SERVICE_CMD_REMOTE_QUERY, RDB_SERVICE_CREATE_RDB_TABLE, RDB_SERVICE_DESTROY_RDB_TABLE, + RDB_SERVICE_CMD_GET_SCHEMA, RDB_SERVICE_CMD_MAX }; virtual std::string ObtainDistributedTableName(const std::string &device, const std::string &table) = 0; @@ -59,8 +60,11 @@ public: virtual int32_t DestroyRDBTable(const RdbSyncerParam ¶m) = 0; - virtual int32_t InitNotifier(const RdbSyncerParam ¶m, const sptr notifier) = 0; + virtual int32_t InitNotifier(const std::string& bundleName, const sptr ¬ifier) = 0; + virtual int32_t GetSchema(const std::string &bundleName, const std::string &storeName) = 0; + + static constexpr const char *SERVICE_NAME = "relational_store"; protected: virtual int32_t DoSync(const RdbSyncerParam ¶m, const SyncOption &option, const RdbPredicates &predicates, SyncResult &result) = 0; diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_store.h b/relational_store/interfaces/inner_api/rdb/include/rdb_store.h index 72ab6599940e715f7abb9466cc1375fcf3b307c6..d20fd73633ef70fa59199740a959a3663b5d82bb 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_store.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_store.h @@ -27,6 +27,7 @@ #include "values_bucket.h" #include "rdb_types.h" #include "rdb_common.h" +#include "rdb_errno.h" namespace OHOS::NativeRdb { class RDB_API_EXPORT RdbStore { @@ -270,8 +271,8 @@ public: * @param predicates Indicates the specified query condition by the instance object of {@link AbsRdbPredicates}. * @param columns Indicates the columns to query. If the value is empty array, the query applies to all columns. */ - virtual std::shared_ptr RemoteQuery(const std::string &device, - const AbsRdbPredicates &predicates, const std::vector &columns) = 0; + virtual std::shared_ptr RemoteQuery(const std::string &device, const AbsRdbPredicates &predicates, + const std::vector &columns, int &errCode) = 0; /** * @brief Updates data in the database based on a a specified instance object of AbsRdbPredicates. @@ -364,7 +365,7 @@ public: * * @param tables Indicates the tables name you want to set. */ - virtual bool SetDistributedTables(const std::vector& tables) = 0; + virtual int SetDistributedTables(const std::vector& tables) = 0; /** * @brief Obtain distributed table name of specified remote device according to local table name. @@ -374,7 +375,8 @@ public: * * @return Returns the distributed table name. */ - virtual std::string ObtainDistributedTableName(const std::string& device, const std::string& table) = 0; + virtual std::string ObtainDistributedTableName( + const std::string &device, const std::string &table, int &errCode) = 0; /** * @brief Sync data between devices. @@ -382,17 +384,17 @@ public: * @param device Indicates the remote device. * @param predicate Indicates the AbsRdbPredicates {@link AbsRdbPredicates} object. */ - virtual bool Sync(const SyncOption& option, const AbsRdbPredicates& predicate, const SyncCallback& callback) = 0; + virtual int Sync(const SyncOption& option, const AbsRdbPredicates& predicate, const SyncCallback& callback) = 0; /** * @brief Subscribe to event changes. */ - virtual bool Subscribe(const SubscribeOption& option, RdbStoreObserver *observer) = 0; + virtual int Subscribe(const SubscribeOption& option, RdbStoreObserver *observer) = 0; /** * @brief UnSubscribe to event changes. */ - virtual bool UnSubscribe(const SubscribeOption& option, RdbStoreObserver *observer) = 0; + virtual int UnSubscribe(const SubscribeOption& option, RdbStoreObserver *observer) = 0; /** * @brief Drop the specified devices Data. diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h b/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h index 0e65d864ff6a24fe454391e88926d657b81ecbdf..ad3c98bfa96e3a6b044e408b9f6c62660c3548a3 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_store_config.h @@ -417,7 +417,18 @@ public: */ RDB_API_EXPORT void SetReadConSize(int readConSize); + /** + * @brief Sets the encrypt key for the object. + */ + void SetEncryptKey(const std::vector &encryptKey); + + /** + * @brief Obtains the encrypt key in this {@code StoreConfig} object. + */ + std::vector GetEncryptKey() const; private: + void ClearEncryptKey(); + std::string name; std::string path; StorageMode storageMode; @@ -434,6 +445,7 @@ private: std::string moduleName_; bool isEncrypt_ = false; + std::vector encryptKey_{}; SecurityLevel securityLevel = SecurityLevel::LAST; std::string uri_; std::string readPermission_; @@ -445,6 +457,11 @@ private: int pageSize; int readConSize_ = 4; std::string encryptAlgo; + + //cloud rdb + std::string cloudId_; +// int32_t schemaVerion_ = -1; + }; } // namespace OHOS::NativeRdb diff --git a/relational_store/interfaces/inner_api/rdb/include/rdb_types.h b/relational_store/interfaces/inner_api/rdb/include/rdb_types.h index 2dfc6044fc7c4cb4b995db5a78329bef8c78662e..291c648436fb3e20570a20531fabf5c4ddcf4e82 100644 --- a/relational_store/interfaces/inner_api/rdb/include/rdb_types.h +++ b/relational_store/interfaces/inner_api/rdb/include/rdb_types.h @@ -48,9 +48,19 @@ struct RdbSyncerParam { }; }; +struct CloudParam { + std::string bundleName; + std::string storeName; + std::string cloudId; +// int32_t schemaVerion; +}; + enum SyncMode { PUSH, PULL, + TIME_FIRST, + NATIVE_FIRST, + CLOUD_FIRST, }; struct SyncOption { @@ -96,6 +106,7 @@ struct RdbPredicates { enum SubscribeMode { REMOTE, + CLOUD, SUBSCRIBE_MODE_MAX }; diff --git a/relational_store/interfaces/inner_api/rdb/include/remote_result_set.h b/relational_store/interfaces/inner_api/rdb/include/remote_result_set.h new file mode 100644 index 0000000000000000000000000000000000000000..e32ac243ddbf1a61ec3b15a77693404cea35ecc2 --- /dev/null +++ b/relational_store/interfaces/inner_api/rdb/include/remote_result_set.h @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 NATIVE_RDB_REMOTE_RESULT_SET_H +#define NATIVE_RDB_REMOTE_RESULT_SET_H + +#include +#include +#include "rdb_visibility.h" + +namespace OHOS { +namespace NativeRdb { + +/** + * @brief Indicates the column type. + * + * Value returned by getColumnType(int) + */ +enum class ColumnType { + /** Indicates the column type is NULL.*/ + TYPE_NULL = 0, + /** Indicates the column type is INTEGER.*/ + TYPE_INTEGER, + /** Indicates the column type is FLOAT.*/ + TYPE_FLOAT, + /** Indicates the column type is STRING.*/ + TYPE_STRING, + /** Indicates the column type is BLOB.*/ + TYPE_BLOB, +}; + +/** + * The RemoteResultSet class of RDB. + * Provides methods for accessing a database result set generated by remote query the database. + */ +class RDB_API_EXPORT RemoteResultSet { +public: + /** + * @brief The error CMD in the correct case. + */ + enum { + /** Indicates the current CMD is CMD_GET_ALL_COLUMN_NAMES.*/ + CMD_GET_ALL_COLUMN_NAMES, + /** Indicates the current CMD is CMD_GET_COLUMN_COUNT.*/ + CMD_GET_COLUMN_COUNT, + /** Indicates the current CMD is CMD_GET_COLUMN_TYPE.*/ + CMD_GET_COLUMN_TYPE, + /** Indicates the current CMD is CMD_GET_COLUMN_INDEX.*/ + CMD_GET_COLUMN_INDEX, + /** Indicates the current CMD is CMD_GET_COLUMN_NAME.*/ + CMD_GET_COLUMN_NAME, + /** Indicates the current CMD is CMD_GET_ROW_COUNT.*/ + CMD_GET_ROW_COUNT, + /** Indicates the current CMD is CMD_GET_ROW_INDEX.*/ + CMD_GET_ROW_INDEX, + /** Indicates the current CMD is CMD_GO_TO.*/ + CMD_GO_TO, + /** Indicates the current CMD is CMD_GO_TO_ROW.*/ + CMD_GO_TO_ROW, + /** Indicates the current CMD is CMD_GO_TO_FIRST_ROW.*/ + CMD_GO_TO_FIRST_ROW, + /** Indicates the current CMD is CMD_GO_TO_LAST_ROW.*/ + CMD_GO_TO_LAST_ROW, + /** Indicates the current CMD is CMD_GO_TO_NEXT_ROW.*/ + CMD_GO_TO_NEXT_ROW, + /** Indicates the current CMD is CMD_GO_TO_PREV_ROW.*/ + CMD_GO_TO_PREV_ROW, + /** Indicates the current CMD is CMD_IS_ENDED_ROW.*/ + CMD_IS_ENDED_ROW, + /** Indicates the current CMD is CMD_IS_STARTED_ROW.*/ + CMD_IS_STARTED_ROW, + /** Indicates the current CMD is CMD_IS_AT_FIRST_ROW.*/ + CMD_IS_AT_FIRST_ROW, + /** Indicates the current CMD is CMD_IS_AT_LAST_ROW.*/ + CMD_IS_AT_LAST_ROW, + /** Indicates the current CMD is CMD_GET_BLOB.*/ + CMD_GET_BLOB, + /** Indicates the current CMD is CMD_GET_STRING.*/ + CMD_GET_STRING, + /** Indicates the current CMD is CMD_GET_INT.*/ + CMD_GET_INT, + /** Indicates the current CMD is CMD_GET_LONG.*/ + CMD_GET_LONG, + /** Indicates the current CMD is CMD_GET_DOUBLE.*/ + CMD_GET_DOUBLE, + /** Indicates the current CMD is CMD_IS_COLUMN_NULL.*/ + CMD_IS_COLUMN_NULL, + /** Indicates the current CMD is CMD_IS_CLOSED.*/ + CMD_IS_CLOSED, + /** Indicates the current CMD is CMD_CLOSE.*/ + CMD_CLOSE, + /** Indicates the current CMD is CMD_MAX.*/ + CMD_MAX + }; + + /** + * @brief Destructor. + */ + virtual ~RemoteResultSet() {} + + /** + * @brief Obtains a string array holding the names of all of the columns in the result set. + * + * @return Returns the names of the columns contains in this query result. + */ + virtual int GetAllColumnNames(std::vector &columnNames) = 0; + + /** + * @brief Obtains the total number of columns. + * + * @return Returns the number of columns + */ + virtual int GetColumnCount(int &count) = 0; + + /** + * @brief Obtains data type of the given column's value. + * + * @param columnIndex Indicates the zero-based index of the target column. + * @return Returns column value type. + */ + virtual int GetColumnType(int columnIndex, ColumnType &columnType) = 0; + + /** + * @brief Obtains the zero-based index for the given column name. + * + * @param columnName Indicates the name of the column. + * @return Returns the column index for the given column, or -1 if the column does not exist. + */ + virtual int GetColumnIndex(const std::string &columnName, int &columnIndex) = 0; + + /** + * @brief Obtains the column name at the given column index. + * + * @param columnIndex Indicates the zero-based index. + * @return Returns the column name for the given index. + */ + virtual int GetColumnName(int columnIndex, std::string &columnName) = 0; + + /** + * @brief Obtains the numbers of rows in the result set. + */ + virtual int GetRowCount(int &count) = 0; + + /** + * @brief Obtains the current position of the cursor in the result set. + * + * The value is zero-based. When the result set is first returned the cursor + * will be at position -1, which is before the first row. + * After the last row is returned another call to next() will leave the cursor past + * the last entry, at a position of count(). + * + * @return Returns the current cursor position. + */ + virtual int GetRowIndex(int &position) const = 0; + + /** + * @brief Move the cursor a relative amount from current position. Positive offset move forward, + * negative offset move backward. + * + * @param offset Indicates the offset to be applied from the current position. + * @return Returns whether the requested move succeeded. + */ + virtual int GoTo(int offset) = 0; + + /** + * @brief Move the cursor to an absolute position. + * + * @param position Indicates the zero-based position to move to. + * @return Returns whether the requested move succeeded. + */ + virtual int GoToRow(int position) = 0; + + /** + * @brief Move the cursor to the first row. + * + * @return Returns whether the requested move succeeded. + */ + virtual int GoToFirstRow() = 0; + + /** + * @brief Move the cursor to the last row. + * + * @return Returns whether the requested move succeeded. + */ + virtual int GoToLastRow() = 0; + + /** + * @brief Move the cursor to the next row. + * + * @return Returns whether the requested move succeeded. + */ + virtual int GoToNextRow() = 0; + + /** + * @brief Move the cursor to the previous row. + * + * @return Returns whether the requested move succeeded. + */ + virtual int GoToPreviousRow() = 0; + + /** + * @brief Obtains whether the cursor is pointing to the position after the last row. + * + * @return Returns whether the cursor is after the last row. + */ + virtual int IsEnded(bool &result) = 0; + + /** + * @brief Obtains whether the cursor is pointing to the position before the first row. + * + * @return Returns whether the cursor is before the first row. + */ + virtual int IsStarted(bool &result) const = 0; + + /** + * @brief Obtains whether the cursor is pointing to the first row. + * + * @return Returns whether the cursor is pointing at the first entry. + */ + virtual int IsAtFirstRow(bool &result) const = 0; + + /** + * @brief Obtains whether the cursor is pointing to the last row. + * + * @return Returns whether the cursor is pointing at the last entry. + */ + virtual int IsAtLastRow(bool &result) = 0; + + /** + * @brief Obtains the value of the requested column as a byte array. + * + * @param columnIndex Indicates the zero-based index of the target column. + * @return Returns the value of the requested column as a byte array. + */ + virtual int GetBlob(int columnIndex, std::vector &blob) = 0; + + /** + * @brief Obtains the value of the requested column as a String. + * + * @param columnIndex Indicates the zero-based index of the target column. + * @return Returns the value of the requested column as a String. + */ + virtual int GetString(int columnIndex, std::string &value) = 0; + + /** + * @brief Obtains the value of the requested column as a int. + * + * @param columnIndex Indicates the zero-based index of the target column. + * @return Returns the value of the requested column as a int. + */ + virtual int GetInt(int columnIndex, int &value) = 0; + + /** + * @brief Obtains the value of the requested column as a long. + * + * @param columnIndex Indicates the zero-based index of the target column. + * @return Returns the value of the requested column as a long. + */ + virtual int GetLong(int columnIndex, int64_t &value) = 0; + + /** + * @brief Obtains the value of the requested column as a double. + * + * @param columnIndex Indicates the zero-based index of the target column. + * @return Returns the value of the requested column as a double. + */ + virtual int GetDouble(int columnIndex, double &value) = 0; + + /** + * @brief Obtains Whether the value of the requested column is null. + * + * @param columnIndex Indicates the zero-based index of the target column. + * @return Returns whether the column value is null. + */ + virtual int IsColumnNull(int columnIndex, bool &isNull) = 0; + + /** + * @brief Obtains Return true if the result set is closed. + * + * @return Returns true if the result set is closed. + */ + virtual bool IsClosed() const = 0; + + /** + * @brief Closes the result set, releasing all of its resources and making it completely invalid. + */ + virtual int Close() = 0; +}; + +} // namespace NativeRdb +} // namespace OHOS +#endif diff --git a/relational_store/interfaces/inner_api/rdb/include/result_set.h b/relational_store/interfaces/inner_api/rdb/include/result_set.h index e4b2ace9890b19fd5a47b2305f823d3227b9f357..4e70b2d7ce538509833281534f8ef3e3f8243129 100644 --- a/relational_store/interfaces/inner_api/rdb/include/result_set.h +++ b/relational_store/interfaces/inner_api/rdb/include/result_set.h @@ -16,286 +16,46 @@ #ifndef NATIVE_RDB_RESULT_SET_H #define NATIVE_RDB_RESULT_SET_H +#include #include #include -#include "rdb_visibility.h" + +#include "remote_result_set.h" +#include "value_object.h" + namespace OHOS { namespace NativeRdb { - -/** - * @brief Indicates the column type. - * - * Value returned by getColumnType(int) - */ -enum class ColumnType { - /** Indicates the column type is NULL.*/ - TYPE_NULL = 0, - /** Indicates the column type is INTEGER.*/ - TYPE_INTEGER, - /** Indicates the column type is NULL.*/ - TYPE_FLOAT, - /** Indicates the column type is FLOAT.*/ - TYPE_STRING, - /** Indicates the column type is STRING.*/ - TYPE_BLOB, +struct RDB_API_EXPORT RowEntity { +public: + RDB_API_EXPORT void Put(const std::string &name, const ValueObject &value); + RDB_API_EXPORT ValueObject Get(const std::string &name) const; + RDB_API_EXPORT ValueObject Get(const int index) const; + RDB_API_EXPORT void Get(std::map &outValues) const; + RDB_API_EXPORT void Clear(); + +private: + std::map values_; + std::vector indexs_; }; /** * The ResultSet class of RDB. * Provides methods for accessing a database result set generated by querying the database. */ -class RDB_API_EXPORT ResultSet { +class RDB_API_EXPORT ResultSet : public RemoteResultSet { public: - /** - * @brief The error CMD in the correct case. - */ - enum { - /** Indicates the current error CMD is CMD_GET_ALL_COLUMN_NAMES.*/ - CMD_GET_ALL_COLUMN_NAMES, - /** Indicates the current error CMD is CMD_GET_COLUMN_COUNT.*/ - CMD_GET_COLUMN_COUNT, - /** Indicates the current error CMD is CMD_GET_COLUMN_TYPE.*/ - CMD_GET_COLUMN_TYPE, - /** Indicates the current error CMD is CMD_GET_COLUMN_INDEX.*/ - CMD_GET_COLUMN_INDEX, - /** Indicates the current error CMD is CMD_GET_COLUMN_NAME.*/ - CMD_GET_COLUMN_NAME, - /** Indicates the current error CMD is CMD_GET_ROW_COUNT.*/ - CMD_GET_ROW_COUNT, - /** Indicates the current error CMD is CMD_GET_ROW_INDEX.*/ - CMD_GET_ROW_INDEX, - /** Indicates the current error CMD is CMD_GO_TO.*/ - CMD_GO_TO, - /** Indicates the current error CMD is CMD_GO_TO_ROW.*/ - CMD_GO_TO_ROW, - /** Indicates the current error CMD is CMD_GO_TO_FIRST_ROW.*/ - CMD_GO_TO_FIRST_ROW, - /** Indicates the current error CMD is CMD_GO_TO_LAST_ROW.*/ - CMD_GO_TO_LAST_ROW, - /** Indicates the current error CMD is CMD_GO_TO_NEXT_ROW.*/ - CMD_GO_TO_NEXT_ROW, - /** Indicates the current error CMD is CMD_GO_TO_PREV_ROW.*/ - CMD_GO_TO_PREV_ROW, - /** Indicates the current error CMD is CMD_IS_ENDED_ROW.*/ - CMD_IS_ENDED_ROW, - /** Indicates the current error CMD is CMD_IS_STARTED_ROW.*/ - CMD_IS_STARTED_ROW, - /** Indicates the current error CMD is CMD_IS_AT_FIRST_ROW.*/ - CMD_IS_AT_FIRST_ROW, - /** Indicates the current error CMD is CMD_IS_AT_LAST_ROW.*/ - CMD_IS_AT_LAST_ROW, - /** Indicates the current error CMD is CMD_GET_BLOB.*/ - CMD_GET_BLOB, - /** Indicates the current error CMD is CMD_GET_STRING.*/ - CMD_GET_STRING, - /** Indicates the current error CMD is CMD_GET_INT.*/ - CMD_GET_INT, - /** Indicates the current error CMD is CMD_GET_LONG.*/ - CMD_GET_LONG, - /** Indicates the current error CMD is CMD_GET_DOUBLE.*/ - CMD_GET_DOUBLE, - /** Indicates the current error CMD is CMD_IS_COLUMN_NULL.*/ - CMD_IS_COLUMN_NULL, - /** Indicates the current error CMD is CMD_IS_CLOSED.*/ - CMD_IS_CLOSED, - /** Indicates the current error CMD is CMD_CLOSE.*/ - CMD_CLOSE, - /** Indicates the current error CMD is CMD_MAX.*/ - CMD_MAX - }; - /** * @brief Destructor. */ virtual ~ResultSet() {} + virtual int GetAsset(int32_t col, ValueObject::Asset &value) = 0; + virtual int GetAssets(int32_t col, ValueObject::Assets &value) = 0; /** - * @brief Obtains a string array holding the names of all of the columns in the result set. - * - * @return Returns the names of the columns contains in this query result. - */ - virtual int GetAllColumnNames(std::vector &columnNames) = 0; - - /** - * @brief Obtains the total number of columns. - * - * @return Returns the number of columns - */ - virtual int GetColumnCount(int &count) = 0; - - /** - * @brief Obtains data type of the given column's value. - * - * @param columnIndex Indicates the zero-based index of the target column. - * @return Returns column value type. - */ - virtual int GetColumnType(int columnIndex, ColumnType &columnType) = 0; - - /** - * @brief Obtains the zero-based index for the given column name. - * - * @param columnName Indicates the name of the column. - * @return Returns the column index for the given column, or -1 if the column does not exist. - */ - virtual int GetColumnIndex(const std::string &columnName, int &columnIndex) = 0; - - /** - * @brief Obtains the column name at the given column index. - * - * @param columnIndex Indicates the zero-based index. - * @return Returns the column name for the given index. - */ - virtual int GetColumnName(int columnIndex, std::string &columnName) = 0; - - /** - * @brief Obtains the numbers of rows in the result set. - */ - virtual int GetRowCount(int &count) = 0; - - /** - * @brief Obtains the current position of the cursor in the result set. - * - * The value is zero-based. When the result set is first returned the cursor - * will be at position -1, which is before the first row. - * After the last row is returned another call to next() will leave the cursor past - * the last entry, at a position of count(). - * - * @return Returns the current cursor position. - */ - virtual int GetRowIndex(int &position) const = 0; - - /** - * @brief Move the cursor a relative amount from current position. Positive offset move forward, - * negative offset move backward. - * - * @param offset Indicates the offset to be applied from the current position. - * @return Returns whether the requested move succeeded. - */ - virtual int GoTo(int offset) = 0; - - /** - * @brief Move the cursor to an absolute position. - * - * @param position Indicates the zero-based position to move to. - * @return Returns whether the requested move succeeded. - */ - virtual int GoToRow(int position) = 0; - - /** - * @brief Move the cursor to the first row. - * - * @return Returns whether the requested move succeeded. - */ - virtual int GoToFirstRow() = 0; - - /** - * @brief Move the cursor to the last row. - * - * @return Returns whether the requested move succeeded. - */ - virtual int GoToLastRow() = 0; - - /** - * @brief Move the cursor to the next row. - * - * @return Returns whether the requested move succeeded. - */ - virtual int GoToNextRow() = 0; - - /** - * @brief Move the cursor to the previous row. - * - * @return Returns whether the requested move succeeded. - */ - virtual int GoToPreviousRow() = 0; - - /** - * @brief Obtains whether the cursor is pointing to the position after the last row. - * - * @return Returns whether the cursor is after the last row. - */ - virtual int IsEnded(bool &result) = 0; - - /** - * @brief Obtains whether the cursor is pointing to the position before the first row. - * - * @return Returns whether the cursor is before the first row. - */ - virtual int IsStarted(bool &result) const = 0; - - /** - * @brief Obtains whether the cursor is pointing to the first row. - * - * @return Returns whether the cursor is pointing at the first entry. - */ - virtual int IsAtFirstRow(bool &result) const = 0; - - /** - * @brief Obtains whether the cursor is pointing to the last row. - * - * @return Returns whether the cursor is pointing at the last entry. - */ - virtual int IsAtLastRow(bool &result) = 0; - - /** - * @brief Obtains the value of the requested column as a byte array. - * - * @param columnIndex Indicates the zero-based index of the target column. - * @return Returns the value of the requested column as a byte array. - */ - virtual int GetBlob(int columnIndex, std::vector &blob) = 0; - - /** - * @brief Obtains the value of the requested column as a String. - * - * @param columnIndex Indicates the zero-based index of the target column. - * @return Returns the value of the requested column as a String. - */ - virtual int GetString(int columnIndex, std::string &value) = 0; - - /** - * @brief Obtains the value of the requested column as a int. - * - * @param columnIndex Indicates the zero-based index of the target column. - * @return Returns the value of the requested column as a int. - */ - virtual int GetInt(int columnIndex, int &value) = 0; - - /** - * @brief Obtains the value of the requested column as a long. - * - * @param columnIndex Indicates the zero-based index of the target column. - * @return Returns the value of the requested column as a long. - */ - virtual int GetLong(int columnIndex, int64_t &value) = 0; - - /** - * @brief Obtains the value of the requested column as a double. - * - * @param columnIndex Indicates the zero-based index of the target column. - * @return Returns the value of the requested column as a double. - */ - virtual int GetDouble(int columnIndex, double &value) = 0; - - /** - * @brief Obtains Whether the value of the requested column is null. - * - * @param columnIndex Indicates the zero-based index of the target column. - * @return Returns whether the column value is null. - */ - virtual int IsColumnNull(int columnIndex, bool &isNull) = 0; - - /** - * @brief Obtains Return true if the result set is closed. - * - * @return Returns true if the result set is closed. - */ - virtual bool IsClosed() const = 0; - - /** - * @brief Closes the result set, releasing all of its resources and making it completely invalid. + * @brief Gets the entire row of data for the current row from the result set. */ - virtual int Close() = 0; + virtual int GetRow(RowEntity &rowEntity) = 0; + virtual int GetModifyTime(std::string &modifyTime) = 0; }; } // namespace NativeRdb diff --git a/relational_store/interfaces/inner_api/rdb/include/value_object.h b/relational_store/interfaces/inner_api/rdb/include/value_object.h index e1ce57f4e96fec090617cc50461db20344fc692e..d9bf97db6a8bfe6ddbba10e47807d177e55feb79 100644 --- a/relational_store/interfaces/inner_api/rdb/include/value_object.h +++ b/relational_store/interfaces/inner_api/rdb/include/value_object.h @@ -19,40 +19,80 @@ #include #include #include -#include -#include "rdb_visibility.h" +#include "asset_value.h" +#include "rdb_visibility.h" namespace OHOS { namespace NativeRdb { -/** - * @brief Indicates the ValueObject {@link ValueObject} type. - */ -enum class ValueObjectType { - /** Indicates the ValueObject type is NULL.*/ - TYPE_NULL = 0, - /** Indicates the ValueObject type is int.*/ - TYPE_INT, - /** Indicates the ValueObject type is double.*/ - TYPE_DOUBLE, - /** Indicates the ValueObject type is string.*/ - TYPE_STRING, - /** Indicates the ValueObject type is bool.*/ - TYPE_BOOL, - /** Indicates the ValueObject type is blob.*/ - TYPE_BLOB, -}; - /** * The ValueObject class of RDB. */ -class ValueObject { +class RDB_API_EXPORT ValueObject { public: /** * @brief Use Type replace std::variant. */ - using Type = std::variant>; + using Nil = std::monostate; + using Blob = std::vector; + using Asset = AssetValue; + using Assets = std::vector; + using Type = std::variant; + + template + struct variant_size_of { + static constexpr size_t value = sizeof...(Types); + }; + + template + struct variant_index_of { + static constexpr size_t value = std::__detail::__variant::__index_of_v; + }; + + template + static variant_size_of variant_size_test(const std::variant &); + + template + static variant_index_of variant_index_test(const T &, const std::variant &); + + template + inline constexpr static int32_t TYPE_INDEX = + decltype(variant_index_test(std::declval(), std::declval()))::value; + + inline constexpr static int32_t TYPE_MAX = decltype(variant_size_test(std::declval()))::value; + + /** + * @brief Indicates the ValueObject {@link ValueObject} type. + * */ + enum TypeId : int32_t { + /** Indicates the ValueObject type is NULL.*/ + TYPE_NULL = TYPE_INDEX, + /** Indicates the ValueObject type is int.*/ + TYPE_INT = TYPE_INDEX, + /** Indicates the ValueObject type is double.*/ + TYPE_DOUBLE = TYPE_INDEX, + /** Indicates the ValueObject type is string.*/ + TYPE_STRING = TYPE_INDEX, + /** Indicates the ValueObject type is bool.*/ + TYPE_BOOL = TYPE_INDEX, + /** Indicates the ValueObject type is blob.*/ + TYPE_BLOB = TYPE_INDEX, + /** Indicates the ValueObject type is asset.*/ + TYPE_ASSET = TYPE_INDEX, + /** Indicates the ValueObject type is assets.*/ + TYPE_ASSETS = TYPE_INDEX, + /** the BUTT.*/ + TYPE_BUTT = TYPE_MAX + }; Type value; + /** + * @brief convert a std::variant input to another std::variant output with different (..._Types) + */ + template + static inline std::enable_if_t< (TYPE_INDEX) < TYPE_MAX, const char *> DeclType() + { + return DECLARE_TYPES[TYPE_INDEX]; + } /** * @brief Constructor. */ @@ -68,17 +108,17 @@ public: * * A parameterized constructor used to create a ValueObject instance. */ - RDB_API_EXPORT ValueObject(Type valueObject) noexcept; + RDB_API_EXPORT ValueObject(Type val) noexcept; /** * @brief Move constructor. */ - RDB_API_EXPORT ValueObject(ValueObject &&valueObject) noexcept; + RDB_API_EXPORT ValueObject(ValueObject &&val) noexcept; /** * @brief Copy constructor. */ - RDB_API_EXPORT ValueObject(const ValueObject &valueObject); + RDB_API_EXPORT ValueObject(const ValueObject &val); /** * @brief Constructor. @@ -87,7 +127,7 @@ public: * * @param val Indicates an int input parameter. */ - RDB_API_EXPORT explicit ValueObject(int val); + RDB_API_EXPORT ValueObject(int32_t val); /** * @brief Constructor. @@ -96,7 +136,7 @@ public: * * @param val Indicates an int64_t input parameter. */ - RDB_API_EXPORT explicit ValueObject(int64_t val); + RDB_API_EXPORT ValueObject(int64_t val); /** * @brief Constructor. @@ -105,7 +145,7 @@ public: * * @param val Indicates an double input parameter. */ - RDB_API_EXPORT explicit ValueObject(double val); + RDB_API_EXPORT ValueObject(double val); /** * @brief Constructor. @@ -114,7 +154,7 @@ public: * * @param val Indicates an bool input parameter. */ - RDB_API_EXPORT explicit ValueObject(bool val); + RDB_API_EXPORT ValueObject(bool val); /** * @brief Constructor. @@ -123,7 +163,9 @@ public: * * @param val Indicates an string input parameter. */ - RDB_API_EXPORT explicit ValueObject(const std::string &val); + RDB_API_EXPORT ValueObject(const std::string &val); + + RDB_API_EXPORT ValueObject(const char *val); /** * @brief Constructor. @@ -132,7 +174,11 @@ public: * * @param val Indicates an vector input parameter. */ - RDB_API_EXPORT explicit ValueObject(const std::vector &blob); + RDB_API_EXPORT ValueObject(const std::vector &blob); + + RDB_API_EXPORT ValueObject(Asset val); + + RDB_API_EXPORT ValueObject(Assets val); /** * @brief Move assignment operator overloaded function. @@ -147,7 +193,7 @@ public: /** * @brief Obtains the type in this {@code ValueObject} object. */ - RDB_API_EXPORT ValueObjectType GetType() const; + RDB_API_EXPORT TypeId GetType() const; /** * @brief Obtains the int value in this {@code ValueObject} object. @@ -179,12 +225,22 @@ public: */ RDB_API_EXPORT int GetBlob(std::vector &val) const; + /** + * @brief Obtains the vector value in this {@code ValueObject} object. + */ + RDB_API_EXPORT int GetAsset(Asset &val) const; + + /** + * @brief Obtains the vector value in this {@code ValueObject} object. + */ + RDB_API_EXPORT int GetAssets(Assets &val) const; + /** * @brief Type conversion function. * * @return Returns the int type ValueObject. */ - operator int () const + operator int() const { return static_cast(std::get(value)); } @@ -194,7 +250,7 @@ public: * * @return Returns the int64_t type ValueObject. */ - operator int64_t () const + operator int64_t() const { return std::get(value); } @@ -204,7 +260,7 @@ public: * * @return Returns the double type ValueObject. */ - operator double () const + operator double() const { return std::get(value); } @@ -214,7 +270,7 @@ public: * * @return Returns the bool type ValueObject. */ - operator bool () const + operator bool() const { return std::get(value); } @@ -224,7 +280,7 @@ public: * * @return Returns the string type ValueObject. */ - operator std::string () const + operator std::string() const { return std::get(value); } @@ -234,9 +290,29 @@ public: * * @return Returns the vector type ValueObject. */ - operator std::vector () const + operator Blob() const { - return std::get>(value); + return std::get(value); + } + + /** + * @brief Type conversion function. + * + * @return Returns the vector type ValueObject. + */ + operator Asset() const + { + return std::get(value); + } + + /** + * @brief Type conversion function. + * + * @return Returns the vector type ValueObject. + */ + operator Assets() const + { + return std::get(value); } /** @@ -252,8 +328,26 @@ public: private: template int Get(T &output) const; + static constexpr const char *DECLARE_TYPES[TypeId::TYPE_BUTT] = { + /** Indicates the ValueObject type is NULL.*/ + "", + /** Indicates the ValueObject type is int.*/ + "INT", + /** Indicates the ValueObject type is double.*/ + "REAL", + /** Indicates the ValueObject type is string.*/ + "TEXT", + /** Indicates the ValueObject type is bool.*/ + "INT", + /** Indicates the ValueObject type is blob.*/ + "BLOB", + /** Indicates the ValueObject type is asset.*/ + "ASSET", + /** Indicates the ValueObject type is assets.*/ + "ASSETS" + }; }; - +using ValueObjectType = ValueObject::TypeId; } // namespace NativeRdb } // namespace OHOS #endif diff --git a/relational_store/interfaces/inner_api/rdb/include/values_bucket.h b/relational_store/interfaces/inner_api/rdb/include/values_bucket.h index 9d25d0def780474338b0d43a5c61203d6d0c0e92..c064fa095bc12ef38e02cda022037bd8ce3ec7c3 100644 --- a/relational_store/interfaces/inner_api/rdb/include/values_bucket.h +++ b/relational_store/interfaces/inner_api/rdb/include/values_bucket.h @@ -25,7 +25,7 @@ namespace NativeRdb { /** * The ValuesBucket class of RDB. */ -class ValuesBucket { +class RDB_API_EXPORT ValuesBucket { public: /** * @brief Constructor. @@ -37,7 +37,7 @@ public: * * A parameterized constructor used to create a ValuesBucket instance. */ - RDB_API_EXPORT explicit ValuesBucket(std::map &valuesMap); + RDB_API_EXPORT explicit ValuesBucket(std::map values); /** * @brief Destructor. @@ -99,6 +99,14 @@ public: */ RDB_API_EXPORT void PutNull(const std::string &columnName); + /** + * @brief Put the integer double bool string bytes asset asset and so on + * to this {@code ValuesBucket} object for the given column name. + * + * @param columnName Indicates the name of the column. + */ + RDB_API_EXPORT void Put(const std::string &columnName, ValueObject value); + /** * @brief Delete the ValueObject object for the given column name. * @@ -138,9 +146,9 @@ public: /** * @brief Obtains the ValuesBucket object's valuesmap. */ - RDB_API_EXPORT void GetAll(std::map &valuesMap) const; - - std::map valuesMap; + RDB_API_EXPORT std::map GetAll() const; + + std::map values_; }; } // namespace NativeRdb diff --git a/relational_store/interfaces/inner_api/rdb/mock/include/abs_result_set.h b/relational_store/interfaces/inner_api/rdb/mock/include/abs_result_set.h new file mode 100644 index 0000000000000000000000000000000000000000..5bb0b3e2cbdb0ee67ca8e0959b65110f7091c805 --- /dev/null +++ b/relational_store/interfaces/inner_api/rdb/mock/include/abs_result_set.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 NATIVE_RDB_ABS_RESULT_SET_H +#define NATIVE_RDB_ABS_RESULT_SET_H + +#include +#include +#include +#include + +#include "result_set.h" +#include "value_object.h" + +namespace OHOS { +namespace NativeRdb { +class AbsResultSet : public ResultSet { +public: + AbsResultSet(); + virtual ~AbsResultSet(); + int GetRowCount(int &count) override; + int GetAllColumnNames(std::vector &columnNames) override; + int GetBlob(int columnIndex, std::vector &blob) override; + int GetString(int columnIndex, std::string &value) override; + int GetInt(int columnIndex, int &value) override; + int GetLong(int columnIndex, int64_t &value) override; + int GetDouble(int columnIndex, double &value) override; + int IsColumnNull(int columnIndex, bool &isNull) override; + int GetRow(RowEntity &rowEntity) override; + int GoToRow(int position) override; + int GetColumnType(int columnIndex, ColumnType &columnType) override; + int GetRowIndex(int &position) const override; + int GoTo(int offset) override; + int GoToFirstRow() override; + int GoToLastRow() override; + int GoToNextRow() override; + int GoToPreviousRow() override; + int IsAtFirstRow(bool &result) const override; + int IsAtLastRow(bool &result) override; + int IsStarted(bool &result) const override; + int IsEnded(bool &result) override; + int GetColumnCount(int &count) override; + int GetColumnIndex(const std::string &columnName, int &columnIndex) override; + int GetColumnName(int columnIndex, std::string &columnName) override; + bool IsClosed() const override; + int Close() override; + +protected: + std::map columnMap_; + int columnCount_ = -1; + // The default position of the result set + static const int INIT_POS = -1; + /* + * The value can be in the range [-1 ~ n], where -1 represents the start flag position and N represents the data end + * flag position, and [0, n-1] represents the real data index. + */ + int rowPos_; + + // Indicates whether the result set is closed + bool isClosed; +}; +} // namespace NativeRdb +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h index aa3c7d56a08c15ceb6e66bdb601728b3e49c2c1f..64a3f5664255a2d1eb0e61768a6d79a6b128e772 100644 --- a/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h +++ b/relational_store/interfaces/inner_api/rdb/mock/include/rdb_store_config.h @@ -132,7 +132,6 @@ private: StorageMode storageMode; std::string journalMode; std::string syncMode; - std::vector encryptKey; bool readOnly; std::string databaseFileType; @@ -141,6 +140,7 @@ private: std::string moduleName_; bool isEncrypt_ = false; + std::vector encryptKey_; SecurityLevel securityLevel = SecurityLevel::LAST; std::string uri_; std::string readPermission_; diff --git a/relational_store/interfaces/inner_api/rdb/mock/include/result_set.h b/relational_store/interfaces/inner_api/rdb/mock/include/result_set.h new file mode 100644 index 0000000000000000000000000000000000000000..824bab2d35508d03107a321c34b469febc7ff925 --- /dev/null +++ b/relational_store/interfaces/inner_api/rdb/mock/include/result_set.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 NATIVE_RDB_RESULT_SET_H +#define NATIVE_RDB_RESULT_SET_H + +#include +#include +#include +#include "remote_result_set.h" +#include "value_object.h" + +namespace OHOS { +namespace NativeRdb { +struct RowEntity { +public: + void Put(const std::string &name, const ValueObject &value); + ValueObject Get(const std::string &name) const; + ValueObject Get(const int index) const; + void Get(std::map &outValues) const; + void Clear(); +private: + std::map values_; + std::vector indexs_; +}; + +class ResultSet : public RemoteResultSet { +public: + virtual ~ResultSet() {} + virtual int GetRow(RowEntity &rowEntity) = 0; +}; + +} // namespace NativeRdb +} // namespace OHOS +#endif diff --git a/relational_store/interfaces/inner_api/rdb/mock/include/value_object.h b/relational_store/interfaces/inner_api/rdb/mock/include/value_object.h index 099f81b99567413a8f2bcbdf7538387872f64099..1733b2fe4d9aeb4b19393eb2708dcf103fc486c6 100644 --- a/relational_store/interfaces/inner_api/rdb/mock/include/value_object.h +++ b/relational_store/interfaces/inner_api/rdb/mock/include/value_object.h @@ -38,12 +38,13 @@ public: ValueObject(Type valueObject) noexcept; ValueObject(ValueObject &&valueObject) noexcept; ValueObject(const ValueObject &valueObject); - explicit ValueObject(int val); - explicit ValueObject(int64_t val); - explicit ValueObject(double val); - explicit ValueObject(bool val); - explicit ValueObject(const std::string &val); - explicit ValueObject(const std::vector &blob); + ValueObject(int val); + ValueObject(int64_t val); + ValueObject(double val); + ValueObject(bool val); + ValueObject(const std::string &val); + ValueObject(const char *val); + ValueObject(const std::vector &blob); ValueObject &operator=(ValueObject &&valueObject) noexcept; ValueObject &operator=(const ValueObject &valueObject); diff --git a/relational_store/interfaces/inner_api/rdb_data_ability_adapter/include/rdb_data_ability_utils.h b/relational_store/interfaces/inner_api/rdb_data_ability_adapter/include/rdb_data_ability_utils.h index 2987783f7c813a56bc9b5fd5d4920e1f24ac7ed4..5aef2bd62d6d45872c77bc79da4f3eb8f0694910 100644 --- a/relational_store/interfaces/inner_api/rdb_data_ability_adapter/include/rdb_data_ability_utils.h +++ b/relational_store/interfaces/inner_api/rdb_data_ability_adapter/include/rdb_data_ability_utils.h @@ -73,7 +73,7 @@ public: /** * @brief Convert NativeRdb::ValuesBucket to DataShare::DataShareValuesBucket. */ - RDB_API_EXPORT static DataShareValuesBucket ToDataShareValuesBucket(const ValuesBucket &valuesBucket); + RDB_API_EXPORT static DataShareValuesBucket ToDataShareValuesBucket(ValuesBucket valuesBucket); /** * @brief Convert NativeRdb::DataAbilityPredicates to DataShare::DataSharePredicates. diff --git a/relational_store/interfaces/inner_api/rdb_data_share_adapter/include/rdb_utils.h b/relational_store/interfaces/inner_api/rdb_data_share_adapter/include/rdb_utils.h index 04a1ed11d5d9caaaea8c53620cd1c74a39f17993..f5ecd9a921281ac1a7a7eb3841b21696eb5d86f4 100644 --- a/relational_store/interfaces/inner_api/rdb_data_share_adapter/include/rdb_utils.h +++ b/relational_store/interfaces/inner_api/rdb_data_share_adapter/include/rdb_utils.h @@ -81,7 +81,7 @@ public: /** * @brief Convert DataShare::DataShareValuesBucket to NativeRdb::ValuesBucket. */ - RDB_API_EXPORT static ValuesBucket ToValuesBucket(const DataShareValuesBucket &bucket); + RDB_API_EXPORT static ValuesBucket ToValuesBucket(DataShareValuesBucket bucket); /** * @brief Convert DataShare::DataShareAbsPredicates to NativeRdb::RdbPredicates. diff --git a/relational_store/relational_store.gni b/relational_store/relational_store.gni index b886073ae0cb218b0cdf0629bb8fc5663dd8a9ac..442ce6d8aa61e3b9a5d9188144ea65757d2cc201 100644 --- a/relational_store/relational_store.gni +++ b/relational_store/relational_store.gni @@ -26,3 +26,5 @@ relational_store_native_path = "${relational_store_base_path}/frameworks/native" relational_store_innerapi_path = "${relational_store_base_path}/interfaces/inner_api" + +cloud_data_native_path = "${relational_store_base_path}/frameworks/native/cloud_data" \ No newline at end of file diff --git a/relational_store/test/js/dataability/unittest/src/DataAbilityPredicatesJsunit.test.js b/relational_store/test/js/dataability/unittest/src/DataAbilityPredicatesJsunit.test.js index 9b99b973f2c9dc929f93e5742f33f95239dabba5..03ab110ce728e20863dc947aac54b9e02c5a6377 100644 --- a/relational_store/test/js/dataability/unittest/src/DataAbilityPredicatesJsunit.test.js +++ b/relational_store/test/js/dataability/unittest/src/DataAbilityPredicatesJsunit.test.js @@ -1916,25 +1916,6 @@ describe('dataAbilityPredicatesTest', function () { console.log(TAG + "************* testDataAbilityAnd0003 end *************"); }) - /** - * @tc.name predicates and normal test - * @tc.number SUB_DDM_AppDataFWK_JSRDB_DataAbilityPredicates_0153 - * @tc.desc predicates and normal test - */ - it('testDataAbilityAnd0004', 0, async function (done) { - console.log(TAG + "************* testDataAbilityAnd0004 start *************"); - { - let dataAbilityPredicates = await new dataAbility.DataAbilityPredicates(); - dataAbilityPredicates.equalTo("stringValue", "ABCDEFGHIJKLMN").or().or().equalTo("integerValue", 1); - let predicates = dataAbility.createRdbPredicates("AllDataType", dataAbilityPredicates); - - console.log(TAG + "you are starting a sql request with predicate or or," - + "using function or() immediately after another or(). that is ridiculous."); - } - done(); - console.log(TAG + "************* testDataAbilityAnd0004 end *************"); - }) - /** * @tc.name predicates order normal test * @tc.number SUB_DDM_AppDataFWK_JSRDB_DataAbilityPredicates_0160 diff --git a/relational_store/test/js/rdb/BUILD.gn b/relational_store/test/js/rdb/BUILD.gn index 0d59022302a62e7687bc0af0ef0d2e8f677c02e9..a3b5ca97e1191c26838a311c263eca579d4bdea1 100644 --- a/relational_store/test/js/rdb/BUILD.gn +++ b/relational_store/test/js/rdb/BUILD.gn @@ -20,4 +20,11 @@ group("unittest") { deps += [ "unittest/src:unittest" ] } + +group("performancetest") { + testonly = true + deps = [] + + deps += [ "performance/src:RdbPerfJsTest" ] +} ############################################################################### diff --git a/relational_store/test/js/rdb/performance/config.json b/relational_store/test/js/rdb/performance/config.json new file mode 100644 index 0000000000000000000000000000000000000000..e1b1bc28e5922882acd683bf6b3b0a439786fbcb --- /dev/null +++ b/relational_store/test/js/rdb/performance/config.json @@ -0,0 +1,62 @@ +{ + "app": { + "bundleName": "com.example.myapplication", + "vendor": "example", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 4, + "target": 5 + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.myapplication", + "name": ".MyApplication", + "deviceType": [ + "tablet", + "default", + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry" + }, + "abilities": [ + { + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "name": "com.example.myapplication.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "MyApplication", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "pages": [ + "pages/index/index" + ], + "name": "default", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} diff --git a/relational_store/test/js/rdb/performance/openharmony_sx.p7b b/relational_store/test/js/rdb/performance/openharmony_sx.p7b new file mode 100644 index 0000000000000000000000000000000000000000..9be1e98fa4c0c28ca997ed660112fa16b194f0f5 Binary files /dev/null and b/relational_store/test/js/rdb/performance/openharmony_sx.p7b differ diff --git a/relational_store/test/js/rdb/performance/src/BUILD.gn b/relational_store/test/js/rdb/performance/src/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e7b7cdd254742bd5338519b094992fc6c355f6f2 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (C) 2023 Huawei Device Co., Ltd. +# 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. + +import("//build/test.gni") + +module_output_path = "relational_store/performance" + +ohos_js_unittest("RdbPerfJsTest") { + module_out_path = module_output_path + + hap_profile = "../config.json" + + certificate_profile = "../openharmony_sx.p7b" +} diff --git a/relational_store/test/js/rdb/performance/src/PredicatestPerf.js b/relational_store/test/js/rdb/performance/src/PredicatestPerf.js new file mode 100644 index 0000000000000000000000000000000000000000..30057c9904b0ec791e650f158dff0746b1df1f60 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/PredicatestPerf.js @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDB_PREDICATES_PERF]"; + +const BASE_COUNT = 2000; // loop times +const BASE_COUNT_FIRST = 200; +const BASE_COUNT_SECOND = 10; +const BASE_LINE_TABLE = 500; // callback tablet base line +const BASE_LINE_PHONE = 1000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('predicatesPerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_Predicates_inDevices_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.inDevices(['123']); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_inDevices average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_inAllDevices_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.inAllDevices(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_inAllDevices average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_equalTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_equalTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_notEqualTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.notEqualTo("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_notEqualTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_beginWrap_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.beginWrap(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_beginWrap average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_endWrap_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + predicates.endWrap(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_endWrap average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_or_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + predicates.or(); + predicates.equalTo("age", 18); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_or average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_and_001', 1, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + predicates.and(); + predicates.equalTo("name", "zs"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_and average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_contains_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.contains("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_contains average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_beginsWith_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.beginsWith("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_beginsWith average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_endWith_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.endsWith("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_endWith average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_isNull_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.isNull("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_isNull average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_isNotNull_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.isNotNull("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_isNotNull average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_like_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.like("name", "li"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_like average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_glob_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.glob("name", "li"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_glob average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_between_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.between("age", 1, 100); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_between average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_notBetween_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.notBetween("age", 1, 100); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_notBetween average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_greaterThan_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.greaterThan("age", 1); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_greaterThan average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_lessThan_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.lessThan("age", 1000); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_lessThan average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_greaterThanOrEqualTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.greaterThanOrEqualTo("age", 1000); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_greaterThanOrEqualTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_lessThanOrEqualTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.lessThanOrEqualTo("age", 1000); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_lessThanOrEqualTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_orderByAsc_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.orderByAsc("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_orderByAsc average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_orderByDesc_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.orderByDesc("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_orderByDesc average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_distinct_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.distinct(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_distinct average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_limitAs_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + predicates.limitAs(6); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_limitAs average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_offsetAs_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + predicates.offsetAs(6); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_offsetAs average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_groupBy_001', 0, async function (done) { + let nameArr = new Array(); + nameArr.push("id"); + nameArr.push("name"); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.groupBy(nameArr); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_groupBy average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_indexedBy_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.indexedBy("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_indexedBy average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_in_001', 0, async function (done) { + let nameArr = new Array(); + nameArr.push("id"); + nameArr.push("name"); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.in("name", nameArr); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_in average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_notIn(_001', 0, async function (done) { + let nameArr = new Array(); + nameArr.push("zhangsan"); + nameArr.push("lisi"); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.notIn("name", nameArr); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_notIn average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + console.info(TAG + "*************Unit Test End*************") +}) \ No newline at end of file diff --git a/relational_store/test/js/rdb/performance/src/RdbHelperCallbackPerf.js b/relational_store/test/js/rdb/performance/src/RdbHelperCallbackPerf.js new file mode 100644 index 0000000000000000000000000000000000000000..14d02c2acc812e52a02a4f6ea79148096ed5c447 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/RdbHelperCallbackPerf.js @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDBHELPER_CALLBACK]"; + +const DB_NAME = "rdbCallback.db"; +const STORE_CONFIG = { + name: DB_NAME, +} +let context = featureAbility.getContext(); +var rdbStore = undefined; +const BASE_COUNT = 2000; // loop times +const BASE_LINE_TABLE = 2500; // callback tablet base line +const BASE_LINE_PHONE = 3000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('rdbHelperCallbackPerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_getRdbStore_Callback_001', 0, async function (done) { + let averageTime = 0; + + async function getRdbStoreCallBackPerf(index) { + dataRdb.getRdbStore(context, STORE_CONFIG, 1, function (err, rdbStore) { + if (index < BASE_COUNT) { + getRdbStoreCallBackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the getRdbStore_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + } + }) + } + + let startTime = new Date().getTime(); + await getRdbStoreCallBackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_deleteRdbStore_Callback_001', 0, async function (done) { + let averageTime = 0; + + async function deleteRdbStoreCallBackPerf(index) { + dataRdb.deleteRdbStore(context, DB_NAME, function (err, data) { + if (index < BASE_COUNT) { + deleteRdbStoreCallBackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the deleteRdbStore_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + } + }) + } + + let startTime = new Date().getTime(); + await deleteRdbStoreCallBackPerf(0); + }) +}) \ No newline at end of file diff --git a/relational_store/test/js/rdb/performance/src/RdbHelperPromisePerf.js b/relational_store/test/js/rdb/performance/src/RdbHelperPromisePerf.js new file mode 100644 index 0000000000000000000000000000000000000000..330ffcd228d5341e45a11492f195bcaa50585933 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/RdbHelperPromisePerf.js @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDBHELPER_PROMISE]"; + +const DB_NAME = "rdbPromise.db"; +const STORE_CONFIG = { + name: DB_NAME, +} +let context = featureAbility.getContext(); +var rdbStore = undefined; +const BASE_COUNT = 2000; // loop times +const BASE_LINE_TABLE = 2500; // callback tablet base line +const BASE_LINE_PHONE = 3000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('rdbHelperPromisePerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_getRdbStore_Promise_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + await dataRdb.getRdbStore(context, STORE_CONFIG, 1); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the getRdbStore_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_deleteRdbStore_Promise_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + await dataRdb.deleteRdbStore(context, DB_NAME, 1); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the deleteRdbStore_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + console.info(TAG + "*************Unit Test End*************") + }) +}) \ No newline at end of file diff --git a/relational_store/test/js/rdb/performance/src/RdbStoreCallbackPerf.js b/relational_store/test/js/rdb/performance/src/RdbStoreCallbackPerf.js new file mode 100644 index 0000000000000000000000000000000000000000..52b39810f54d96507b831d210a18d45abcf77b80 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/RdbStoreCallbackPerf.js @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDBSTORE_CALLBACK]"; +const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + +const DB_NAME = "rdbStoreCallback.db"; +const STORE_CONFIG = { + name: DB_NAME, +} +let context = featureAbility.getContext(); +var rdbStore = undefined; +const BASE_COUNT = 1000; // loop times +const INSERT_BASE_COUNT = 300; +const BASE_LINE_TABLE = 1800; // callback tablet base line +const BASE_LINE_PHONE = 7000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('rdbStoreCallbackPerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + async function prepareTestData() { + console.info(TAG + "prepare for query performance test"); + var u8 = new Uint8Array([1, 2, 3]); + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await rdbStore.insert("test", valueBucket); + } + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_query_Callback_001', 0, async function (done) { + let averageTime = 0; + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 10); + + async function queryCallbackPerf(index) { + rdbStore.query(predicates, [], function (err, resultSet) { + resultSet.close(); + if (index < BASE_COUNT) { + queryCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the query_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "*************Unit Test End*************"); + done(); + } + }) + } + + let startTime = new Date().getTime(); + queryCallbackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_insert_Callback_001', 0, async function (done) { + let averageTime = 0; + var uBlob = new Uint8Array([1, 2, 3]); + var insertValueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": uBlob, + } + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 10); + + async function InsertCallbackPerf(index) { + rdbStore.insert("test", insertValueBucket, function (err, data) { + if (index < INSERT_BASE_COUNT) { + InsertCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / INSERT_BASE_COUNT; + console.info(TAG + " the insert_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + } + }) + } + + let startTime = new Date().getTime(); + InsertCallbackPerf(0); + }) +}) \ No newline at end of file diff --git a/relational_store/test/js/rdb/performance/src/RdbStoreOthersCallbackPerf.js b/relational_store/test/js/rdb/performance/src/RdbStoreOthersCallbackPerf.js new file mode 100644 index 0000000000000000000000000000000000000000..03ced63506a094061d2010d1d6e20439fc363a85 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/RdbStoreOthersCallbackPerf.js @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDBSTORE_OTHERS_CALLBACK]"; +const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + +const DB_NAME = "rdbUpdateCallback.db"; +const STORE_CONFIG = { + name: DB_NAME, +} +let context = featureAbility.getContext(); +var rdbStore = undefined; +const BASE_COUNT = 1000; // loop times +const SPECIAL_BASE_COUNT = 300; +const BASE_LINE_TABLE = 1800; // callback tablet base line +const BASE_LINE_PHONE = 15000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('rdbStoreOthersCallbackPerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + async function prepareTestData() { + console.info(TAG + "prepare for query performance test"); + var u8 = new Uint8Array([1, 2, 3]); + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await rdbStore.insert("test", valueBucket); + } + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_update_Callback_001', 0, async function (done) { + let averageTime = 0; + var uBlob = new Uint8Array([1, 2, 3]) + var updateVB = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": uBlob, + } + let predicates = new dataRdb.RdbPredicates("test"); + + async function updateCallbackPerf(index) { + predicates.equalTo("age", 18); + rdbStore.update(updateVB, predicates, function (err, data) { + if (index < SPECIAL_BASE_COUNT) { + updateCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; + console.info(TAG + " the update_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + } + }) + } + + let startTime = new Date().getTime(); + updateCallbackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_delete_Callback_001', 0, async function (done) { + let averageTime = 0; + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 0); + + async function deleteCallbackPerf(index) { + rdbStore.delete(predicates, function (err, data) { + if (index < BASE_COUNT) { + deleteCallbackPerf(index + 1) + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the delete_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + } + }) + } + + let startTime = new Date().getTime(); + deleteCallbackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_querySql_Callback_001', 0, async function (done) { + let averageTime = 0; + + async function querySqlCallbackPerf(index) { + rdbStore.querySql("select * from test", [], function (err, data) { + if (index < BASE_COUNT) { + querySqlCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the querySql_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + } + }) + } + + let startTime = new Date().getTime(); + querySqlCallbackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_executeSql_Callback_001', 0, async function (done) { + let averageTime = 0; + + async function executeSqlCallbackPerf(index) { + rdbStore.executeSql("insert into test (name, age) values ('tom', 22)", function (err, data) { + if (index < SPECIAL_BASE_COUNT) { + executeSqlCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; + console.info(TAG + " the executeSql_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + } + }) + } + + let startTime = new Date().getTime(); + executeSqlCallbackPerf(0); + }) +}) diff --git a/relational_store/test/js/rdb/performance/src/RdbStorePromisePerf.js b/relational_store/test/js/rdb/performance/src/RdbStorePromisePerf.js new file mode 100644 index 0000000000000000000000000000000000000000..0034a9a870db09cb7b241d67200afa58da2aa828 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/RdbStorePromisePerf.js @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDBSTORE_PROMISE]"; +const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + +const DB_NAME = "rdbStorePromise.db"; +const STORE_CONFIG = { + name: DB_NAME, +} +let context = featureAbility.getContext(); +var rdbStore = undefined; +const BASE_COUNT = 1000; // loop times +const BASE_LINE_TABLE = 1800; // callback tablet base line +const BASE_LINE_PHONE = 3000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('rdbStorePromisePerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + async function prepareTestData() { + console.info(TAG + "prepare for query performance test") + var u8 = new Uint8Array([1, 2, 3]) + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + await dataRdb.insert("test", valueBucket); + } + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_query_Promise_001', 0, async function (done) { + let averageTime = 0; + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 10); + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + let resultSet = await rdbStore.query(predicates, []); + resultSet.close(); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the query_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "*************Unit Test End*************"); + done(); + }) +}) diff --git a/relational_store/test/js/rdb/performance/src/RdbStoreSyncPerf.js b/relational_store/test/js/rdb/performance/src/RdbStoreSyncPerf.js new file mode 100644 index 0000000000000000000000000000000000000000..df364d0c0cdb4b9d14a4a50961550917e14c7d88 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/RdbStoreSyncPerf.js @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDB_SYNC_PROMISE]"; +const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + +const DB_NAME = "rdbSync.db"; +const STORE_CONFIG = { + name: DB_NAME, +} +let context = featureAbility.getContext(); +var rdbStore = undefined; +const BASE_COUNT = 1000; // loop times +const BASE_LINE_TABLE = 2500; // callback tablet base line +const BASE_LINE_PHONE = 3000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + + +describe('rdbStoreSyncPerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_version_001', 0, async function (done) { + let averageTime = 0; + let dbVersion = 1; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + dbVersion = rdbStore.version; + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the version average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_transaction_commit_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + rdbStore.beginTransaction(); + rdbStore.commit(); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the transaction_commit average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_transaction_rollback_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + rdbStore.beginTransaction(); + rdbStore.rollBack(); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the transaction_rollback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + console.info(TAG + "*************Unit Test End*************"); + }) +}) diff --git a/relational_store/test/js/rdb/performance/src/ResultSetPerf.js b/relational_store/test/js/rdb/performance/src/ResultSetPerf.js new file mode 100644 index 0000000000000000000000000000000000000000..797d16047dae3972c7219cace8c6399c1bf289f0 --- /dev/null +++ b/relational_store/test/js/rdb/performance/src/ResultSetPerf.js @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.rdb'; +import featureAbility from '@ohos.ability.featureAbility'; +import deviceInfo from '@ohos.deviceInfo'; + +const TAG = "[RDB_RESULTSET_PERF]"; +const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + +const DB_NAME = "resultSetPerf.db"; +const STORE_CONFIG = { + name: DB_NAME, +} +let context = featureAbility.getContext(); +var rdbStore = undefined; +const BASE_COUNT = 2000; // loop times +const SPECIAL_BASE_COUNT = 12000; +const BASE_LINE_TABLE = 500; // callback tablet base line +const BASE_LINE_PHONE = 1000; // callback phone base line +const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; + +describe('resultSetPerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + async function prepareTestData() { + console.info(TAG + "prepare for query performance test"); + var valueBuckets = []; + var u8 = new Uint8Array([1, 2, 3]) + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, + } + for (let i = 0; i < BASE_COUNT; i++) { + valueBucket.age += i; + valueBuckets.push(valueBucket); + } + await rdbStore.batchInsert("test", valueBuckets) + } + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_ResultSet_GetColumnIndex_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_LINE; i++) { + resultSet.getColumnIndex("id"); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetColumnIndex average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GetColumnName_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getColumnName(0); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetColumnName average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GoTo_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goTo(i % 2); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoTo average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GoToRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToRow(1); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GoToFirstRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToFirstRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToFirstRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GoToLastRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToLastRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToLastRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GoToNextRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToNextRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToNextRow average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GoToPreviousRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToLastRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToPreviousRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToPreviousRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GetBlob_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("blobType"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getBlob(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetBlob average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GetString_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("name"); + let flag = resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (var i = 0; i < SPECIAL_BASE_COUNT; i++) { + resultSet.getString(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; + console.info(TAG + " the ResultSet_GetString average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done() + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GetLong_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("age"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getLong(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetLong average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_GetDouble_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("salary"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getDouble(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetDouble average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_ResultSet_IsColumnNull_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("salary"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.isColumnNull(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_IsColumnNull average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + console.info(TAG + "*************Unit Test End*************"); +}) \ No newline at end of file diff --git a/relational_store/test/js/rdb/unittest/src/RdbstorePredicatesJsunit.test.js b/relational_store/test/js/rdb/unittest/src/RdbstorePredicatesJsunit.test.js index 602f8c12b08870a428440339759d70fd1e3817f6..0d22de23fb1740e65f869b502e3d487ff839d272 100644 --- a/relational_store/test/js/rdb/unittest/src/RdbstorePredicatesJsunit.test.js +++ b/relational_store/test/js/rdb/unittest/src/RdbstorePredicatesJsunit.test.js @@ -1798,23 +1798,6 @@ describe('rdbPredicatesTest', function () { console.log(TAG + "************* testAnd0003 end *************"); }) - /** - * @tc.name predicates and normal test - * @tc.number SUB_DDM_AppDataFWK_JSRDB_Predicates_0153 - * @tc.desc predicates and normal test - */ - it('testAnd0004', 0, async function (done) { - console.log(TAG + "************* testAnd0004 start *************"); - - let predicates = new dataRdb.RdbPredicates("AllDataType"); - predicates.equalTo("stringValue", "ABCDEFGHIJKLMN").or().or().equalTo("integerValue", 1); - console.log(TAG + "you are starting a sql request with predicate or or," - + "using function or() immediately after another or(). that is ridiculous."); - - done(); - console.log(TAG + "************* testAnd0004 end *************"); - }) - /** * @tc.name predicates order normal test * @tc.number SUB_DDM_AppDataFWK_JSRDB_Predicates_0160 diff --git a/relational_store/test/js/relationalstore/BUILD.gn b/relational_store/test/js/relationalstore/BUILD.gn index 0d59022302a62e7687bc0af0ef0d2e8f677c02e9..27abd8a16ba9e6c5cf8d4beec894cb73555eea4f 100644 --- a/relational_store/test/js/relationalstore/BUILD.gn +++ b/relational_store/test/js/relationalstore/BUILD.gn @@ -20,4 +20,11 @@ group("unittest") { deps += [ "unittest/src:unittest" ] } + +group("performancetest") { + testonly = true + deps = [] + + deps += [ "performance/src:RelationalStorePerfJsTest" ] +} ############################################################################### diff --git a/relational_store/test/js/relationalstore/performance/src/BUILD.gn b/relational_store/test/js/relationalstore/performance/src/BUILD.gn index d13758d24b7418eba934347960dcf8e207c2bd3b..d0814abe7c9eed8aa87ae4d6f14fb7aefa0345dc 100644 --- a/relational_store/test/js/relationalstore/performance/src/BUILD.gn +++ b/relational_store/test/js/relationalstore/performance/src/BUILD.gn @@ -13,9 +13,9 @@ import("//build/test.gni") -module_output_path = "relational_store/oh_perf" +module_output_path = "relational_store/performance" -ohos_js_unittest("OHRdbPerfJsTest") { +ohos_js_unittest("RelationalStorePerfJsTest") { module_out_path = module_output_path hap_profile = "../config.json" diff --git a/relational_store/test/js/relationalstore/performance/src/PredicatestPerf.js b/relational_store/test/js/relationalstore/performance/src/PredicatestPerf.js index 47c0f77b68b63019ddff476174c5ff37452ad1b5..da7fd55667909073b7898bb0c25dff127201fa25 100644 --- a/relational_store/test/js/relationalstore/performance/src/PredicatestPerf.js +++ b/relational_store/test/js/relationalstore/performance/src/PredicatestPerf.js @@ -13,21 +13,12 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; -import featureAbility from '@ohos.ability.featureAbility'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDB_PREDICATES_PERF]"; -const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; - -const DB_NAME = "predicatesPerf.db"; -const STORE_CONFIG = { - name: DB_NAME, -} -let context = featureAbility.getContext(); -var rdbStore = undefined; + const BASE_COUNT = 2000; // loop times const BASE_COUNT_FIRST = 200; const BASE_COUNT_SECOND = 10; @@ -36,480 +27,480 @@ const BASE_LINE_PHONE = 1000; // callback phone base line const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; describe('predicatesPerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - }) - - console.log(TAG + "*************Unit Test Begin*************"); - - it('SUB_DDM_PERF_RDB_Predicates_inDevices_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.inDevices(['123']); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_inDevices average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_inAllDevices_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.inAllDevices(); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_inAllDevices average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_equalTo_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.equalTo("name", "lisi"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_equalTo average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_notEqualTo_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.notEqualTo("name", "lisi"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_notEqualTo average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_beginWrap_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.beginWrap(); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_beginWrap average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_endWrap_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.equalTo("name", "lisi"); - predicates.endWrap(); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_endWrap average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_or_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.equalTo("name", "lisi"); - predicates.or(); - predicates.equalTo("age", 18); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_or average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_and_001', 1, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.equalTo("name", "lisi"); - predicates.and(); - predicates.equalTo("name", "zs"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_and average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_contains_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.contains("name", "lisi"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_contains average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_beginsWith_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.beginsWith("name", "lisi"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_beginsWith average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_endWith_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.endsWith("name", "lisi"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_endWith average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_isNull_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.isNull("name"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_isNull average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_isNotNull_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.isNotNull("name"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_isNotNull average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_like_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.like("name", "li"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_like average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_glob_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.glob("name", "li"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_glob average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_between_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.between("age", 1, 100); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_between average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_notBetween_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.notBetween("age", 1, 100); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_notBetween average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_greaterThan_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.greaterThan("age", 1); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_greaterThan average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_lessThan_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.lessThan("age", 1000); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_lessThan average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_greaterThanOrEqualTo_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.greaterThanOrEqualTo("age", 1000); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_greaterThanOrEqualTo average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_lessThanOrEqualTo_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.lessThanOrEqualTo("age", 1000); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_lessThanOrEqualTo average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_orderByAsc_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.orderByAsc("name"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_orderByAsc average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_orderByDesc_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.orderByDesc("name"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_orderByDesc average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_distinct_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.distinct(); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_distinct average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_limitAs_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - predicates.limitAs(6); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_limitAs average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_offsetAs_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - predicates.offsetAs(6); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_offsetAs average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_groupBy_001', 0, async function (done) { - let nameArr = new Array(); - nameArr.push("id"); - nameArr.push("name"); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.groupBy(nameArr); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_groupBy average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_indexedBy_001', 0, async function (done) { - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.indexedBy("name"); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_indexedBy average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_in_001', 0, async function (done) { - let nameArr = new Array(); - nameArr.push("id"); - nameArr.push("name"); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.in("name", nameArr); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_in average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - it('SUB_DDM_PERF_RDB_Predicates_notIn(_001', 0, async function (done) { - let nameArr = new Array(); - nameArr.push("zhangsan"); - nameArr.push("lisi"); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT_FIRST; i++) { - let predicates = new dataRdb.RdbPredicates("test"); - for (let j = 0; j < BASE_COUNT_SECOND; j++) { - predicates.notIn("name", nameArr); - } - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the Predicates_notIn average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) - - console.info(TAG + "*************Unit Test End*************") + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_Predicates_inDevices_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.inDevices(['123']); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_inDevices average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_inAllDevices_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.inAllDevices(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_inAllDevices average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_equalTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_equalTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_notEqualTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.notEqualTo("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_notEqualTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_beginWrap_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.beginWrap(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_beginWrap average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_endWrap_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + predicates.endWrap(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_endWrap average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_or_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + predicates.or(); + predicates.equalTo("age", 18); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_or average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_and_001', 1, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.equalTo("name", "lisi"); + predicates.and(); + predicates.equalTo("name", "zs"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_and average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_contains_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.contains("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_contains average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_beginsWith_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.beginsWith("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_beginsWith average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_endWith_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.endsWith("name", "lisi"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_endWith average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_isNull_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.isNull("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_isNull average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_isNotNull_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.isNotNull("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_isNotNull average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_like_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.like("name", "li"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_like average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_glob_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.glob("name", "li"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_glob average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_between_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.between("age", 1, 100); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_between average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_notBetween_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.notBetween("age", 1, 100); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_notBetween average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_greaterThan_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.greaterThan("age", 1); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_greaterThan average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_lessThan_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.lessThan("age", 1000); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_lessThan average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_greaterThanOrEqualTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.greaterThanOrEqualTo("age", 1000); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_greaterThanOrEqualTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_lessThanOrEqualTo_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.lessThanOrEqualTo("age", 1000); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_lessThanOrEqualTo average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_orderByAsc_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.orderByAsc("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_orderByAsc average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_orderByDesc_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.orderByDesc("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_orderByDesc average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_distinct_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.distinct(); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_distinct average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_limitAs_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + predicates.limitAs(6); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_limitAs average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_offsetAs_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + predicates.offsetAs(6); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_offsetAs average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_groupBy_001', 0, async function (done) { + let nameArr = new Array(); + nameArr.push("id"); + nameArr.push("name"); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.groupBy(nameArr); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_groupBy average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_indexedBy_001', 0, async function (done) { + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.indexedBy("name"); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_indexedBy average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_in_001', 0, async function (done) { + let nameArr = new Array(); + nameArr.push("id"); + nameArr.push("name"); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.in("name", nameArr); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_in average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + it('SUB_DDM_PERF_RDB_Predicates_notIn(_001', 0, async function (done) { + let nameArr = new Array(); + nameArr.push("zhangsan"); + nameArr.push("lisi"); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT_FIRST; i++) { + let predicates = new dataRdb.RdbPredicates("test"); + for (let j = 0; j < BASE_COUNT_SECOND; j++) { + predicates.notIn("name", nameArr); + } + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the Predicates_notIn average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) + + console.info(TAG + "*************Unit Test End*************") }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/performance/src/RdbHelperCallbackPerf.js b/relational_store/test/js/relationalstore/performance/src/RdbHelperCallbackPerf.js index ffb0ce800aab9528d8b8251f71562c3a7adffe22..7781c9dddb136adffddac2251d5f6e3d2f8596da 100644 --- a/relational_store/test/js/relationalstore/performance/src/RdbHelperCallbackPerf.js +++ b/relational_store/test/js/relationalstore/performance/src/RdbHelperCallbackPerf.js @@ -13,18 +13,16 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDBHELPER_CALLBACK]"; -const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; - const DB_NAME = "rdbCallback.db"; const STORE_CONFIG = { - name: DB_NAME, + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S1 } let context = featureAbility.getContext(); var rdbStore = undefined; @@ -34,62 +32,62 @@ const BASE_LINE_PHONE = 3000; // callback phone base line const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; describe('rdbHelperCallbackPerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - rdbStore = null - await dataRdb.deleteRdbStore(context, DB_NAME); - }) + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null + await dataRdb.deleteRdbStore(context, DB_NAME); + }) - console.log(TAG + "*************Unit Test Begin*************"); + console.log(TAG + "*************Unit Test Begin*************"); - it('SUB_DDM_PERF_RDB_getRdbStore_Callback_001', 0, async function (done) { - let averageTime = 0; + it('SUB_DDM_PERF_RDB_getRdbStore_Callback_001', 0, async function (done) { + let averageTime = 0; - async function getRdbStoreCallBackPerf(index) { - dataRdb.getRdbStore(context, STORE_CONFIG, 1, function (err, rdbStore) { - if (index < BASE_COUNT) { - getRdbStoreCallBackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the getRdbStore_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) + async function getRdbStoreCallBackPerf(index) { + dataRdb.getRdbStore(context, STORE_CONFIG, function (err, rdbStore) { + if (index < BASE_COUNT) { + getRdbStoreCallBackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the getRdbStore_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); } + }) + } - let startTime = new Date().getTime(); - await getRdbStoreCallBackPerf(0); - }) + let startTime = new Date().getTime(); + await getRdbStoreCallBackPerf(0); + }) - it('SUB_DDM_PERF_RDB_deleteRdbStore_Callback_001', 0, async function (done) { - let averageTime = 0; + it('SUB_DDM_PERF_RDB_deleteRdbStore_Callback_001', 0, async function (done) { + let averageTime = 0; - async function deleteRdbStoreCallBackPerf(index) { - dataRdb.deleteRdbStore(context, DB_NAME, function (err, data) { - if (index < BASE_COUNT) { - deleteRdbStoreCallBackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the deleteRdbStore_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) + async function deleteRdbStoreCallBackPerf(index) { + dataRdb.deleteRdbStore(context, DB_NAME, function (err, data) { + if (index < BASE_COUNT) { + deleteRdbStoreCallBackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the deleteRdbStore_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); } + }) + } - let startTime = new Date().getTime(); - await deleteRdbStoreCallBackPerf(0); - }) + let startTime = new Date().getTime(); + await deleteRdbStoreCallBackPerf(0); + }) }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/performance/src/RdbHelperPromisePerf.js b/relational_store/test/js/relationalstore/performance/src/RdbHelperPromisePerf.js index fad1e09ee2b72ecf6158bf965b2ac00bd746fd01..d507666d560a2435f055f3101c262d43c6484fbe 100644 --- a/relational_store/test/js/relationalstore/performance/src/RdbHelperPromisePerf.js +++ b/relational_store/test/js/relationalstore/performance/src/RdbHelperPromisePerf.js @@ -13,18 +13,16 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDBHELPER_PROMISE]"; -const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; - const DB_NAME = "rdbPromise.db"; const STORE_CONFIG = { - name: DB_NAME, + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S1 } let context = featureAbility.getContext(); var rdbStore = undefined; @@ -34,47 +32,47 @@ const BASE_LINE_PHONE = 3000; // callback phone base line const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; describe('rdbHelperPromisePerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - rdbStore = null; - await dataRdb.deleteRdbStore(context, DB_NAME); - }) + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) - console.log(TAG + "*************Unit Test Begin*************"); + console.log(TAG + "*************Unit Test Begin*************"); - it('SUB_DDM_PERF_RDB_getRdbStore_Promise_001', 0, async function (done) { - let averageTime = 0; - let startTime = new Date().getTime(); - for (var i = 0; i < BASE_COUNT; i++) { - await dataRdb.getRdbStore(context, STORE_CONFIG, 1); - } - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the getRdbStore_Promise average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_getRdbStore_Promise_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + await dataRdb.getRdbStore(context, STORE_CONFIG); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the getRdbStore_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_deleteRdbStore_Promise_001', 0, async function (done) { - let averageTime = 0; - let startTime = new Date().getTime(); - for (var i = 0; i < BASE_COUNT; i++) { - await dataRdb.deleteRdbStore(context, DB_NAME, 1); - } - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the deleteRdbStore_Promise average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - console.info(TAG + "*************Unit Test End*************") - }) + it('SUB_DDM_PERF_RDB_deleteRdbStore_Promise_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + await dataRdb.deleteRdbStore(context, DB_NAME, 1); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the deleteRdbStore_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + console.info(TAG + "*************Unit Test End*************") + }) }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/performance/src/RdbStoreCallbackPerf.js b/relational_store/test/js/relationalstore/performance/src/RdbStoreCallbackPerf.js index 0c4fc81fe220c2850db9e41febecb26d5e520d80..72aed689349e5844eba2c1bd25937790d34327d3 100644 --- a/relational_store/test/js/relationalstore/performance/src/RdbStoreCallbackPerf.js +++ b/relational_store/test/js/relationalstore/performance/src/RdbStoreCallbackPerf.js @@ -13,18 +13,19 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDBSTORE_CALLBACK]"; const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; const DB_NAME = "rdbStoreCallback.db"; const STORE_CONFIG = { - name: DB_NAME, + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S1 } let context = featureAbility.getContext(); var rdbStore = undefined; @@ -35,91 +36,91 @@ const BASE_LINE_PHONE = 7000; // callback phone base line const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; describe('rdbStoreCallbackPerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - await rdbStore.executeSql(CREATE_TABLE_TEST, null); - await prepareTestData(); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - await rdbStore.executeSql("drop table test"); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - rdbStore = null; - await dataRdb.deleteRdbStore(context, DB_NAME); - }) + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) - async function prepareTestData() { - console.info(TAG + "prepare for query performance test"); - var u8 = new Uint8Array([1, 2, 3]); - var valueBucket = { - "name": "zhangsan", - "age": 18, - "salary": 100.5, - "blobType": u8, - } - await rdbStore.insert("test", valueBucket); + async function prepareTestData() { + console.info(TAG + "prepare for query performance test"); + var u8 = new Uint8Array([1, 2, 3]); + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, } + await rdbStore.insert("test", valueBucket); + } - console.log(TAG + "*************Unit Test Begin*************"); + console.log(TAG + "*************Unit Test Begin*************"); - it('SUB_DDM_PERF_RDB_query_Callback_001', 0, async function (done) { - let averageTime = 0; - let predicates = new dataRdb.RdbPredicates("test"); - predicates.equalTo("age", 10); + it('SUB_DDM_PERF_RDB_query_Callback_001', 0, async function (done) { + let averageTime = 0; + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 10); - async function queryCallbackPerf(index) { - rdbStore.query(predicates, [], function (err, resultSet) { - resultSet.close(); - if (index < BASE_COUNT) { - queryCallbackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the query_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - console.info(TAG + "*************Unit Test End*************"); - done(); - } - }) + async function queryCallbackPerf(index) { + rdbStore.query(predicates, [], function (err, resultSet) { + resultSet.close(); + if (index < BASE_COUNT) { + queryCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the query_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "*************Unit Test End*************"); + done(); } + }) + } - let startTime = new Date().getTime(); - queryCallbackPerf(0); - }) + let startTime = new Date().getTime(); + queryCallbackPerf(0); + }) - it('SUB_DDM_PERF_RDB_insert_Callback_001', 0, async function (done) { - let averageTime = 0; - var uBlob = new Uint8Array([1, 2, 3]); - var insertValueBucket = { - "name": "zhangsan", - "age": 18, - "salary": 100.5, - "blobType": uBlob, - } - let predicates = new dataRdb.RdbPredicates("test"); - predicates.equalTo("age", 10); + it('SUB_DDM_PERF_RDB_insert_Callback_001', 0, async function (done) { + let averageTime = 0; + var uBlob = new Uint8Array([1, 2, 3]); + var insertValueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": uBlob, + } + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 10); - async function InsertCallbackPerf(index) { - rdbStore.insert("test", insertValueBucket, function (err, data) { - if (index < INSERT_BASE_COUNT) { - InsertCallbackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / INSERT_BASE_COUNT; - console.info(TAG + " the insert_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) + async function InsertCallbackPerf(index) { + rdbStore.insert("test", insertValueBucket, function (err, data) { + if (index < INSERT_BASE_COUNT) { + InsertCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / INSERT_BASE_COUNT; + console.info(TAG + " the insert_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); } + }) + } - let startTime = new Date().getTime(); - InsertCallbackPerf(0); - }) + let startTime = new Date().getTime(); + InsertCallbackPerf(0); + }) }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/performance/src/RdbStoreOthersCallbackPerf.js b/relational_store/test/js/relationalstore/performance/src/RdbStoreOthersCallbackPerf.js index 6fa5cec90e1d29c653be745e998747a172c9de13..1bce013b5c1b5e7961c915fc990a3617776490e9 100644 --- a/relational_store/test/js/relationalstore/performance/src/RdbStoreOthersCallbackPerf.js +++ b/relational_store/test/js/relationalstore/performance/src/RdbStoreOthersCallbackPerf.js @@ -13,18 +13,19 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDBSTORE_OTHERS_CALLBACK]"; const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; const DB_NAME = "rdbUpdateCallback.db"; const STORE_CONFIG = { - name: DB_NAME, + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S1 } let context = featureAbility.getContext(); var rdbStore = undefined; @@ -35,175 +36,131 @@ const BASE_LINE_PHONE = 15000; // callback phone base line const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; describe('rdbStoreOthersCallbackPerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - await rdbStore.executeSql(CREATE_TABLE_TEST, null); - await prepareTestData(); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - await rdbStore.executeSql("drop table test"); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - rdbStore = null; - await dataRdb.deleteRdbStore(context, DB_NAME); - }) - - async function prepareTestData() { - console.info(TAG + "prepare for query performance test"); - var u8 = new Uint8Array([1, 2, 3]); - var valueBucket = { - "name": "zhangsan", - "age": 18, - "salary": 100.5, - "blobType": u8, - } - await rdbStore.insert("test", valueBucket); + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + async function prepareTestData() { + console.info(TAG + "prepare for query performance test"); + var u8 = new Uint8Array([1, 2, 3]); + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, } - - console.log(TAG + "*************Unit Test Begin*************"); - - it('SUB_DDM_PERF_RDB_update_Callback_001', 0, async function (done) { - let averageTime = 0; - var uBlob = new Uint8Array([1, 2, 3]) - var updateVB = { - "name": "zhangsan", - "age": 18, - "salary": 100.5, - "blobType": uBlob, - } - let predicates = new dataRdb.RdbPredicates("test"); - - async function updateCallbackPerf(index) { - predicates.equalTo("age", 18); - rdbStore.update(updateVB, predicates, function (err, data) { - if (index < SPECIAL_BASE_COUNT) { - updateCallbackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; - console.info(TAG + " the update_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) - } - - let startTime = new Date().getTime(); - updateCallbackPerf(0); - }) - - it('SUB_DDM_PERF_RDB_delete_Callback_001', 0, async function (done) { - let averageTime = 0; - let predicates = new dataRdb.RdbPredicates("test"); - predicates.equalTo("age", 0); - - async function deleteCallbackPerf(index) { - rdbStore.delete(predicates, function (err, data) { - if (index < BASE_COUNT) { - deleteCallbackPerf(index + 1) - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the delete_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) - } - - let startTime = new Date().getTime(); - deleteCallbackPerf(0); - }) - - it('SUB_DDM_PERF_RDB_querySql_Callback_001', 0, async function (done) { - let averageTime = 0; - - async function querySqlCallbackPerf(index) { - rdbStore.querySql("select * from test", [], function (err, data) { - if (index < BASE_COUNT) { - querySqlCallbackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the querySql_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) + await rdbStore.insert("test", valueBucket); + } + + console.log(TAG + "*************Unit Test Begin*************"); + + it('SUB_DDM_PERF_RDB_update_Callback_001', 0, async function (done) { + let averageTime = 0; + var uBlob = new Uint8Array([1, 2, 3]) + var updateVB = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": uBlob, + } + let predicates = new dataRdb.RdbPredicates("test"); + + async function updateCallbackPerf(index) { + predicates.equalTo("age", 18); + rdbStore.update(updateVB, predicates, function (err, data) { + if (index < SPECIAL_BASE_COUNT) { + updateCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; + console.info(TAG + " the update_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); } + }) + } - let startTime = new Date().getTime(); - querySqlCallbackPerf(0); - }) - - it('SUB_DDM_PERF_RDB_executeSql_Callback_001', 0, async function (done) { - let averageTime = 0; - - async function executeSqlCallbackPerf(index) { - rdbStore.executeSql("insert into test (name, age) values ('tom', 22)", function (err, data) { - if (index < SPECIAL_BASE_COUNT) { - executeSqlCallbackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; - console.info(TAG + " the executeSql_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) + let startTime = new Date().getTime(); + updateCallbackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_delete_Callback_001', 0, async function (done) { + let averageTime = 0; + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 0); + + async function deleteCallbackPerf(index) { + rdbStore.delete(predicates, function (err, data) { + if (index < BASE_COUNT) { + deleteCallbackPerf(index + 1) + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the delete_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); } + }) + } - let startTime = new Date().getTime(); - executeSqlCallbackPerf(0); - }) - - it('SUB_DDM_PERF_RDB_backup_Callback_001', 0, async function (done) { - let averageTime = 0; - - async function backupCallbackPerf(index) { - rdbStore.backup("backup.db", function (err, data) { - if (index < BASE_COUNT) { - backupCallbackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the backup_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - } - }) + let startTime = new Date().getTime(); + deleteCallbackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_querySql_Callback_001', 0, async function (done) { + let averageTime = 0; + + async function querySqlCallbackPerf(index) { + rdbStore.querySql("select * from test", [], function (err, data) { + if (index < BASE_COUNT) { + querySqlCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the querySql_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); } + }) + } - let startTime = new Date().getTime(); - backupCallbackPerf(0); - }) - - it('SUB_DDM_PERF_RDB_restore_Callback_001', 0, async function (done) { - let averageTime = 0; - - async function restoreCallbackPerf(index) { - rdbStore.restore("backup.db", function (err, data) { - if (index < BASE_COUNT) { - restoreCallbackPerf(index + 1); - } else { - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the restore_Callback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - dataRdb.deleteRdbStore(context, "backup.db", function (err, data) { - done(); - }) - } - }) + let startTime = new Date().getTime(); + querySqlCallbackPerf(0); + }) + + it('SUB_DDM_PERF_RDB_executeSql_Callback_001', 0, async function (done) { + let averageTime = 0; + + async function executeSqlCallbackPerf(index) { + rdbStore.executeSql("insert into test (name, age) values ('tom', 22)", function (err, data) { + if (index < SPECIAL_BASE_COUNT) { + executeSqlCallbackPerf(index + 1); + } else { + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; + console.info(TAG + " the executeSql_Callback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); } + }) + } - let startTime = new Date().getTime(); - restoreCallbackPerf(0); - }) + let startTime = new Date().getTime(); + executeSqlCallbackPerf(0); + }) }) diff --git a/relational_store/test/js/relationalstore/performance/src/RdbStorePromisePerf.js b/relational_store/test/js/relationalstore/performance/src/RdbStorePromisePerf.js index 87c157e0f08544a47a4f1014037a885f8d921796..a2209b6f2eda796749646b0fea46becdeb63d94d 100644 --- a/relational_store/test/js/relationalstore/performance/src/RdbStorePromisePerf.js +++ b/relational_store/test/js/relationalstore/performance/src/RdbStorePromisePerf.js @@ -13,18 +13,19 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDBSTORE_PROMISE]"; const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; const DB_NAME = "rdbStorePromise.db"; const STORE_CONFIG = { - name: DB_NAME, + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S1 } let context = featureAbility.getContext(); var rdbStore = undefined; @@ -34,53 +35,53 @@ const BASE_LINE_PHONE = 3000; // callback phone base line const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; describe('rdbStorePromisePerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - await rdbStore.executeSql(CREATE_TABLE_TEST, null); - await prepareTestData(); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - await rdbStore.executeSql("drop table test"); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - rdbStore = null; - await dataRdb.deleteRdbStore(context, DB_NAME); - }) + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) - async function prepareTestData() { - console.info(TAG + "prepare for query performance test") - var u8 = new Uint8Array([1, 2, 3]) - var valueBucket = { - "name": "zhangsan", - "age": 18, - "salary": 100.5, - "blobType": u8, - } - await dataRdb.insert("test", valueBucket); + async function prepareTestData() { + console.info(TAG + "prepare for query performance test") + var u8 = new Uint8Array([1, 2, 3]) + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, } + await dataRdb.insert("test", valueBucket); + } - console.log(TAG + "*************Unit Test Begin*************"); + console.log(TAG + "*************Unit Test Begin*************"); - it('SUB_DDM_PERF_RDB_query_Promise_001', 0, async function (done) { - let averageTime = 0; - let predicates = new dataRdb.RdbPredicates("test"); - predicates.equalTo("age", 10); - let startTime = new Date().getTime(); - for (var i = 0; i < BASE_COUNT; i++) { - let resultSet = await rdbStore.query(predicates, []); - resultSet.close(); - } - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the query_Promise average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - console.info(TAG + "*************Unit Test End*************"); - done(); - }) + it('SUB_DDM_PERF_RDB_query_Promise_001', 0, async function (done) { + let averageTime = 0; + let predicates = new dataRdb.RdbPredicates("test"); + predicates.equalTo("age", 10); + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + let resultSet = await rdbStore.query(predicates, []); + resultSet.close(); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the query_Promise average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + console.info(TAG + "*************Unit Test End*************"); + done(); + }) }) diff --git a/relational_store/test/js/relationalstore/performance/src/RdbStoreSyncPerf.js b/relational_store/test/js/relationalstore/performance/src/RdbStoreSyncPerf.js index b8b922b93348e7b6c97d2faf96107dc1452aa6c5..3a3b90f288a0868846bcb18e68cc56f6b0419a3f 100644 --- a/relational_store/test/js/relationalstore/performance/src/RdbStoreSyncPerf.js +++ b/relational_store/test/js/relationalstore/performance/src/RdbStoreSyncPerf.js @@ -13,18 +13,16 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDB_SYNC_PROMISE]"; -const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; - const DB_NAME = "rdbSync.db"; const STORE_CONFIG = { - name: DB_NAME, + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S1 } let context = featureAbility.getContext(); var rdbStore = undefined; @@ -35,64 +33,64 @@ const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_L describe('rdbStoreSyncPerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - rdbStore = null - await dataRdb.deleteRdbStore(context, DB_NAME); - }) + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null + await dataRdb.deleteRdbStore(context, DB_NAME); + }) - console.log(TAG + "*************Unit Test Begin*************"); + console.log(TAG + "*************Unit Test Begin*************"); - it('SUB_DDM_PERF_RDB_version_001', 0, async function (done) { - let averageTime = 0; - let dbVersion = 1; - let startTime = new Date().getTime(); - for (var i = 0; i < BASE_COUNT; i++) { - dbVersion = rdbStore.version; - } - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the version average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_version_001', 0, async function (done) { + let averageTime = 0; + let dbVersion = 1; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + dbVersion = rdbStore.version; + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the version average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_transaction_commit_001', 0, async function (done) { - let averageTime = 0; - let startTime = new Date().getTime(); - for (var i = 0; i < BASE_COUNT; i++) { - rdbStore.beginTransaction(); - rdbStore.commit(); - } - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the transaction_commit average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_transaction_commit_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + rdbStore.beginTransaction(); + rdbStore.commit(); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the transaction_commit average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_transaction_rollback_001', 0, async function (done) { - let averageTime = 0; - let startTime = new Date().getTime(); - for (var i = 0; i < BASE_COUNT; i++) { - rdbStore.beginTransaction(); - rdbStore.rollBack(); - } - let endTime = new Date().getTime(); - averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the transaction_rollback average time is: " + averageTime + " μs"); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - console.info(TAG + "*************Unit Test End*************"); - }) + it('SUB_DDM_PERF_RDB_transaction_rollback_001', 0, async function (done) { + let averageTime = 0; + let startTime = new Date().getTime(); + for (var i = 0; i < BASE_COUNT; i++) { + rdbStore.beginTransaction(); + rdbStore.rollBack(); + } + let endTime = new Date().getTime(); + averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the transaction_rollback average time is: " + averageTime + " μs"); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + console.info(TAG + "*************Unit Test End*************"); + }) }) diff --git a/relational_store/test/js/relationalstore/performance/src/ResultSetPerf.js b/relational_store/test/js/relationalstore/performance/src/ResultSetPerf.js index 15ea1d0d8f7475f7bd1e4abe6245f772c02ab325..797a790627bb38dec55fd72460786ce1547d67d6 100644 --- a/relational_store/test/js/relationalstore/performance/src/ResultSetPerf.js +++ b/relational_store/test/js/relationalstore/performance/src/ResultSetPerf.js @@ -13,18 +13,19 @@ * limitations under the License. */ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert } from 'deccjsunit/index'; -import dataRdb from '@ohos.data.rdb'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; import featureAbility from '@ohos.ability.featureAbility'; import deviceInfo from '@ohos.deviceInfo'; const TAG = "[RDB_RESULTSET_PERF]"; const CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT, " -+ "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; + + "name TEXT, age INTEGER, salary REAL, blobType BLOB)"; const DB_NAME = "resultSetPerf.db"; const STORE_CONFIG = { - name: DB_NAME, + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S1 } let context = featureAbility.getContext(); var rdbStore = undefined; @@ -35,260 +36,254 @@ const BASE_LINE_PHONE = 1000; // callback phone base line const BASE_LINE = (deviceInfo.deviceType == "tablet") ? BASE_LINE_TABLE : BASE_LINE_PHONE; describe('resultSetPerf', function () { - beforeAll(async function () { - console.info(TAG + 'beforeAll'); - rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG, 1); - }) - beforeEach(async function () { - console.info(TAG + 'beforeEach'); - await rdbStore.executeSql(CREATE_TABLE_TEST, null); - await prepareTestData(); - }) - afterEach(async function () { - console.info(TAG + 'afterEach'); - await rdbStore.executeSql("drop table test"); - }) - afterAll(async function () { - console.info(TAG + 'afterAll'); - rdbStore = null; - await dataRdb.deleteRdbStore(context, DB_NAME); - }) + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG); + }) + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + await rdbStore.executeSql(CREATE_TABLE_TEST, null); + await prepareTestData(); + }) + afterEach(async function () { + console.info(TAG + 'afterEach'); + await rdbStore.executeSql("drop table test"); + }) + afterAll(async function () { + console.info(TAG + 'afterAll'); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) - async function prepareTestData() { - console.info(TAG + "prepare for query performance test"); - var valueBuckets = []; - var u8 = new Uint8Array([1, 2, 3]) - var valueBucket = { - "name": "zhangsan", - "age": 18, - "salary": 100.5, - "blobType": u8, - } - for (let i = 0; i < BASE_COUNT; i++) { - valueBucket.age += i; - valueBuckets.push(valueBucket); - } - rdbStore.batchInsert("test", valueBuckets, function (err, insertNum) { - if (err) { - console.error(`batchInsert is failed, err: ${err}`); - return; - } - console.info(`batchInsert is successful, the number of values that were inserted = ${insertNum}`); - }) + async function prepareTestData() { + console.info(TAG + "prepare for query performance test"); + var valueBuckets = []; + var u8 = new Uint8Array([1, 2, 3]) + var valueBucket = { + "name": "zhangsan", + "age": 18, + "salary": 100.5, + "blobType": u8, } + for (let i = 0; i < BASE_COUNT; i++) { + valueBucket.age += i; + valueBuckets.push(valueBucket); + } + await rdbStore.batchInsert("test", valueBuckets); + } - console.log(TAG + "*************Unit Test Begin*************"); + console.log(TAG + "*************Unit Test Begin*************"); - it('SUB_DDM_PERF_RDB_ResultSet_GetColumnIndex_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - resultSet.goToFirstRow(); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_LINE; i++) { - resultSet.getColumnIndex("id"); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GetColumnIndex average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GetColumnIndex_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_LINE; i++) { + resultSet.getColumnIndex("id"); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetColumnIndex average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GetColumnName_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - resultSet.goToFirstRow(); - let startTime = new Date().getTime() - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.getColumnName(0); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GetColumnName average time is: " + averageTime + " μs") - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GetColumnName_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getColumnName(0); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetColumnName average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GoTo_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - resultSet.goToFirstRow(); - let startTime = new Date().getTime() - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.goTo(i % 2); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GoTo average time is: " + averageTime + " μs") - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GoTo_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goTo(i % 2); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoTo average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GoToRow_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - resultSet.goToFirstRow(); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.goToRow(1); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GoToRow average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GoToRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToRow(1); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GoToFirstRow_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.goToFirstRow(); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GoToFirstRow average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GoToFirstRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToFirstRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToFirstRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GoToLastRow_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.goToLastRow(); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GoToLastRow average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GoToLastRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToLastRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToLastRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GoToNextRow_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - resultSet.goToFirstRow(); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.goToNextRow(); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GoToNextRow average time is: " + averageTime + " μs") - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GoToNextRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToNextRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToNextRow average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GoToPreviousRow_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - resultSet.goToLastRow(); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.goToPreviousRow(); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GoToPreviousRow average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GoToPreviousRow_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + resultSet.goToLastRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.goToPreviousRow(); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GoToPreviousRow average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GetBlob_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - let columnIndex = resultSet.getColumnIndex("blobType"); - resultSet.goToFirstRow(); - let startTime = new Date().getTime() - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.getBlob(columnIndex); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GetBlob average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GetBlob_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("blobType"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getBlob(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetBlob average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GetString_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - let columnIndex = resultSet.getColumnIndex("name"); - let flag = resultSet.goToFirstRow(); - let startTime = new Date().getTime(); - for (var i = 0; i < SPECIAL_BASE_COUNT; i++) { - resultSet.getString(columnIndex); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; - console.info(TAG + " the ResultSet_GetString average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done() - }) + it('SUB_DDM_PERF_RDB_ResultSet_GetString_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("name"); + let flag = resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (var i = 0; i < SPECIAL_BASE_COUNT; i++) { + resultSet.getString(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / SPECIAL_BASE_COUNT; + console.info(TAG + " the ResultSet_GetString average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done() + }) - it('SUB_DDM_PERF_RDB_ResultSet_GetLong_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - let columnIndex = resultSet.getColumnIndex("age"); - resultSet.goToFirstRow(); - let startTime = new Date().getTime(); - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.getLong(columnIndex); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GetLong average time is: " + averageTime + " μs") - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GetLong_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("age"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime(); + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getLong(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetLong average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_GetDouble_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - let columnIndex = resultSet.getColumnIndex("salary"); - resultSet.goToFirstRow(); - let startTime = new Date().getTime() - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.getDouble(columnIndex); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_GetDouble average time is: " + averageTime + " μs") - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_GetDouble_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("salary"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.getDouble(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_GetDouble average time is: " + averageTime + " μs") + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - it('SUB_DDM_PERF_RDB_ResultSet_IsColumnNull_001', 0, async function (done) { - let predicates = new dataRdb.RdbPredicates("test"); - let resultSet = await rdbStore.query(predicates); - let columnIndex = resultSet.getColumnIndex("salary"); - resultSet.goToFirstRow(); - let startTime = new Date().getTime() - for (let i = 0; i < BASE_COUNT; i++) { - resultSet.isColumnNull(columnIndex); - } - let endTime = new Date().getTime(); - let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; - console.info(TAG + " the ResultSet_IsColumnNull average time is: " + averageTime + " μs"); - resultSet.close(); - expect(averageTime < BASE_LINE).assertTrue(); - done(); - }) + it('SUB_DDM_PERF_RDB_ResultSet_IsColumnNull_001', 0, async function (done) { + let predicates = new dataRdb.RdbPredicates("test"); + let resultSet = await rdbStore.query(predicates); + let columnIndex = resultSet.getColumnIndex("salary"); + resultSet.goToFirstRow(); + let startTime = new Date().getTime() + for (let i = 0; i < BASE_COUNT; i++) { + resultSet.isColumnNull(columnIndex); + } + let endTime = new Date().getTime(); + let averageTime = ((endTime - startTime) * 1000) / BASE_COUNT; + console.info(TAG + " the ResultSet_IsColumnNull average time is: " + averageTime + " μs"); + resultSet.close(); + expect(averageTime < BASE_LINE).assertTrue(); + done(); + }) - console.info(TAG + "*************Unit Test End*************"); + console.info(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/performance/src/SceneGetValuesBucketPerf.js b/relational_store/test/js/relationalstore/performance/src/SceneGetValuesBucketPerf.js new file mode 100644 index 0000000000000000000000000000000000000000..33aa0de7e28f031f35f63c49fbeec18c2ed48faa --- /dev/null +++ b/relational_store/test/js/relationalstore/performance/src/SceneGetValuesBucketPerf.js @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, Assert} from 'deccjsunit/index'; +import dataRdb from '@ohos.data.relationalStore'; +import featureAbility from '@ohos.ability.featureAbility'; + +const TAG = "[RDB_RESULTSET_PERF]"; +const CREATE_TABLE_TEST = "CREATE TABLE test (" + + "data01 TEXT, data02 INTEGER, data03 FLOAT, data04 BLOB, data05 BOOLEAN, " + + "data06 TEXT, data07 INTEGER, data08 FLOAT, data09 BLOB, data10 BOOLEAN, " + + "data11 TEXT, data12 INTEGER, data13 FLOAT, data14 BLOB, data15 BOOLEAN, " + + "data16 TEXT, data17 INTEGER, data18 FLOAT, data19 BLOB, data20 BOOLEAN" + + ");"; + +const FIELDS = ["data01", "data02", "data03", "data04", "data05", "data06", "data07", "data08", "data09", "data10", + "data11", "data12", "data13", "data14", "data15", "data16", "data17", "data18", "data19", "data20"] + +function CREATE_STRING(len) { + let result = ''; + for (let i = 0; i < len; i++) { + result += 'a'; + } + return result; +} + +const CONST_STRING_VALUE = CREATE_STRING(127); + +function CREATE_UINT8_ARRAY(len) { + let result = new Uint8Array(len); + for (let i = 0; i < len; i++) { + result[i] = 1; + } + return result; +} + +const CONST_UINT8_ARRAY = CREATE_UINT8_ARRAY(127); + +const DB_NAME = "resultSetPerf.db"; +const STORE_CONFIG = { + name: DB_NAME, + securityLevel: dataRdb.SecurityLevel.S3 +} + +let context = featureAbility.getContext(); +let rdbStore = undefined; +const BASE_COUNT = 2000; // loop times + +describe('SceneGetValuesBucketPerf', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll'); + rdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG); + await rdbStore.executeSql(CREATE_TABLE_TEST); + await prepareTestData(); + }) + + beforeEach(async function () { + console.info(TAG + 'beforeEach'); + }) + + afterEach(async function () { + console.info(TAG + 'afterEach'); + }) + + afterAll(async function () { + console.info(TAG + 'afterAll'); + await rdbStore.executeSql("drop table test"); + rdbStore = null; + await dataRdb.deleteRdbStore(context, DB_NAME); + }) + + async function prepareTestData() { + console.info(TAG + "prepare for query performance test"); + let valueBuckets = []; + let valueBucket = { + data01: CONST_STRING_VALUE, + data02: 10001, + data03: 101.5, + data04: CONST_UINT8_ARRAY, + data05: false, + data06: CONST_STRING_VALUE, + data07: 10002, + data08: 102.5, + data09: CONST_UINT8_ARRAY, + data10: true, + data11: CONST_STRING_VALUE, + data12: 10003, + data13: 103.5, + data14: CONST_UINT8_ARRAY, + data15: false, + data16: CONST_STRING_VALUE, + data17: 10004, + data18: 104.5, + data19: CONST_UINT8_ARRAY, + data20: true + } + for (let i = 0; i < BASE_COUNT; i++) { + valueBuckets.push(valueBucket); + } + await rdbStore.batchInsert("test", valueBuckets) + } + + it('Scene_GetValuesBucket_0001', 0, async function (done) { + console.log(TAG + "************* Scene_GetValuesBucket_0001 start *************"); + let predicates = await new dataRdb.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + expect(2000).assertEqual(resultSet.rowCount); + + let startTime = new Date().getTime(); + let allValues = new Array(); + let i = 0; + while (resultSet.goToNextRow()) { + let values = resultSet.getRow(); + allValues[i++] = values; + } + resultSet.close(); + let endTime = new Date().getTime(); + let averageTime = (endTime - startTime); + console.info(TAG + " the Scene_GetValuesBucket_0001 average time is: " + averageTime + " ms"); + expect(2000).assertEqual(allValues.length); + expect(averageTime).assertLess(600); + + expect(CONST_STRING_VALUE).assertEqual(allValues[0]["data01"]); + done(); + console.log(TAG + "************* Scene_GetValuesBucket_0001 end *************"); + }) + + /** + * @tc.name RDB Backup Restore test + * @tc.number SUB_DDM_RDB_JS_RdbBackupRestoreTest_0010 + * @tc.desc RDB backup and restore function test + */ + it('Scene_GetValuesBucket_0002', 0, async function (done) { + console.log(TAG + "************* Scene_GetValuesBucket_0002 start *************"); + let predicates = await new dataRdb.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + expect(2000).assertEqual(resultSet.rowCount); + + let startTime = new Date().getTime(); + let allValues = new Array(2000); + + let i = 0; + let indexes = new Array(20); + while (resultSet.goToNextRow()) { + let values = new Array(); + + if (i == 0) { + for (let i = 0; i < 20; i++) { + indexes[i] = resultSet.getColumnIndex(FIELDS[i]); + } + } + + for (let i = 0; i < 20; i++) { + switch (resultSet.getColumnType(indexes[i])) { + case 0: // TYPE_NULL + values[FIELDS[i]] = null; + break; + case 1: // TYPE_INTEGER + values[FIELDS[i]] = resultSet.getInt(indexes[i]); + break; + case 2: // TYPE_FLOAT + values[FIELDS[i]] = resultSet.getDouble(indexes[i]); + break; + case 3: // TYPE_STRING + values[FIELDS[i]] = resultSet.getString(indexes[i]); + break; + case 4: // TYPE_BLOB + values[FIELDS[i]] = resultSet.getBlob(indexes[i]); + break; + } + } + allValues[i++] = values; + } + resultSet.close(); + let endTime = new Date().getTime(); + let averageTime = (endTime - startTime); + console.info(TAG + " the Scene_GetValuesBucket_0002 average time is: " + averageTime + " ms"); + expect(2000).assertEqual(allValues.length); + expect(averageTime).assertLess(1500); + + expect(CONST_STRING_VALUE).assertEqual(allValues[0]["data01"]); + done(); + console.log(TAG + "************* Scene_GetValuesBucket_0002 end *************"); + }) +}) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreDistributedJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreDistributedJsunit.test.js index d4957a29839de953fa1f24f1bef93490ec097e2e..ff5326f6db42d63cbbf572a81003bfeded68ce46 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreDistributedJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreDistributedJsunit.test.js @@ -19,6 +19,7 @@ import ability_featureAbility from '@ohos.ability.featureAbility' const TAG = "[RELATIONAL_STORE_JSKITS_TEST]" const STORE_NAME = "distributed_rdb.db" +const E_NOT_SUPPORTED = 801; var rdbStore = undefined; var context = ability_featureAbility.getContext() @@ -94,8 +95,8 @@ describe('rdbStoreDistributedTest', function () { console.log(TAG + "set none to be distributed table success"); expect(rdbStore).assertEqual(rdbStore) } catch (err) { - console.log(TAG + "set none to be distributed table failed"); - expect(null).assertFail(); + console.log(TAG + `set none to be distributed table failed, err is ${err.code}.`); + expect(E_NOT_SUPPORTED).assertEqual(err.code); } done() console.log(TAG + "************* testRdbStoreDistributed002 end *************"); @@ -113,8 +114,8 @@ describe('rdbStoreDistributedTest', function () { console.log(TAG + "set employee to be distributed table success"); expect(rdbStore).assertEqual(rdbStore) } catch (err) { - console.log(TAG + "set employee to be distributed table failed"); - expect(null).assertFail(); + console.log(TAG + `set employee to be distributed table failed, err is ${err.code}.`); + expect(E_NOT_SUPPORTED).assertEqual(err.code); } done() console.log(TAG + "************* testRdbStoreDistributed003 end *************"); @@ -132,8 +133,8 @@ describe('rdbStoreDistributedTest', function () { console.log(TAG + "set employee and product to be distributed table success"); expect(rdbStore).assertEqual(rdbStore) } catch (err) { - console.log(TAG + "set employee and product to be distributed table failed"); - expect(null).assertFail(); + console.log(TAG + `set employee and product to be distributed table failed, err is ${err.code}.`); + expect(E_NOT_SUPPORTED).assertEqual(err.code); } done() console.log(TAG + "************* testRdbStoreDistributed004 end *************"); diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetRow.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetRow.test.js new file mode 100644 index 0000000000000000000000000000000000000000..76d4c1672882fa942ccc30d71f4b2667580baff2 --- /dev/null +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetGetRow.test.js @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * 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. + */ + +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from 'deccjsunit/index' +import data_relationalStore from '@ohos.data.relationalStore'; +import ability_featureAbility from '@ohos.ability.featureAbility' + +var context = ability_featureAbility.getContext() + +const TAG = "[RELATIONAL_STORE_JSKITS_TEST]" + +const STORE_CONFIG = { + name: "stepResultSet_getRow_test.db", + securityLevel: data_relationalStore.SecurityLevel.S1, +} +let rdbStore +describe('rdbStoreResultSetGetRowTest', function () { + beforeAll(async function () { + console.info(TAG + 'beforeAll') + await data_relationalStore.deleteRdbStore(context, "stepResultSet_getRow_test.db"); + rdbStore = await data_relationalStore.getRdbStore(context, STORE_CONFIG); + }) + + beforeEach(async function () { + console.info(TAG + 'beforeEach') + await rdbStore.executeSql("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 TEXT, " + + "data2 INTEGER, data3 FLOAT, data4 BLOB, data5 BOOLEAN);"); + }) + + afterEach(async function () { + console.info(TAG + 'afterEach') + await rdbStore.executeSql("DROP TABLE IF EXISTS test"); + }) + + afterAll(async function () { + console.info(TAG + 'afterAll') + await data_relationalStore.deleteRdbStore(context, "stepResultSet_getRow_test.db"); + }) + + console.log(TAG + "*************Unit Test Begin*************"); + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRowTest0001 + * @tc.desc resultSet getRow test + */ + it('rdbStoreResultSetGetRowTest0001', 0, async function (done) { + console.log(TAG + "************* rdbStoreResultSetGetRowTest0001 start *************"); + let valueBucket = { + id: 1 + }; + let rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + expect(true).assertEqual(resultSet.goToFirstRow()); + + let valueBucket_ret = resultSet.getRow(); + + expect(1).assertEqual(valueBucket_ret["id"]); + expect(null).assertEqual(valueBucket_ret["data1"]); + expect(null).assertEqual(valueBucket_ret["data2"]); + expect(null).assertEqual(valueBucket_ret["data3"]); + expect(null).assertEqual(valueBucket_ret["data4"]); + expect(null).assertEqual(valueBucket_ret["data5"]); + + done(); + console.log(TAG + "************* rdbStoreResultSetGetRowTest0001 end *************"); + }) + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRowTest0002 + * @tc.desc resultSet getRow test + */ + it('rdbStoreResultSetGetRowTest0002', 0, async function (done) { + console.log(TAG + "************* rdbStoreResultSetGetRowTest0002 start *************"); + let valueBucket = { + data1: null, + data2: undefined, + data4: undefined, + data5: null + }; + let rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + expect(true).assertEqual(resultSet.goToFirstRow()); + + let valueBucket_ret = resultSet.getRow(); + + expect(1).assertEqual(valueBucket_ret["id"]); + expect(null).assertEqual(valueBucket_ret["data1"]); + expect(null).assertEqual(valueBucket_ret["data2"]); + expect(null).assertEqual(valueBucket_ret["data3"]); + expect(null).assertEqual(valueBucket_ret["data4"]); + expect(null).assertEqual(valueBucket_ret["data5"]); + + done(); + console.log(TAG + "************* rdbStoreResultSetGetRowTest0002 end *************"); + }) + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRowTest0003 + * @tc.desc resultSet getRow test + */ + it('rdbStoreResultSetGetRowTest0003', 0, async function (done) { + console.log(TAG + "************* rdbStoreResultSetGetRowTest0003 start *************"); + let valueBucket = { + data1: "hello", + data2: 10, + data3: 1.0, + data4: new Uint8Array([1, 2, 3, 4]), + data5: true, + }; + let rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates) + expect(true).assertEqual(resultSet.goToFirstRow()); + + let valueBucket_ret = resultSet.getRow(); + + expect(1).assertEqual(valueBucket_ret.id); + expect("hello").assertEqual(valueBucket_ret.data1); + expect(10).assertEqual(valueBucket_ret.data2); + expect(1.0).assertEqual(valueBucket_ret.data3); + expect(4).assertEqual(valueBucket_ret.data4[3]); + expect(1).assertEqual(valueBucket_ret.data5); + + done(); + console.log(TAG + "************* rdbStoreResultSetGetRowTest0003 end *************"); + }) + + /** + * @tc.name rdb store resultSet getRow test + * @tc.number rdbStoreResultSetGetRowTest0004 + * @tc.desc resultSet getRow test + */ + it('rdbStoreResultSetGetRowTest0004', 0, async function (done) { + console.log(TAG + "************* rdbStoreResultSetGetRowTest0004 start *************"); + let valueBucket = { + "data1": "", + "data2": 10, + "data3": 1.0, + "data4": new Uint8Array([1, 2, 3, 4]), + "data5": true, + }; + let rowId = await rdbStore.insert("test", valueBucket); + expect(1).assertEqual(rowId); + + let predicates = await new data_relationalStore.RdbPredicates("test") + let resultSet = await rdbStore.query(predicates, ["data1", "data2"]) + expect(true).assertEqual(resultSet.goToFirstRow()); + + let valueBucket_ret = resultSet.getRow(); + + expect("").assertEqual(valueBucket_ret.data1); + expect(undefined).assertEqual(valueBucket_ret.data3); + expect(undefined).assertEqual(valueBucket_ret.data4); + + done(); + console.log(TAG + "************* rdbStoreResultSetGetRowTest0004 end *************"); + }) + console.log(TAG + "*************Unit Test End*************"); +}) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js index 1fa6b5ee627347c030ad206057a1b0c3768f52d7..fb02dbec7cf1a6c60c8aa291023706002f7127ba 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbStoreResultSetJsunit.test.js @@ -1974,7 +1974,7 @@ describe('rdbResultSetTest', function () { expect("").assertEqual(resultSet.getString(1)) } } catch (e) { - expect(e.code).assertEqual("14800000"); + expect(e.code).assertEqual("14800013"); } resultSet.close() expect(true).assertEqual(resultSet.isClosed) @@ -2015,7 +2015,7 @@ describe('rdbResultSetTest', function () { expect("").assertEqual(resultSet.getString(1)) } } catch (e) { - expect(e.code).assertEqual("14800000"); + expect(e.code).assertEqual("14800013"); } resultSet.close() @@ -2274,43 +2274,5 @@ describe('rdbResultSetTest', function () { console.log(TAG + "************* testBigData0014 end *************"); }) - - /** - * @tc.name resultSet Maximum read connections normal test - * @tc.number Maximum_Read_Connections_0001 - * @tc.desc resultSet getBlob normal test - */ - it('testMaximumReadConnections0001', 0, async function (done) { - console.log(TAG + "************* testMaximumReadConnections0002 start *************"); - - try{ - let resultSet1 = await rdbStore.queryByStep("SELECT ?, ? FROM test", ["id", "data1"]) - expect(true).assertEqual(resultSet1.goToFirstRow()) - - let resultSet2 = await rdbStore.queryByStep("SELECT ?, ? FROM test", ["id", "data1"]) - expect(true).assertEqual(resultSet2.goToFirstRow()) - - let resultSet3 = await rdbStore.queryByStep("SELECT ?, ? FROM test", ["id", "data1"]) - expect(true).assertEqual(resultSet3.goToFirstRow()) - - let resultSet4 = await rdbStore.queryByStep("SELECT ?, ? FROM test", ["id", "data1"]) - expect(true).assertEqual(resultSet4.goToFirstRow()) - - resultSet1.close(); - resultSet2.close(); - resultSet3.close(); - resultSet4.close(); - - resultSet1 = null; - resultSet2 = null; - resultSet3 = null; - resultSet4 = null; - } catch (e) { - expect(null).assertFail(); - } - done(); - console.log(TAG + "************* testMaximumReadConnections0001 end *************"); - }) - console.log(TAG + "*************Unit Test End*************"); }) \ No newline at end of file diff --git a/relational_store/test/js/relationalstore/unittest/src/RdbstorePredicatesJsunit.test.js b/relational_store/test/js/relationalstore/unittest/src/RdbstorePredicatesJsunit.test.js index bfcd076b607d628783c2bf33449f1ff124003d21..d990822bc43032768b27c03dcc76fb5547d37afb 100644 --- a/relational_store/test/js/relationalstore/unittest/src/RdbstorePredicatesJsunit.test.js +++ b/relational_store/test/js/relationalstore/unittest/src/RdbstorePredicatesJsunit.test.js @@ -1802,23 +1802,6 @@ describe('rdbPredicatesTest', function () { console.log(TAG + "************* testAnd0003 end *************"); }) - /** - * @tc.name predicates and normal test - * @tc.number SUB_DDM_AppDataFWK_JSRDB_Predicates_0153 - * @tc.desc predicates and normal test - */ - it('testAnd0004', 0, async function (done) { - console.log(TAG + "************* testAnd0004 start *************"); - - let predicates = new data_relationalStore.RdbPredicates("AllDataType"); - predicates.equalTo("stringValue", "ABCDEFGHIJKLMN").or().or().equalTo("integerValue", 1); - console.log(TAG + "you are starting a sql request with predicate or or," - + "using function or() immediately after another or(). that is ridiculous."); - - done(); - console.log(TAG + "************* testAnd0004 end *************"); - }) - /** * @tc.name predicates order normal test * @tc.number SUB_DDM_AppDataFWK_JSRDB_Predicates_0160 diff --git a/relational_store/test/native/cloud_data/BUILD.gn b/relational_store/test/native/cloud_data/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..021323f2b18534c0c21e5fa135fc128876574df9 --- /dev/null +++ b/relational_store/test/native/cloud_data/BUILD.gn @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# 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. + diff --git a/relational_store/test/native/rdb/BUILD.gn b/relational_store/test/native/rdb/BUILD.gn index e340d52a9b983d326e2b8538b8521809e86eb000..f6d223dac1dad1624c9918a599dbbdb1c66891fe 100644 --- a/relational_store/test/native/rdb/BUILD.gn +++ b/relational_store/test/native/rdb/BUILD.gn @@ -52,10 +52,12 @@ ohos_unittest("NativeRdbTest") { "unittest/rdb_predicates_join_test.cpp", "unittest/rdb_predicates_test.cpp", "unittest/rdb_sqlite_shared_result_set_test.cpp", + "unittest/rdb_step_result_get_row_test.cpp", "unittest/rdb_step_result_set_test.cpp", "unittest/rdb_store_concurrent_test.cpp", "unittest/rdb_store_config_test.cpp", "unittest/rdb_store_interface_test.cpp", + "unittest/rdb_store_rekey_test.cpp", "unittest/rdb_transaction_test.cpp", "unittest/rdb_update_test.cpp", "unittest/rdb_upgrade_test.cpp", diff --git a/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/distributed_test.cpp b/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/distributed_test.cpp index 8c5204d9a9026091af71226e1b77e73570b5dcde..3482e061ff45f188cda8df1c78a525ea793add25 100644 --- a/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/distributed_test.cpp +++ b/relational_store/test/native/rdb/distributedtest/rdb_store_impl_test/distributed_test.cpp @@ -152,12 +152,14 @@ HWTEST_F(DistributedTest, RemoteQuery001, TestSize.Level1) }); std::vector tables = {"test"}; DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", deviceInfos_); - std::string test = store_->ObtainDistributedTableName(deviceInfos_[0].networkId, tables[0]); + int errCode = E_ERROR; + std::string test = store_->ObtainDistributedTableName(deviceInfos_[0].networkId, tables[0], errCode); AbsRdbPredicates predicate(tables[0]); predicate.EqualTo("name", "zhangsan"); std::vector columns; - std::shared_ptr resultSet = store_-> RemoteQuery(deviceInfos_[0].networkId, predicate, columns); - + errCode = E_ERROR; + std::shared_ptr resultSet = store_->RemoteQuery(deviceInfos_[0].networkId, predicate, columns, errCode); + EXPECT_TRUE(ret > 0); EXPECT_EQ(returvalue, "zhangsan"); } diff --git a/relational_store/test/native/rdb/unittest/rdb_encrypt_decrypt_test.cpp b/relational_store/test/native/rdb/unittest/rdb_encrypt_decrypt_test.cpp index 29d28ac0e3ad68959b6cf50929bf5b35630c780e..44689a2cd26eaa0594b0f1f2ec6db98608ddf2bd 100644 --- a/relational_store/test/native/rdb/unittest/rdb_encrypt_decrypt_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_encrypt_decrypt_test.cpp @@ -245,25 +245,33 @@ HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_05, TestSize.Level1) /** * @tc.name: RdbStore_Encrypt_Decrypt_Test_006 - * @tc.desc: test SaveSecretKeyToFile when KeyFileType isNot PUB_KEY_FILE + * @tc.desc: test GetRdbStore with specified key * @tc.type: FUNC */ HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_06, TestSize.Level1) { + std::vector key{ 1, 2, 3 }; RdbStoreConfig config(RdbEncryptTest::ENCRYPTED_DATABASE_NAME); - config.SetEncryptStatus(true); - config.SetBundleName("com.example.TestEncrypt6"); + config.SetEncryptKey(key); EncryptTestOpenCallback helper; int errCode; std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); EXPECT_NE(store, nullptr); - bool ret = - RdbSecurityManager::GetInstance().CheckKeyDataFileExists(RdbSecurityManager::KeyFileType::PUB_KEY_BAK_FILE); - EXPECT_EQ(ret, false); - std::vector key = RdbSecurityManager::GetInstance().GenerateRandomNum(RdbSecurityManager::RDB_KEY_SIZE); - bool flag = RdbSecurityManager::GetInstance().SaveSecretKeyToFile( - RdbSecurityManager::KeyFileType::PUB_KEY_BAK_FILE, key); - EXPECT_EQ(flag, true); + + std::string keyPath = RDB_TEST_PATH + "key/" + "encrypted.pub_key"; + std::string newKeyPath = RDB_TEST_PATH + "key/" + +"encrypted.pub_key.new"; + bool isFileExists = OHOS::FileExists(keyPath); + EXPECT_EQ(isFileExists, false); + isFileExists = OHOS::FileExists(newKeyPath); + EXPECT_EQ(isFileExists, false); + + store.reset(); + RdbHelper::ClearCache(); + + std::vector wrongKey{ 4, 5, 6 }; + config.SetEncryptKey(wrongKey); + store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_EQ(store, nullptr); } /** @@ -280,9 +288,9 @@ HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_07, TestSize.Level1) int errCode; std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); EXPECT_NE(store, nullptr); - auto key = RdbSecurityManager::GetInstance().GetRdbPassword(RdbSecurityManager::KeyFileType::PUB_KEY_BAK_FILE); + auto key = RdbSecurityManager::GetInstance().GetRdbPassword(RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY); RdbPassword password = {}; - EXPECT_EQ(key, password); + EXPECT_NE(key, password); } /** @@ -301,6 +309,9 @@ HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_08, TestSize.Level1) int errCode; std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); EXPECT_NE(store, nullptr); + + errCode = RdbHelper::DeleteRdbStore(path); + EXPECT_EQ(errCode, E_OK); } /** @@ -324,7 +335,7 @@ HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_09, TestSize.Level1) EXPECT_EQ(ret, E_OK); EXPECT_EQ(distributedStatus, false); ret = RdbSecurityManager::GetInstance().GetKeyDistributedStatus( - RdbSecurityManager::KeyFileType::PUB_KEY_BAK_FILE, distributedStatus); + RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY, distributedStatus); EXPECT_EQ(ret, E_ERROR); EXPECT_EQ(distributedStatus, false); ret = RdbSecurityManager::GetInstance().SetKeyDistributedStatus( @@ -335,6 +346,6 @@ HWTEST_F(RdbEncryptTest, RdbStore_Encrypt_09, TestSize.Level1) EXPECT_EQ(ret, E_OK); EXPECT_EQ(distributedStatus, true); ret = RdbSecurityManager::GetInstance().SetKeyDistributedStatus( - RdbSecurityManager::KeyFileType::PUB_KEY_BAK_FILE, distributedStatus); + RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY, distributedStatus); EXPECT_EQ(ret, E_ERROR); } diff --git a/relational_store/test/native/rdb/unittest/rdb_execute_test.cpp b/relational_store/test/native/rdb/unittest/rdb_execute_test.cpp index cec0a0d9ab3741e978bd08e5e94703d53131c267..9b486e439cc3feaafda774019eef8f217a60aa5f 100644 --- a/relational_store/test/native/rdb/unittest/rdb_execute_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_execute_test.cpp @@ -35,12 +35,10 @@ public: static const std::string DATABASE_NAME; static std::shared_ptr store; - static const int E_SQLITE_ERROR; // errno SQLITE_ERROR }; const std::string RdbExecuteTest::DATABASE_NAME = RDB_TEST_PATH + "execute_test.db"; std::shared_ptr RdbExecuteTest::store = nullptr; -const int RdbExecuteTest::E_SQLITE_ERROR = -1; // errno SQLITE_ERROR class ExecuteTestOpenCallback : public RdbOpenCallback { public: diff --git a/relational_store/test/native/rdb/unittest/rdb_predicates_test.cpp b/relational_store/test/native/rdb/unittest/rdb_predicates_test.cpp index 4d055a38fd5892e66c3afb5a6abf3659337635c4..c9378919c465c6e65c2def46e084f1d59669dd3c 100644 --- a/relational_store/test/native/rdb/unittest/rdb_predicates_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_predicates_test.cpp @@ -1600,4 +1600,22 @@ HWTEST_F(RdbStorePredicateTest, RdbStore_InDevices_InAllDevices_026, TestSize.Le AbsRdbPredicates* absRdbPredicates1 = predicates.InAllDevices(); EXPECT_NE(absRdbPredicates1, nullptr); EXPECT_EQ(absRdbPredicates, absRdbPredicates1); +} + +/* * + * @tc.name: RdbStore_GetDistributedPredicates_027 + * @tc.desc: Normal testCase of RdbPredicates for GetDistributedPredicates method + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(RdbStorePredicateTest, RdbStore_GetDistributedPredicates_027, TestSize.Level1) +{ + RdbPredicates predicates("AllDataType"); + predicates.EqualTo("stringValue", "ABCDEFGHIJKLMN")->OrderByDesc("integerValue")->Limit(2); + auto distributedRdbPredicates = predicates.GetDistributedPredicates(); + EXPECT_EQ(distributedRdbPredicates.table_, "AllDataType"); + EXPECT_EQ(distributedRdbPredicates.operations_.size(), 3UL); + EXPECT_EQ(distributedRdbPredicates.operations_[0].operator_, OHOS::DistributedRdb::EQUAL_TO); + EXPECT_EQ(distributedRdbPredicates.operations_[0].field_, "stringValue"); + EXPECT_EQ(distributedRdbPredicates.operations_[0].values_[0], "ABCDEFGHIJKLMN"); } \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp b/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp index 8b3853db6efca9bc187065ffddfe4a760b022caf..f3c28b3300af0ba0a60d069ccd4413bcc470c466 100644 --- a/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_sqlite_shared_result_set_test.cpp @@ -36,12 +36,10 @@ public: static const std::string DATABASE_NAME; static std::shared_ptr store; - static const int E_SQLITE_ERROR; }; const std::string RdbSqliteSharedResultSetTest::DATABASE_NAME = RDB_TEST_PATH + "shared_test.db"; std::shared_ptr RdbSqliteSharedResultSetTest::store = nullptr; -const int RdbSqliteSharedResultSetTest::E_SQLITE_ERROR = -1; class SqliteSharedOpenCallback : public RdbOpenCallback { public: @@ -943,4 +941,76 @@ HWTEST_F(RdbSqliteSharedResultSetTest, Sqlite_Shared_Result_Set_018, TestSize.Le resultSet->Close(); bool closeFlag = resultSet->IsClosed(); EXPECT_EQ(closeFlag, true); +} + +/* * + * @tc.name: Sqlite_Shared_Result_Set_019 + * @tc.desc: normal testcase of SqliteSharedResultSet for GetRow + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbSqliteSharedResultSetTest, Sqlite_Shared_Result_Set_019, TestSize.Level1) +{ + GenerateDefaultTable(); + std::vector selectionArgs; + std::unique_ptr resultSet = + RdbSqliteSharedResultSetTest::store->QuerySql("SELECT * FROM test", selectionArgs); + EXPECT_NE(resultSet, nullptr); + + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + + int iRet = E_ERROR; + RowEntity rowEntity; + iRet = resultSet->GetRow(rowEntity); + EXPECT_EQ(E_OK, iRet); + + int idValue = rowEntity.Get("id"); + std::string data1Value = rowEntity.Get("data1"); + int data2Value = rowEntity.Get("data2"); + double data3Value = rowEntity.Get("data3"); + std::vector data4Value = rowEntity.Get("data4"); + EXPECT_EQ(1, idValue); + EXPECT_EQ("hello", data1Value); + EXPECT_EQ(10, data2Value); + EXPECT_EQ(1.0, data3Value); + EXPECT_EQ(66, data4Value[0]); + + int idValueByIndex = rowEntity.Get(0); + std::string data1ValueByIndex = rowEntity.Get(1); + int data2ValueByIndex = rowEntity.Get(2); + double data3ValueByIndex = rowEntity.Get(3); + std::vector data4ValueByIndex = rowEntity.Get(4); + EXPECT_EQ(1, idValueByIndex); + EXPECT_EQ("hello", data1ValueByIndex); + EXPECT_EQ(10, data2ValueByIndex); + EXPECT_EQ(1.0, data3ValueByIndex); + EXPECT_EQ(66, data4ValueByIndex[0]); +} + +/* * + * @tc.name: Sqlite_Shared_Result_Set_020 + * @tc.desc: normal testcase of SqliteSharedResultSet for GetRow + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbSqliteSharedResultSetTest, Sqlite_Shared_Result_Set_020, TestSize.Level1) +{ + GenerateDefaultTable(); + std::vector selectionArgs; + std::unique_ptr resultSet = + RdbSqliteSharedResultSetTest::store->QuerySql("SELECT data1, data2 FROM test", selectionArgs); + EXPECT_NE(resultSet, nullptr); + + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + + int iRet = E_ERROR; + RowEntity rowEntity; + iRet = resultSet->GetRow(rowEntity); + EXPECT_EQ(E_OK, iRet); + + std::string data1Value = rowEntity.Get("data1"); + EXPECT_EQ("hello", data1Value); + + std::string data1ValueByIndex = rowEntity.Get(0); + EXPECT_EQ("hello", data1ValueByIndex); } \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_step_result_get_row_test.cpp b/relational_store/test/native/rdb/unittest/rdb_step_result_get_row_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b564e018f37c08a91a57175c6e63d4180db3353 --- /dev/null +++ b/relational_store/test/native/rdb/unittest/rdb_step_result_get_row_test.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 + +#include + +#include "common.h" +#include "logger.h" +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" + +using namespace testing::ext; +using namespace OHOS::NativeRdb; + +class RdbStepResultSetGetRowTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + + static const std::string DATABASE_NAME; + static std::shared_ptr store; +}; + +const std::string RdbStepResultSetGetRowTest::DATABASE_NAME = RDB_TEST_PATH + "stepResultSet_getRow_test.db"; +std::shared_ptr RdbStepResultSetGetRowTest::store = nullptr; + +class RdbStepResultSetGetOpenCallback : public RdbOpenCallback { +public: + int OnCreate(RdbStore &rdbStore) override; + int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override; +}; + +int RdbStepResultSetGetOpenCallback::OnCreate(RdbStore &store) +{ + return E_OK; +} + +int RdbStepResultSetGetOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion) +{ + return E_OK; +} + +void RdbStepResultSetGetRowTest::SetUpTestCase(void) +{ + int errCode = E_OK; + RdbHelper::DeleteRdbStore(DATABASE_NAME); + RdbStoreConfig config(RdbStepResultSetGetRowTest::DATABASE_NAME); + RdbStepResultSetGetOpenCallback helper; + RdbStepResultSetGetRowTest::store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_NE(RdbStepResultSetGetRowTest::store, nullptr); + EXPECT_EQ(errCode, E_OK); +} + +void RdbStepResultSetGetRowTest::TearDownTestCase(void) +{ + RdbHelper::ClearCache(); + RdbHelper::DeleteRdbStore(RdbStepResultSetGetRowTest::DATABASE_NAME); +} + +void RdbStepResultSetGetRowTest::SetUp(void) +{ + store->ExecuteSql("CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, data1 TEXT, " + "data2 INTEGER, data3 FLOAT, data4 BLOB, data5 BOOLEAN);"); +} + +void RdbStepResultSetGetRowTest::TearDown(void) +{ + store->ExecuteSql("DROP TABLE IF EXISTS test"); +} + +/* * + * @tc.name: RdbStore_StepResultSet_GetRow_001 + * @tc.desc: test StepResultSet GetRow + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbStepResultSetGetRowTest, RdbStore_StepResultSet_GetRow_001, TestSize.Level1) +{ + int64_t rowId; + ValuesBucket valuesBucket; + valuesBucket.PutInt("id", ValueObject(1)); + int errorCode = RdbStepResultSetGetRowTest::store->Insert(rowId, "test", valuesBucket); + EXPECT_EQ(E_OK, errorCode); + EXPECT_EQ(1, rowId); + + std::unique_ptr resultSet = RdbStepResultSetGetRowTest::store->QueryByStep("SELECT * FROM test"); + EXPECT_NE(resultSet, nullptr); + + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + + int iRet = E_ERROR; + RowEntity rowEntity; + iRet = resultSet->GetRow(rowEntity); + EXPECT_EQ(E_OK, iRet); + + int idValue = rowEntity.Get("id"); + EXPECT_EQ(1, idValue); + + int idValueByIndex = rowEntity.Get(0); + EXPECT_EQ(1, idValueByIndex); + + resultSet->Close(); +} + +/* * + * @tc.name: RdbStore_StepResultSet_GetRow_002 + * @tc.desc: test StepResultSet GetRow + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbStepResultSetGetRowTest, RdbStore_StepResultSet_GetRow_002, TestSize.Level1) +{ + ValuesBucket valuesBucket; + valuesBucket.PutNull("data1"); + valuesBucket.PutNull("data2"); + valuesBucket.PutNull("data3"); + valuesBucket.PutNull("data4"); + valuesBucket.PutNull("data5"); + int64_t rowId; + int errorCode = RdbStepResultSetGetRowTest::store->Insert(rowId, "test", valuesBucket); + EXPECT_EQ(E_OK, errorCode); + EXPECT_EQ(1, rowId); + + std::unique_ptr resultSet = RdbStepResultSetGetRowTest::store->QueryByStep("SELECT * FROM test"); + EXPECT_NE(resultSet, nullptr); + + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + + int iRet = E_ERROR; + RowEntity rowEntity; + iRet = resultSet->GetRow(rowEntity); + EXPECT_EQ(E_OK, iRet); + + int idValue = rowEntity.Get("id"); + EXPECT_EQ(1, idValue); + + int idValueByIndex = rowEntity.Get(0); + EXPECT_EQ(1, idValueByIndex); + + resultSet->Close(); +} + +/* * + * @tc.name: RdbStore_StepResultSet_GetRow_003 + * @tc.desc: test StepResultSet GetRow + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbStepResultSetGetRowTest, RdbStore_StepResultSet_GetRow_003, TestSize.Level1) +{ + ValuesBucket valuesBucket; + valuesBucket.PutString("data1", "olleh"); + valuesBucket.PutInt("data2", 20); + valuesBucket.PutDouble("data3", 2.0); + valuesBucket.PutBlob("data4", { 4, 3, 2, 1 }); + valuesBucket.PutBool("data5", true); + int64_t rowId; + int errorCode = RdbStepResultSetGetRowTest::store->Insert(rowId, "test", valuesBucket); + EXPECT_EQ(E_OK, errorCode); + EXPECT_EQ(1, rowId); + + std::unique_ptr resultSet = RdbStepResultSetGetRowTest::store->QueryByStep("SELECT * FROM test"); + EXPECT_NE(resultSet, nullptr); + + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + + int iRet = E_ERROR; + RowEntity rowEntity; + iRet = resultSet->GetRow(rowEntity); + EXPECT_EQ(E_OK, iRet); + + int idValue = rowEntity.Get("id"); + std::string data1Value = rowEntity.Get("data1"); + int data2Value = rowEntity.Get("data2"); + double data3Value = rowEntity.Get("data3"); + std::vector data4Value = rowEntity.Get("data4"); + int data5Value = rowEntity.Get("data5"); + EXPECT_EQ(1, idValue); + EXPECT_EQ("olleh", data1Value); + EXPECT_EQ(20, data2Value); + EXPECT_EQ(2.0, data3Value); + EXPECT_EQ(1, data4Value[3]); + EXPECT_EQ(1, data5Value); + + int idValueByIndex = rowEntity.Get(0); + std::string data1ValueByIndex = rowEntity.Get(1); + int data2ValueByIndex = rowEntity.Get(2); + double data3ValueByIndex = rowEntity.Get(3); + std::vector data4ValueByIndex = rowEntity.Get(4); + int data5ValueByIndex = rowEntity.Get(5); + EXPECT_EQ(1, idValueByIndex); + EXPECT_EQ("olleh", data1ValueByIndex); + EXPECT_EQ(20, data2ValueByIndex); + EXPECT_EQ(2.0, data3ValueByIndex); + EXPECT_EQ(1, data4ValueByIndex[3]); + EXPECT_EQ(1, data5ValueByIndex); + + resultSet->Close(); +} + +/* * + * @tc.name: RdbStore_StepResultSet_GetRow_004 + * @tc.desc: test StepResultSet GetRow + * @tc.type: FUNC + * @tc.require: AR000FKD4F + */ +HWTEST_F(RdbStepResultSetGetRowTest, RdbStore_StepResultSet_GetRow_004, TestSize.Level1) +{ + ValuesBucket valuesBucket; + valuesBucket.PutString("data1", ""); + valuesBucket.PutInt("data2", 10); + valuesBucket.PutDouble("data3", 1.0); + valuesBucket.PutBlob("data4", { 1, 2, 3, 4 }); + valuesBucket.PutBool("data5", true); + int64_t rowId; + int errorCode = RdbStepResultSetGetRowTest::store->Insert(rowId, "test", valuesBucket); + EXPECT_EQ(E_OK, errorCode); + EXPECT_EQ(1, rowId); + + std::unique_ptr resultSet = + RdbStepResultSetGetRowTest::store->QueryByStep("SELECT data1, data2 FROM test"); + EXPECT_NE(resultSet, nullptr); + + EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + + int iRet = E_ERROR; + RowEntity rowEntity; + iRet = resultSet->GetRow(rowEntity); + EXPECT_EQ(E_OK, iRet); + + std::string data1Value = rowEntity.Get("data1"); + EXPECT_EQ("", data1Value); + + std::string data1ValueByIndex = rowEntity.Get(0); + EXPECT_EQ("", data1ValueByIndex); + + resultSet->Close(); +} \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp b/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp index 22ee3381459a8332ebb47ba69cf27a57fe95fa3e..3cd6e7b00169dbc469d02a090c58b6bc92896f3e 100644 --- a/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_step_result_set_test.cpp @@ -13,8 +13,10 @@ * limitations under the License. */ +#include #include #include + #include "common.h" #include "logger.h" #include "rdb_errno.h" @@ -35,14 +37,10 @@ public: static const std::string DATABASE_NAME; static std::shared_ptr store; - static const int E_SQLITE_ERROR; - static const int E_INVALID_COLUMN_TYPE; }; const std::string RdbStepResultSetTest::DATABASE_NAME = RDB_TEST_PATH + "stepResultSet_test.db"; std::shared_ptr RdbStepResultSetTest::store = nullptr; -const int RdbStepResultSetTest::E_SQLITE_ERROR = -1; // errno SQLITE_ERROR -const int RdbStepResultSetTest::E_INVALID_COLUMN_TYPE = 1009; // errno SQLITE_NULL class RdbStepResultSetOpenCallback : public RdbOpenCallback { public: @@ -137,12 +135,13 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_001, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT * FROM test"); EXPECT_NE(resultSet, nullptr); - bool bResultSet = false; + bool bResultSet = true; int iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); EXPECT_EQ(resultSet->GoTo(1), E_OK); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -216,17 +215,18 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_002, TestSize.Level1) resultSet->GetRowCount(count); EXPECT_EQ(3, count); - int position = -1; + int position = INT_MIN; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); - bool bResultSet = false; + bool bResultSet = true; resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(bResultSet, false); EXPECT_EQ(E_OK, resultSet->GoToRow(2)); + bResultSet = false; iRet = resultSet->IsAtLastRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(true, bResultSet); @@ -239,14 +239,17 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_002, TestSize.Level1) EXPECT_EQ(E_OK, resultSet->GoToLastRow()); + bResultSet = false; iRet = resultSet->IsAtLastRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(true, bResultSet); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = true; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -264,8 +267,8 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_003, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT * FROM test"); EXPECT_NE(resultSet, nullptr); - int position = -1; - bool bResultSet = false; + int position = INT_MIN; + bool bResultSet = true; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); @@ -274,10 +277,12 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_003, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -290,14 +295,17 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_003, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(0, position); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = true; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -314,14 +322,17 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_003, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); + bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = false; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -339,8 +350,8 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_004, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT data1, data2, data3, data4 FROM test"); EXPECT_NE(resultSet, nullptr); - int position = -1; - bool bResultSet = false; + int position = INT_MIN; + bool bResultSet = true; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); @@ -349,6 +360,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_004, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -359,10 +371,12 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_004, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); + bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -382,7 +396,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_005, TestSize.Level1) EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); - int position = -1; + int position = INT_MIN; bool bResultSet = false; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); @@ -392,6 +406,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_005, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -401,10 +416,12 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_005, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(0, position); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -412,10 +429,12 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_005, TestSize.Level1) EXPECT_EQ(E_OK, resultSet->GoToNextRow()); EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -435,8 +454,8 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_006, TestSize.Level1) EXPECT_NE(E_OK, resultSet->GoToFirstRow()); - int position = -1; - bool bResultSet = false; + int position = INT_MIN; + bool bResultSet = true; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); @@ -445,6 +464,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_006, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -452,10 +472,12 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_006, TestSize.Level1) EXPECT_NE(E_OK, resultSet->GoToNextRow()); EXPECT_NE(E_OK, resultSet->GoToFirstRow()); + bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -476,8 +498,8 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_007, TestSize.Level1) int moveTimes = 0; EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); moveTimes++; - int position = -1; - bool bResultSet = false; + int position = INT_MIN; + bool bResultSet = true; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(0, position); @@ -493,6 +515,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_007, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); + bResultSet = false; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -513,7 +536,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_008, TestSize.Level1) EXPECT_NE(E_OK, resultSet->GoToFirstRow()); moveTimes++; - int position = -1; + int position = INT_MIN; bool bResultSet = false; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); @@ -530,6 +553,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_008, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); + bResultSet = false; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -888,6 +912,7 @@ HWTEST_F(RdbStepResultSetTest, RdbStore_StepResultSet_016, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -915,7 +940,7 @@ HWTEST_F(RdbStepResultSetTest, testGetRowCount003, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT * FROM test"); EXPECT_NE(resultSet, nullptr); - bool bResultSet = false; + bool bResultSet = true; int iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -926,6 +951,7 @@ HWTEST_F(RdbStepResultSetTest, testGetRowCount003, TestSize.Level1) EXPECT_EQ(3, count); EXPECT_EQ(E_OK, resultSet->GoToNextRow()); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -963,7 +989,7 @@ HWTEST_F(RdbStepResultSetTest, testGetRowCount003, TestSize.Level1) EXPECT_EQ(3, count); EXPECT_EQ(E_OK, resultSet->GoToNextRow()); - int position = -1; + int position = INT_MIN; iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(1, position); @@ -1005,12 +1031,13 @@ HWTEST_F(RdbStepResultSetTest, testGetRowCount004, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT data1, data2, data3, data4 FROM test"); EXPECT_NE(resultSet, nullptr); - bool bResultSet = false; + bool bResultSet = true; int iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); EXPECT_EQ(E_OK, resultSet->GoToNextRow()); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -1050,7 +1077,7 @@ HWTEST_F(RdbStepResultSetTest, testGetRowCount004, TestSize.Level1) EXPECT_EQ(E_OK, resultSet->GoToNextRow()); - int position = -1; + int position = INT_MIN; iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(1, position); @@ -1093,17 +1120,18 @@ HWTEST_F(RdbStepResultSetTest, testGoToRow005, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT data1, data2, data3, data4 FROM test"); EXPECT_NE(resultSet, nullptr); - bool bResultSet = false; + bool bResultSet = true; int iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); EXPECT_EQ(E_OK, resultSet->GoToNextRow()); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); - int position = -1; + int position = INT_MIN; iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(0, position); @@ -1167,7 +1195,7 @@ HWTEST_F(RdbStepResultSetTest, testGo006, TestSize.Level1) GenerateDefaultTable(); std::unique_ptr resultSet = store->QueryByStep("SELECT * FROM test"); EXPECT_NE(resultSet, nullptr); - int position = -1; + int position = INT_MIN; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); @@ -1252,13 +1280,14 @@ HWTEST_F(RdbStepResultSetTest, testGoToPrevious007, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(3, count); - bool bResultSet = false; + bool bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -1295,11 +1324,12 @@ HWTEST_F(RdbStepResultSetTest, testGoToPrevious007, TestSize.Level1) int ret = resultSet->GoToPreviousRow(); EXPECT_NE(E_OK, ret); - int position = -1; + int position = INT_MIN; iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); + bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -1323,6 +1353,7 @@ HWTEST_F(RdbStepResultSetTest, testGoToPrevious007, TestSize.Level1) EXPECT_EQ(E_OK, resultSet->GoToLastRow()); + bResultSet = false; iRet = resultSet->IsAtLastRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(true, bResultSet); @@ -1339,6 +1370,7 @@ HWTEST_F(RdbStepResultSetTest, testGoToPrevious007, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); + bResultSet = false; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -1356,13 +1388,14 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep008, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT data1, data2, data3, data4 FROM test"); EXPECT_NE(resultSet, nullptr); - bool bResultSet = false; + bool bResultSet = true; int iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); EXPECT_EQ(E_OK, resultSet->GoTo(1)); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); @@ -1387,7 +1420,7 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep008, TestSize.Level1) EXPECT_EQ(E_OK, resultSet->GoToFirstRow()); EXPECT_EQ(E_OK, resultSet->GoToNextRow()); - int position = -1; + int position = INT_MIN; iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(1, position); @@ -1435,18 +1468,19 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep009, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(3, count); - int position = -1; + int position = INT_MIN; iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); - bool bResultSet = false; + bool bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); EXPECT_EQ(E_OK, resultSet->GoToRow(2)); + bResultSet = false; iRet = resultSet->IsAtLastRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(true, bResultSet); @@ -1459,18 +1493,22 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep009, TestSize.Level1) EXPECT_EQ(E_OK, resultSet->GoToLastRow()); + bResultSet = false; iRet = resultSet->IsAtLastRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(true, bResultSet); + bResultSet = false; iRet = resultSet->IsAtLastRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(true, bResultSet); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = true; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -1488,19 +1526,21 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep010, TestSize.Level1) std::unique_ptr resultSet = store->QueryByStep("SELECT data1, data2, data3, data4 FROM test"); EXPECT_NE(resultSet, nullptr); - int position = -1; + int position = INT_MIN; int iRet = resultSet->GetRowIndex(position); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); - bool bResultSet = false; + bool bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -1513,14 +1553,17 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep010, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(0, position); + bResultSet = false; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = false; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); + bResultSet = true; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); @@ -1533,14 +1576,17 @@ HWTEST_F(RdbStepResultSetTest, testSqlStep010, TestSize.Level1) EXPECT_EQ(E_OK, iRet); EXPECT_EQ(-1, position); + bResultSet = true; iRet = resultSet->IsStarted(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = true; iRet = resultSet->IsAtFirstRow(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, false); + bResultSet = false; iRet = resultSet->IsEnded(bResultSet); EXPECT_EQ(E_OK, iRet); EXPECT_EQ(bResultSet, true); diff --git a/relational_store/test/native/rdb/unittest/rdb_store_config_test.cpp b/relational_store/test/native/rdb/unittest/rdb_store_config_test.cpp index 74d88c166d1f697d2be35b9859d70b74580673b4..8c41c97cb81542b0727be8a188f560df51f92c71 100644 --- a/relational_store/test/native/rdb/unittest/rdb_store_config_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_store_config_test.cpp @@ -73,6 +73,7 @@ void RdbStoreConfigTest::SetUp(void) void RdbStoreConfigTest::TearDown(void) { + RdbHelper::DeleteRdbStore(RDB_TEST_PATH + "config_test.db"); RdbHelper::ClearCache(); } @@ -247,7 +248,7 @@ HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_006, TestSize.Level1) std::string currentMode; int ret = store->ExecuteAndGetString(currentMode, "PRAGMA journal_mode"); EXPECT_EQ(ret, E_OK); - EXPECT_EQ(currentMode, "wal"); + EXPECT_EQ(currentMode, "delete"); } /** @@ -756,7 +757,7 @@ HWTEST_F(RdbStoreConfigTest, RdbStoreConfig_025, TestSize.Level1) retEncryptAlgo = config.GetEncryptAlgo(); EXPECT_EQ("", retEncryptAlgo); store = RdbHelper::GetRdbStore(config, 1, helper, errCode); - EXPECT_EQ(store, nullptr); + EXPECT_NE(store, nullptr); } /** diff --git a/relational_store/test/native/rdb/unittest/rdb_store_rekey_test.cpp b/relational_store/test/native/rdb/unittest/rdb_store_rekey_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab96934f7b2c9d831ca6830c0dcfaf4921ba7537 --- /dev/null +++ b/relational_store/test/native/rdb/unittest/rdb_store_rekey_test.cpp @@ -0,0 +1,327 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* 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 +#include +#include + +#include "common.h" +#include "file_ex.h" +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" +#include "rdb_security_manager.h" +#include "sqlite_database_utils.h" + +using namespace testing::ext; +using namespace OHOS::NativeRdb; +class RdbRekeyTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp() override; + void TearDown() override; + + static std::string RemoveSuffix(const std::string &name); + static std::chrono::system_clock::time_point GetKeyFileDate(const std::string &dbName); + static bool ChangeKeyFileDate(const std::string &dbName, int rep); + static RdbStoreConfig GetRdbConfig(const std::string &name); + static void InsertData(std::shared_ptr &store); + static void CheckQueryData(std::shared_ptr &store); + + static const std::string encryptedDatabaseName; + static const std::string encryptedDatabasePath; + static const std::string encryptedDatabaseKeyDir; + static const std::string encryptedDatabaseMockName; + static const std::string encryptedDatabaseMockPath; + static constexpr int HOURS_EXPIRED = (24 * 365) + 1; + static constexpr int HOURS_NOT_EXPIRED = (24 * 30); +}; + +const std::string RdbRekeyTest::encryptedDatabaseName = "encrypted.db"; +const std::string RdbRekeyTest::encryptedDatabasePath = RDB_TEST_PATH + encryptedDatabaseName; +const std::string RdbRekeyTest::encryptedDatabaseKeyDir = RDB_TEST_PATH + "key/"; +const std::string RdbRekeyTest::encryptedDatabaseMockName = "encrypted_mock.db"; +const std::string RdbRekeyTest::encryptedDatabaseMockPath = RDB_TEST_PATH + encryptedDatabaseMockName; + +class RekeyTestOpenCallback : public RdbOpenCallback { +public: + int OnCreate(RdbStore &store) override; + int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override; + static const std::string createTableTest; +}; + +std::string const RekeyTestOpenCallback::createTableTest = "CREATE TABLE IF NOT EXISTS test " + "(id INTEGER PRIMARY KEY " + "AUTOINCREMENT, " + "name TEXT NOT NULL, age INTEGER, " + "salary " + "REAL, blobType BLOB)"; + +int RekeyTestOpenCallback::OnCreate(RdbStore &store) +{ + return store.ExecuteSql(createTableTest); +} + +int RekeyTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion) +{ + return E_OK; +} + +void RdbRekeyTest::SetUpTestCase() {} + +void RdbRekeyTest::TearDownTestCase() {} + +void RdbRekeyTest::SetUp() +{ + RdbStoreConfig config = GetRdbConfig(encryptedDatabasePath); + RekeyTestOpenCallback helper; + int errCode; + std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + EXPECT_NE(store, nullptr); + InsertData(store); + store.reset(); + RdbHelper::ClearCache(); +} + +void RdbRekeyTest::TearDown() +{ + RdbHelper::ClearCache(); + RdbHelper::DeleteRdbStore(RdbRekeyTest::encryptedDatabasePath); +} + +std::string RdbRekeyTest::RemoveSuffix(const string &name) +{ + std::string suffix(".db"); + auto pos = name.rfind(suffix); + if (pos == std::string::npos || pos < name.length() - suffix.length()) { + return name; + } + return { name, 0, pos }; +} + +std::chrono::system_clock::time_point RdbRekeyTest::GetKeyFileDate(const std::string &dbName) +{ + std::chrono::system_clock::time_point timePoint; + std::string name = RemoveSuffix(dbName); + auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key"; + if (!OHOS::FileExists(keyPath)) { + return timePoint; + } + std::vector content; + auto loaded = OHOS::LoadBufferFromFile(keyPath, content); + if (!loaded) { + return timePoint; + } + auto iter = content.begin(); + iter++; + constexpr uint32_t dateFileLength = sizeof(time_t) / sizeof(uint8_t); + std::vector date; + date.assign(iter, iter + dateFileLength); + timePoint = std::chrono::system_clock::from_time_t(*reinterpret_cast(const_cast(&date[0]))); + return timePoint; +} + +bool RdbRekeyTest::ChangeKeyFileDate(const std::string &dbName, int rep) +{ + std::string name = RemoveSuffix(dbName); + auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key"; + if (!OHOS::FileExists(keyPath)) { + return false; + } + std::vector content; + auto loaded = OHOS::LoadBufferFromFile(keyPath, content); + if (!loaded) { + return false; + } + auto time = + std::chrono::system_clock::to_time_t(std::chrono::system_clock::system_clock::now() - std::chrono::hours(rep)); + std::vector date(reinterpret_cast(&time), reinterpret_cast(&time) + sizeof(time)); + std::copy(date.begin(), date.end(), ++content.begin()); + + auto saved = OHOS::SaveBufferToFile(keyPath, content); + return saved; +} + +RdbStoreConfig RdbRekeyTest::GetRdbConfig(const std::string &name) +{ + RdbStoreConfig config(name); + config.SetEncryptStatus(true); + config.SetBundleName("com.example.test_rekey"); + return config; +} + +void RdbRekeyTest::InsertData(std::shared_ptr &store) +{ + int64_t id; + ValuesBucket values; + std::string name = "zhangsan"; + int age = 18; + double salary = 100.5; + std::vector blob{ 1, 2, 3 }; + values.PutString("name", name); + values.PutInt("age", age); + values.PutDouble("salary", salary); + values.PutBlob("blobType", blob); + int insertRet = store->Insert(id, "test", values); + EXPECT_EQ(insertRet, E_OK); +} + +void RdbRekeyTest::CheckQueryData(std::shared_ptr &store) +{ + std::unique_ptr resultSet = + store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector{ "zhangsan" }); + EXPECT_NE(resultSet, nullptr); + int result = resultSet->GoToFirstRow(); + EXPECT_EQ(result, E_OK); + int columnIndex; + std::string strVal; + ColumnType columnType; + result = resultSet->GetColumnIndex("name", columnIndex); + EXPECT_EQ(result, E_OK); + result = resultSet->GetColumnType(columnIndex, columnType); + EXPECT_EQ(result, E_OK); + EXPECT_EQ(columnType, ColumnType::TYPE_STRING); + result = resultSet->GetString(columnIndex, strVal); + EXPECT_EQ(result, E_OK); + EXPECT_EQ("zhangsan", strVal); + + result = resultSet->Close(); + EXPECT_EQ(result, E_OK); +} + +/** +* @tc.name: Rdb_Rekey_Test_001 +* @tc.desc: test RdbStore rekey function +* @tc.type: FUNC +*/ +HWTEST_F(RdbRekeyTest, Rdb_Rekey_01, TestSize.Level1) +{ + std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key"; + std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new"; + + bool isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + + bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_EXPIRED); + ASSERT_TRUE(isFileDateChanged); + + auto changedDate = GetKeyFileDate(encryptedDatabaseName); + ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_EXPIRED)); + + RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath); + RekeyTestOpenCallback helper; + int errCode; + std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + ASSERT_NE(store, nullptr); + + isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + isFileExists = OHOS::FileExists(newKeyPath); + ASSERT_FALSE(isFileExists); + + auto newDate = GetKeyFileDate(encryptedDatabaseName); + ASSERT_TRUE(std::chrono::system_clock::now() - newDate < std::chrono::seconds(2)); + CheckQueryData(store); +} + +/** +* @tc.name: Rdb_Rekey_Test_002 +* @tc.desc: test RdbStore with not outdated password +* @tc.type: FUNC +*/ +HWTEST_F(RdbRekeyTest, Rdb_Rekey_02, TestSize.Level1) +{ + std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key"; + bool isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + + bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_NOT_EXPIRED); + ASSERT_TRUE(isFileDateChanged); + + auto changedDate = GetKeyFileDate(encryptedDatabaseName); + ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_NOT_EXPIRED)); + + RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath); + RekeyTestOpenCallback helper; + int errCode; + std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + ASSERT_NE(store, nullptr); + CheckQueryData(store); +} + +/** +* @tc.name: Rdb_Rekey_Test_003 +* @tc.desc: try to open store and execute RekeyRecover() without key and new key files. +* @tc.type: FUNC +*/ +HWTEST_F(RdbRekeyTest, Rdb_Rekey_03, TestSize.Level1) +{ + std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key"; + std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new"; + + bool isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + + SqliteDatabaseUtils::DeleteFile(keyPath); + isFileExists = OHOS::FileExists(keyPath); + ASSERT_FALSE(isFileExists); + isFileExists = OHOS::FileExists(newKeyPath); + ASSERT_FALSE(isFileExists); + + RekeyTestOpenCallback helper; + int errCode; + RdbStoreConfig config = GetRdbConfig(encryptedDatabasePath); + std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + ASSERT_EQ(store, nullptr); +} + +/** +* @tc.name: Rdb_Rekey_Test_004 +* @tc.desc: try to open store and modify create date to a future time. +* @tc.type: FUNC +*/ +HWTEST_F(RdbRekeyTest, Rdb_Rekey_04, TestSize.Level1) +{ + std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key"; + std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new"; + + bool isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + + auto keyFileDate = GetKeyFileDate(encryptedDatabaseName); + + bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, -RdbRekeyTest::HOURS_EXPIRED); + ASSERT_TRUE(isFileDateChanged); + + auto changedDate = GetKeyFileDate(encryptedDatabaseName); + ASSERT_GT(changedDate, keyFileDate); + + RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath); + RekeyTestOpenCallback helper; + int errCode; + std::shared_ptr store = RdbHelper::GetRdbStore(config, 1, helper, errCode); + ASSERT_NE(store, nullptr); + + isFileExists = OHOS::FileExists(keyPath); + ASSERT_TRUE(isFileExists); + isFileExists = OHOS::FileExists(newKeyPath); + ASSERT_FALSE(isFileExists); + + keyFileDate = GetKeyFileDate(encryptedDatabaseName); + ASSERT_EQ(changedDate, keyFileDate); + + CheckQueryData(store); +} \ No newline at end of file diff --git a/relational_store/test/native/rdb/unittest/rdb_transaction_test.cpp b/relational_store/test/native/rdb/unittest/rdb_transaction_test.cpp index 665328fa7494da44d8ce7df2300a383ed11b32b1..bda1219aa99a75f816c62c1d798460ede22a705d 100644 --- a/relational_store/test/native/rdb/unittest/rdb_transaction_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_transaction_test.cpp @@ -15,6 +15,7 @@ #include +#include #include #include "common.h" @@ -35,12 +36,10 @@ public: static const std::string DATABASE_NAME; static std::shared_ptr store; - static const int E_SQLITE_ERROR; // errno SQLITE_ERROR }; const std::string RdbTransactionTest::DATABASE_NAME = RDB_TEST_PATH + "transaction_test.db"; std::shared_ptr RdbTransactionTest::store = nullptr; -const int RdbTransactionTest::E_SQLITE_ERROR = -1; // errno SQLITE_ERROR class TransactionTestOpenCallback : public RdbOpenCallback { public: @@ -675,7 +674,7 @@ HWTEST_F(RdbTransactionTest, RdbStore_BatchInsert_003, TestSize.Level1) valuesBuckets.push_back(std::move(values)); } - number = -1; + number = INT_MIN; error = store->BatchInsert(number, "test", valuesBuckets); EXPECT_EQ(E_OK, error); EXPECT_EQ(-1, number); diff --git a/relational_store/test/native/rdb/unittest/rdb_value_bucket_test.cpp b/relational_store/test/native/rdb/unittest/rdb_value_bucket_test.cpp index 361653cdc3c3d7174d177edb5768d6dbe0b93d28..f295f31d33bb3e1c0c1d31c21a3be3c74277833b 100644 --- a/relational_store/test/native/rdb/unittest/rdb_value_bucket_test.cpp +++ b/relational_store/test/native/rdb/unittest/rdb_value_bucket_test.cpp @@ -14,16 +14,16 @@ */ #include - #include +#include "itypes_util.h" #include "logger.h" #include "message_parcel.h" #include "parcel.h" +#include "parser.h" +#include "sqlite_global_config.h" #include "value_object.h" #include "values_bucket.h" -#include "itypes_util.h" - using namespace testing::ext; using namespace OHOS; using namespace OHOS::NativeRdb; @@ -166,7 +166,6 @@ HWTEST_F(ValuesBucketTest, Values_Bucket_002, TestSize.Level1) HWTEST_F(ValuesBucketTest, Values_Bucket_003, TestSize.Level1) { ValuesBucket values; - std::map getAllValuesMap; values.PutInt("id", 1); values.PutString("name", std::string("zhangsan")); values.PutLong("No.", 9223372036854775807L); @@ -175,11 +174,6 @@ HWTEST_F(ValuesBucketTest, Values_Bucket_003, TestSize.Level1) values.PutBlob("codes", std::vector{ 1, 2, 3 }); values.PutNull("mark"); - values.GetAll(getAllValuesMap); - EXPECT_EQ(7, getAllValuesMap.size()); - getAllValuesMap.clear(); - EXPECT_EQ(true, getAllValuesMap.empty()); - EXPECT_EQ(7, values.Size()); values.Clear(); EXPECT_EQ(true, values.IsEmpty()); @@ -242,3 +236,82 @@ HWTEST_F(ValuesBucketTest, Values_Object_001, TestSize.Level1) std::vector retVectorUint8 = ValueObject(valueVectorUint8); EXPECT_EQ(valueVectorUint8, retVectorUint8); } + +/** + * @tc.name: Convert from subset + * @tc.desc: test ValuesObject operator + * @tc.type: FUNC + */ +HWTEST_F(ValuesBucketTest, Convert_From_Subset, TestSize.Level1) +{ + ValueObject::Type output = AssetValue(); + using Type = std::variant>; + Type input; + Parser::Convert(input, output); + auto *nil = std::get_if(&output); + EXPECT_TRUE(nil != nullptr); + input = int64_t(54); + Parser::Convert(input, output); + auto *number = std::get_if(&output); + EXPECT_TRUE(number != nullptr); + EXPECT_TRUE(*number == 54); + input = double(1.1); + Parser::Convert(input, output); + auto *real = std::get_if(&output); + EXPECT_TRUE(real != nullptr); + input = std::string("my test"); + Parser::Convert(input, output); + auto *text = std::get_if(&output); + EXPECT_TRUE(text != nullptr); + EXPECT_TRUE(*text == "my test"); + input = std::vector(10, 'm'); + Parser::Convert(input, output); + auto *blob = std::get_if>(&output); + EXPECT_TRUE(blob != nullptr); + EXPECT_TRUE(*blob == std::vector(10, 'm')); +} + +/** + * @tc.name: Convert to subset + * @tc.desc: test ValuesObject operator + * @tc.type: FUNC + */ +HWTEST_F(ValuesBucketTest, Convert_To_Subset, TestSize.Level1) +{ + using Type = std::variant>; + Type output; + ValueObject::Type input; + Parser::Convert(input, output); + auto *nil = std::get_if(&output); + EXPECT_TRUE(nil != nullptr); + input = int64_t(54); + Parser::Convert(input, output); + auto *number = std::get_if(&output); + EXPECT_TRUE(number != nullptr); + EXPECT_TRUE(*number == 54); + input = double(1.1); + Parser::Convert(input, output); + auto *real = std::get_if(&output); + EXPECT_TRUE(real != nullptr); + input = std::string("my test"); + Parser::Convert(input, output); + auto *text = std::get_if(&output); + EXPECT_TRUE(text != nullptr); + EXPECT_TRUE(*text == "my test"); + input = std::vector(10, 'm'); + Parser::Convert(input, output); + auto *blob = std::get_if>(&output); + EXPECT_TRUE(blob != nullptr); + EXPECT_TRUE(*blob == std::vector(10, 'm')); + AssetValue value{.version = 0, .name = "123", .uri = "my test path", .createTime = "12", .modifyTime = "12"}; + input = value ; + output = {}; + Parser::Convert(input, output); + nil = std::get_if(&output); + EXPECT_TRUE(nil != nullptr); + input = std::vector(10, value); + output = {}; + Parser::Convert(input, output); + nil = std::get_if(&output); + EXPECT_TRUE(nil != nullptr); +} \ No newline at end of file diff --git a/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp b/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp index 21eb06cae2d4189a33f24368a6d005cb7118b34f..96fda84dd6f11cf3c0478e1b9ccc6d295ce7a00c 100644 --- a/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp +++ b/relational_store/test/native/rdb_data_share_adapter/unittest/rdb_data_share_adapter_test.cpp @@ -44,17 +44,11 @@ public: static const std::string DATABASE_NAME; static std::shared_ptr store; - static const int E_SQLITE_ERROR; - static const int E_INVALID_COLUMN_TYPE; - static const size_t DEFAULT_BLOCK_SIZE; static const std::string RDB_ADAPTER_TEST_PATH; }; const std::string RdbDataShareAdapterTest::RDB_ADAPTER_TEST_PATH = "/data/test/"; const std::string RdbDataShareAdapterTest::DATABASE_NAME = RDB_ADAPTER_TEST_PATH + "rdbDataShareAdapter_test.db"; -const int RdbDataShareAdapterTest::E_SQLITE_ERROR = -1; // errno SQLITE_ERROR -const int RdbDataShareAdapterTest::E_INVALID_COLUMN_TYPE = 1009; // errno SQLITE_NULL -const size_t RdbDataShareAdapterTest::DEFAULT_BLOCK_SIZE = 2 * 1024 * 1024; std::shared_ptr RdbDataShareAdapterTest::store = nullptr; class RdbStepSharedResultSetOpenCallback : public RdbOpenCallback { diff --git a/test/include/CMakeLists.txt b/test/include/CMakeLists.txt index c46a8d0f0d36cbf181daf0f137c40131404a294f..3b964f9c86703396dcd0d2f3d4bdcd93c3aac61d 100644 --- a/test/include/CMakeLists.txt +++ b/test/include/CMakeLists.txt @@ -40,6 +40,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/interfaces/i include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/interfaces/inner_api/dataability/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/interfaces/inner_api/rdb/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/interfaces/inner_api/rdb_data_share_adapter/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/interfaces/inner_api/rdb_device_manager_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../relational_store/frameworks/native/rdb_data_share_adapter/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../data_share/interfaces/inner_api/common/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../data_share/interfaces/inner_api/consumer/include)