• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define LOG_TAG "RdbSqlUtils"
17 #include "rdb_sql_utils.h"
18 
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 #include <algorithm>
23 #include <cstdio>
24 
25 #include "acl.h"
26 #include "logger.h"
27 #include "rdb_errno.h"
28 #include "rdb_platform.h"
29 #include "sqlite_sql_builder.h"
30 #include "sqlite_utils.h"
31 #include "rdb_fault_hiview_reporter.h"
32 
33 namespace OHOS {
34 using namespace Rdb;
35 namespace NativeRdb {
36 using namespace OHOS::DATABASE_UTILS;
37 constexpr int32_t SERVICE_GID = 3012;
CreateDirectory(const std::string & databaseDir)38 int RdbSqlUtils::CreateDirectory(const std::string &databaseDir)
39 {
40     std::string tempDirectory = databaseDir;
41     std::vector<std::string> directories;
42 
43     size_t pos = tempDirectory.find('/');
44     while (pos != std::string::npos) {
45         std::string directory = tempDirectory.substr(0, pos);
46         directories.push_back(directory);
47         tempDirectory = tempDirectory.substr(pos + 1);
48         pos = tempDirectory.find('/');
49     }
50     directories.push_back(tempDirectory);
51 
52     std::string databaseDirectory;
53     for (const std::string &directory : directories) {
54         databaseDirectory = databaseDirectory + "/" + directory;
55         if (access(databaseDirectory.c_str(), F_OK) != 0) {
56             if (MkDir(databaseDirectory)) {
57                 LOG_ERROR("failed to mkdir errno[%{public}d] %{public}s, parent dir modes: %{public}s", errno,
58                     SqliteUtils::Anonymous(databaseDirectory).c_str(),
59                     SqliteUtils::GetParentModes(databaseDirectory).c_str());
60                 RdbFaultHiViewReporter::ReportFault(RdbFaultEvent(FT_EX_FILE, E_CREATE_FOLDER_FAIL, BUNDLE_NAME_COMMON,
61                     "failed to mkdir errno[ " + std::to_string(errno) + "]," + databaseDirectory +
62                         "parent dir modes:" + SqliteUtils::GetParentModes(databaseDirectory)));
63                 return E_CREATE_FOLDER_FAIL;
64             }
65             // Set the default ACL attribute to the database root directory to ensure that files created by the server
66             // also have permission to operate on the client side.
67             Acl acl(databaseDirectory);
68             acl.SetDefaultUser(GetUid(), Acl::R_RIGHT | Acl::W_RIGHT);
69             acl.SetDefaultGroup(SERVICE_GID, Acl::R_RIGHT | Acl::W_RIGHT);
70         }
71     }
72     return E_OK;
73 }
74 
GetCustomDatabasePath(const std::string & rootDir,const std::string & name,const std::string & customDir)75 std::pair<std::string, int> RdbSqlUtils::GetCustomDatabasePath(
76     const std::string &rootDir, const std::string &name, const std::string &customDir)
77 {
78     std::string databasePath;
79     databasePath.append(rootDir).append("/").append(customDir).append("/").append(name);
80 
81     struct stat fileStat;
82     if (stat(databasePath.c_str(), &fileStat) != 0) {
83         LOG_ERROR("File state error. path: %{public}s, errno: %{public}d",
84             SqliteUtils::Anonymous(databasePath).c_str(), errno);
85         return std::make_pair("", E_INVALID_FILE_PATH);
86     }
87     return std::make_pair(databasePath, E_OK);
88 }
89 
90 /**
91  * @brief get custom data base path.
92  */
GetDefaultDatabasePath(const std::string & baseDir,const std::string & name,const std::string & customDir)93 std::pair<std::string, int> RdbSqlUtils::GetDefaultDatabasePath(
94     const std::string &baseDir, const std::string &name, const std::string &customDir)
95 {
96     int errorCode = E_OK;
97     if (customDir.empty()) {
98         return std::make_pair(GetDefaultDatabasePath(baseDir, name, errorCode), errorCode);
99     }
100 
101     std::string databaseDir;
102     databaseDir.append(baseDir).append("/rdb/").append(customDir);
103 
104     errorCode = CreateDirectory(databaseDir);
105     if (errorCode != E_OK) {
106         LOG_ERROR("failed errno[%{public}d] baseDir : %{public}s name : %{public}s customDir : %{public}s", errno,
107             SqliteUtils::Anonymous(baseDir).c_str(), SqliteUtils::Anonymous(name).c_str(),
108             SqliteUtils::Anonymous(customDir).c_str());
109     }
110     return std::make_pair(databaseDir.append("/").append(name), errorCode);
111 }
112 
113 /**
114  * Get and Check default path.
115  */
GetDefaultDatabasePath(const std::string & baseDir,const std::string & name,int & errorCode)116 std::string RdbSqlUtils::GetDefaultDatabasePath(const std::string &baseDir, const std::string &name, int &errorCode)
117 {
118     std::string databaseDir = baseDir + "/rdb";
119     errorCode = CreateDirectory(databaseDir);
120     if (errorCode != E_OK) {
121         LOG_ERROR("failed errno[%{public}d] baseDir : %{public}s name : %{public}s", errno,
122             SqliteUtils::Anonymous(baseDir).c_str(), SqliteUtils::Anonymous(name).c_str());
123     }
124     return databaseDir.append("/").append(name);
125 }
126 
BuildQueryString(const AbsRdbPredicates & predicates,const std::vector<std::string> & columns)127 std::string RdbSqlUtils::BuildQueryString(const AbsRdbPredicates &predicates, const std::vector<std::string> &columns)
128 {
129     return SqliteSqlBuilder::BuildQueryString(predicates, columns);
130 }
131 
GetInsertSqlInfo(const std::string & table,const Row & row,Resolution resolution)132 std::pair<int, SqlInfo> RdbSqlUtils::GetInsertSqlInfo(const std::string &table, const Row &row, Resolution resolution)
133 {
134     SqlInfo sqlInfo;
135     if (table.empty()) {
136         return std::make_pair(E_EMPTY_TABLE_NAME, sqlInfo);
137     }
138 
139     if (row.IsEmpty()) {
140         return std::make_pair(E_EMPTY_VALUES_BUCKET, sqlInfo);
141     }
142 
143     auto conflictClause = SqliteUtils::GetConflictClause(static_cast<int>(resolution));
144     if (conflictClause == nullptr) {
145         return std::make_pair(E_INVALID_CONFLICT_FLAG, sqlInfo);
146     }
147     std::string sql;
148     sql.append("INSERT").append(conflictClause).append(" INTO ").append(table).append("(");
149     size_t bindArgsSize = row.values_.size();
150     std::vector<ValueObject> bindArgs;
151     bindArgs.reserve(bindArgsSize);
152     const char *split = "";
153     for (const auto &[key, val] : row.values_) {
154         sql.append(split).append(key);
155         if (val.GetType() == ValueObject::TYPE_ASSETS && resolution == ConflictResolution::ON_CONFLICT_REPLACE) {
156             return std::make_pair(E_INVALID_ARGS, sqlInfo);
157         }
158         SqliteSqlBuilder::UpdateAssetStatus(val, AssetValue::STATUS_INSERT);
159         bindArgs.push_back(val); // columnValue
160         split = ",";
161     }
162 
163     sql.append(") VALUES (");
164     if (bindArgsSize > 0) {
165         sql.append(SqliteSqlBuilder::GetSqlArgs(bindArgsSize));
166     }
167 
168     sql.append(")");
169     sqlInfo.sql = std::move(sql);
170     sqlInfo.args = std::move(bindArgs);
171     return std::make_pair(E_OK, sqlInfo);
172 }
173 
GetUpdateSqlInfo(const AbsRdbPredicates & predicates,const Row & row,Resolution resolution,const std::vector<std::string> & returningFields)174 std::pair<int, SqlInfo> RdbSqlUtils::GetUpdateSqlInfo(const AbsRdbPredicates &predicates, const Row &row,
175     Resolution resolution, const std::vector<std::string> &returningFields)
176 {
177     SqlInfo sqlInfo;
178     auto table = predicates.GetTableName();
179     auto args = predicates.GetBindArgs();
180     auto where = predicates.GetWhereClause();
181     if (table.empty()) {
182         return std::make_pair(E_EMPTY_TABLE_NAME, sqlInfo);
183     }
184 
185     if (row.IsEmpty()) {
186         return std::make_pair(E_EMPTY_VALUES_BUCKET, sqlInfo);
187     }
188 
189     auto clause = SqliteUtils::GetConflictClause(static_cast<int>(resolution));
190     if (clause == nullptr) {
191         return std::make_pair(E_INVALID_CONFLICT_FLAG, sqlInfo);
192     }
193     std::string sql;
194     sql.append("UPDATE").append(clause).append(" ").append(table).append(" SET ");
195     std::vector<ValueObject> tmpBindArgs;
196     size_t tmpBindSize = row.values_.size() + args.size();
197     tmpBindArgs.reserve(tmpBindSize);
198     const char *split = "";
199     for (auto &[key, val] : row.values_) {
200         sql.append(split);
201         if (val.GetType() == ValueObject::TYPE_ASSETS) {
202             sql.append(key).append("=merge_assets(").append(key).append(", ?)"); // columnName
203         } else if (val.GetType() == ValueObject::TYPE_ASSET) {
204             sql.append(key).append("=merge_asset(").append(key).append(", ?)"); // columnName
205         } else {
206             sql.append(key).append("=?"); // columnName
207         }
208         tmpBindArgs.push_back(val); // columnValue
209         split = ",";
210     }
211     if (!where.empty()) {
212         sql.append(" WHERE ").append(where);
213     }
214     if (!returningFields.empty()) {
215         SqliteSqlBuilder::AppendReturning(sql, returningFields);
216     }
217     tmpBindArgs.insert(tmpBindArgs.end(), args.begin(), args.end());
218 
219     sqlInfo.sql = std::move(sql);
220     sqlInfo.args = std::move(tmpBindArgs);
221     return std::make_pair(E_OK, sqlInfo);
222 }
223 
GetDeleteSqlInfo(const AbsRdbPredicates & predicates,const std::vector<std::string> & returningFields)224 std::pair<int, SqlInfo> RdbSqlUtils::GetDeleteSqlInfo(
225     const AbsRdbPredicates &predicates, const std::vector<std::string> &returningFields)
226 {
227     SqlInfo sqlInfo;
228     auto table = predicates.GetTableName();
229     auto where = predicates.GetWhereClause();
230     if (table.empty()) {
231         return std::make_pair(E_EMPTY_TABLE_NAME, sqlInfo);
232     }
233     std::string sql;
234     sql.append("DELETE FROM ").append(table);
235     if (!where.empty()) {
236         sql.append(" WHERE ").append(where);
237     }
238     if (!returningFields.empty()) {
239         SqliteSqlBuilder::AppendReturning(sql, returningFields);
240     }
241     sqlInfo.sql = std::move(sql);
242     sqlInfo.args = predicates.GetBindArgs();
243     return std::make_pair(E_OK, sqlInfo);
244 }
245 
GetQuerySqlInfo(const AbsRdbPredicates & predicates,const Fields & columns)246 std::pair<int, SqlInfo> RdbSqlUtils::GetQuerySqlInfo(const AbsRdbPredicates &predicates, const Fields &columns)
247 {
248     SqlInfo sqlInfo;
249     std::string sql = SqliteSqlBuilder::BuildQueryString(predicates, columns);
250     sqlInfo.sql = std::move(sql);
251     sqlInfo.args = predicates.GetBindArgs();
252     return std::make_pair(E_OK, sqlInfo);
253 }
254 } // namespace NativeRdb
255 } // namespace OHOS