@capacitor-community/sqlite 5.0.7-2 → 5.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -2
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLite.java +126 -3
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLitePlugin.java +115 -1
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/Database.java +142 -80
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/ImportFromJson.java +9 -9
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsDelete.java +484 -0
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsDrop.java +3 -3
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSQLStatement.java +169 -0
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsUpgrade.java +4 -4
- package/dist/esm/definitions.d.ts +117 -13
- package/dist/esm/definitions.js +103 -51
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +4 -0
- package/dist/esm/web.js +44 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +147 -51
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +147 -51
- package/dist/plugin.js.map +1 -1
- package/electron/dist/plugin.js +605 -181
- package/electron/dist/plugin.js.map +1 -1
- package/ios/Plugin/CapacitorSQLite.swift +123 -2
- package/ios/Plugin/CapacitorSQLitePlugin.m +4 -0
- package/ios/Plugin/CapacitorSQLitePlugin.swift +131 -1
- package/ios/Plugin/Database.swift +79 -2
- package/ios/Plugin/ImportExportJson/ImportFromJson.swift +13 -2
- package/ios/Plugin/Utils/UtilsDelete.swift +119 -117
- package/ios/Plugin/Utils/UtilsSQLCipher.swift +13 -5
- package/ios/Plugin/Utils/UtilsSQLStatement.swift +84 -84
- package/ios/Plugin/Utils/UtilsUpgrade.swift +3 -0
- package/package.json +5 -2
- package/src/definitions.ts +214 -57
- package/src/web.ts +48 -0
package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsDelete.java
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
package com.getcapacitor.community.database.sqlite.SQLite;
|
|
2
|
+
|
|
3
|
+
import static com.getcapacitor.community.database.sqlite.SQLite.UtilsSQLStatement.addPrefixToWhereClause;
|
|
4
|
+
import static com.getcapacitor.community.database.sqlite.SQLite.UtilsSQLStatement.extractForeignKeyInfo;
|
|
5
|
+
import static com.getcapacitor.community.database.sqlite.SQLite.UtilsSQLStatement.flattenMultilineString;
|
|
6
|
+
|
|
7
|
+
import com.getcapacitor.JSArray;
|
|
8
|
+
import com.getcapacitor.JSObject;
|
|
9
|
+
import java.util.ArrayList;
|
|
10
|
+
import java.util.Arrays;
|
|
11
|
+
import java.util.HashMap;
|
|
12
|
+
import java.util.Iterator;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
import java.util.Map;
|
|
15
|
+
import java.util.regex.Matcher;
|
|
16
|
+
import java.util.regex.Pattern;
|
|
17
|
+
import org.json.JSONException;
|
|
18
|
+
import org.json.JSONObject;
|
|
19
|
+
|
|
20
|
+
public class UtilsDelete {
|
|
21
|
+
|
|
22
|
+
private final UtilsSQLStatement _statUtil = new UtilsSQLStatement();
|
|
23
|
+
|
|
24
|
+
public static class ReferenceResult {
|
|
25
|
+
|
|
26
|
+
String tableWithRefs;
|
|
27
|
+
List<String> retRefs;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static class ForeignKeyInfo {
|
|
31
|
+
|
|
32
|
+
String tableName;
|
|
33
|
+
List<String> forKeys;
|
|
34
|
+
List<String> refKeys;
|
|
35
|
+
String action;
|
|
36
|
+
|
|
37
|
+
public ForeignKeyInfo() {
|
|
38
|
+
this.tableName = "";
|
|
39
|
+
this.forKeys = new ArrayList<>();
|
|
40
|
+
this.refKeys = new ArrayList<>();
|
|
41
|
+
this.action = "NO ACTION";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public ForeignKeyInfo(List<String> forKeys, String tableName, List<String> refKeys, String action) {
|
|
45
|
+
this.tableName = tableName;
|
|
46
|
+
this.forKeys = forKeys;
|
|
47
|
+
this.refKeys = refKeys;
|
|
48
|
+
this.action = action;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public String getTableName() {
|
|
52
|
+
return tableName;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public String getAction() {
|
|
56
|
+
return action;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public List<String> getForKeys() {
|
|
60
|
+
return forKeys;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public List<String> getRefKeys() {
|
|
64
|
+
return refKeys;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public static class UpdateResults {
|
|
69
|
+
|
|
70
|
+
private String setStmt;
|
|
71
|
+
private String updWhereStmt;
|
|
72
|
+
|
|
73
|
+
public UpdateResults() {
|
|
74
|
+
this.setStmt = "";
|
|
75
|
+
this.updWhereStmt = "";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public UpdateResults(String setStmt, String updWhereStmt) {
|
|
79
|
+
this.setStmt = setStmt;
|
|
80
|
+
this.updWhereStmt = updWhereStmt;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public String getSetStmt() {
|
|
84
|
+
return setStmt;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public String getUpdWhereStmt() {
|
|
88
|
+
return updWhereStmt;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public static boolean findReferencesAndUpdate(
|
|
93
|
+
Database mDB,
|
|
94
|
+
String tableName,
|
|
95
|
+
String whereStmt,
|
|
96
|
+
String[] initColNames,
|
|
97
|
+
ArrayList<Object> values
|
|
98
|
+
) throws Exception {
|
|
99
|
+
try {
|
|
100
|
+
boolean retBool = true;
|
|
101
|
+
ReferenceResult result = getReferences(mDB, tableName);
|
|
102
|
+
List<String> references = result.retRefs;
|
|
103
|
+
String tableNameWithRefs = result.tableWithRefs;
|
|
104
|
+
|
|
105
|
+
if (references.size() <= 0) {
|
|
106
|
+
return retBool;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (tableName.equals(tableNameWithRefs)) {
|
|
110
|
+
return retBool;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (String ref : references) {
|
|
114
|
+
ForeignKeyInfo foreignKeyInfo = extractForeignKeyInfo(ref);
|
|
115
|
+
|
|
116
|
+
String refTable = foreignKeyInfo.tableName;
|
|
117
|
+
if (refTable.isEmpty() || !refTable.equals(tableName)) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
List<String> withRefsNames = foreignKeyInfo.forKeys;
|
|
122
|
+
List<String> colNames = foreignKeyInfo.refKeys;
|
|
123
|
+
|
|
124
|
+
if (colNames.size() != withRefsNames.size()) {
|
|
125
|
+
throw new Error("findReferencesAndUpdate: mismatch length");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
String action = foreignKeyInfo.action;
|
|
129
|
+
if (action.equals("NO_ACTION")) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
String updTableName = tableNameWithRefs;
|
|
134
|
+
List<String> updColNames = withRefsNames;
|
|
135
|
+
|
|
136
|
+
UpdateResults results = new UpdateResults();
|
|
137
|
+
|
|
138
|
+
if (!checkValuesMatch(withRefsNames.toArray(new String[0]), initColNames)) {
|
|
139
|
+
Map<String, Object> relatedItemsResult = searchForRelatedItems(
|
|
140
|
+
mDB,
|
|
141
|
+
updTableName,
|
|
142
|
+
tableName,
|
|
143
|
+
whereStmt,
|
|
144
|
+
withRefsNames.toArray(new String[0]),
|
|
145
|
+
colNames.toArray(new String[0]),
|
|
146
|
+
values
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (
|
|
150
|
+
((List<String>) relatedItemsResult.get("relatedItems")).size() == 0 &&
|
|
151
|
+
((String) relatedItemsResult.get("key")).length() == 0
|
|
152
|
+
) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!updTableName.equals(tableName)) {
|
|
157
|
+
switch (action) {
|
|
158
|
+
case "RESTRICT":
|
|
159
|
+
results = upDateWhereForRestrict(relatedItemsResult);
|
|
160
|
+
break;
|
|
161
|
+
case "CASCADE":
|
|
162
|
+
results = upDateWhereForCascade(relatedItemsResult);
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
results = upDateWhereForDefault(withRefsNames, relatedItemsResult);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
throw new Error("Not implemented. Please transfer your example to the maintainer");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!results.getSetStmt().isEmpty() && !results.getUpdWhereStmt().isEmpty()) {
|
|
174
|
+
executeUpdateForDelete(mDB, updTableName, results.getUpdWhereStmt(), results.getSetStmt(), updColNames, values);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return retBool;
|
|
178
|
+
} catch (Exception error) {
|
|
179
|
+
String msg = error.getMessage() != null ? error.getMessage() : error.toString();
|
|
180
|
+
throw new Exception(msg);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public static ReferenceResult getReferences(Database mDB, String tableName) throws Exception {
|
|
185
|
+
String sqlStmt =
|
|
186
|
+
"SELECT sql FROM sqlite_master " +
|
|
187
|
+
"WHERE sql LIKE('%FOREIGN KEY%') AND sql LIKE('%REFERENCES%') AND " +
|
|
188
|
+
"sql LIKE('%" +
|
|
189
|
+
tableName +
|
|
190
|
+
"%') AND sql LIKE('%ON DELETE%');";
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
JSArray references = mDB.selectSQL(sqlStmt, new ArrayList<>());
|
|
194
|
+
ReferenceResult referenceResult = new ReferenceResult();
|
|
195
|
+
List<String> retRefs = new ArrayList<>();
|
|
196
|
+
String tableWithRefs = "";
|
|
197
|
+
|
|
198
|
+
if (references.length() > 0) {
|
|
199
|
+
Map<String, Object> result = getRefs(references.getJSONObject(0).getString("sql"));
|
|
200
|
+
retRefs = (List<String>) result.get("foreignKeys");
|
|
201
|
+
tableWithRefs = (String) result.get("tableName");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
referenceResult.tableWithRefs = tableWithRefs;
|
|
205
|
+
referenceResult.retRefs = retRefs;
|
|
206
|
+
|
|
207
|
+
return referenceResult;
|
|
208
|
+
} catch (Exception e) {
|
|
209
|
+
String error = e.getMessage() != null ? e.getMessage() : e.toString();
|
|
210
|
+
String msg = "getReferences: " + error;
|
|
211
|
+
throw new Exception(msg);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public static Map<String, Object> getRefs(String sqlStatement) throws Exception {
|
|
216
|
+
Map<String, Object> result = new HashMap<>();
|
|
217
|
+
String tableName = "";
|
|
218
|
+
List<String> foreignKeys = new ArrayList<>();
|
|
219
|
+
String statement = flattenMultilineString(sqlStatement);
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
// Regular expression pattern to match the table name
|
|
223
|
+
String tableNamePattern = "CREATE\\s+TABLE\\s+(\\w+)\\s+\\(";
|
|
224
|
+
Pattern tableNameRegex = Pattern.compile(tableNamePattern);
|
|
225
|
+
Matcher tableNameMatcher = tableNameRegex.matcher(statement);
|
|
226
|
+
if (tableNameMatcher.find()) {
|
|
227
|
+
tableName = tableNameMatcher.group(1);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Regular expression pattern to match the FOREIGN KEY constraints
|
|
231
|
+
String foreignKeyPattern =
|
|
232
|
+
"FOREIGN\\s+KEY\\s+\\([^)]+\\)\\s+REFERENCES\\s+(\\w+)\\s*\\([^)]+\\)\\s+ON\\s+DELETE\\s+(CASCADE|RESTRICT|SET\\s+DEFAULT|SET\\s+NULL|NO\\s+ACTION)";
|
|
233
|
+
Pattern foreignKeyRegex = Pattern.compile(foreignKeyPattern);
|
|
234
|
+
Matcher foreignKeyMatcher = foreignKeyRegex.matcher(statement);
|
|
235
|
+
while (foreignKeyMatcher.find()) {
|
|
236
|
+
String foreignKey = foreignKeyMatcher.group(0);
|
|
237
|
+
foreignKeys.add(foreignKey);
|
|
238
|
+
}
|
|
239
|
+
} catch (Exception e) {
|
|
240
|
+
String msg = "getRefs: Error creating regular expression: " + e.toString();
|
|
241
|
+
throw new Exception(msg);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
result.put("tableName", tableName);
|
|
245
|
+
result.put("foreignKeys", foreignKeys);
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
public static boolean checkValuesMatch(String[] array1, String[] array2) {
|
|
250
|
+
for (String value : array1) {
|
|
251
|
+
boolean found = false;
|
|
252
|
+
for (String item : array2) {
|
|
253
|
+
if (value.equals(item)) {
|
|
254
|
+
found = true;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (!found) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public static Map<String, Object> searchForRelatedItems(
|
|
266
|
+
Database mDB,
|
|
267
|
+
String updTableName,
|
|
268
|
+
String tableName,
|
|
269
|
+
String whStmt,
|
|
270
|
+
String[] withRefsNames,
|
|
271
|
+
String[] colNames,
|
|
272
|
+
ArrayList<Object> values
|
|
273
|
+
) throws Exception {
|
|
274
|
+
List<Object> relatedItems = new ArrayList<>();
|
|
275
|
+
String key = "";
|
|
276
|
+
String[] t1Names = new String[withRefsNames.length];
|
|
277
|
+
String[] t2Names = new String[colNames.length];
|
|
278
|
+
|
|
279
|
+
for (int i = 0; i < withRefsNames.length; i++) {
|
|
280
|
+
t1Names[i] = "t1." + withRefsNames[i];
|
|
281
|
+
t2Names[i] = "t2." + colNames[i];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
// addPrefix to the whereClause and swap colNames with withRefsNames
|
|
286
|
+
String whereClause = addPrefixToWhereClause(whStmt, colNames, withRefsNames, "t2.");
|
|
287
|
+
// look at the whereclause and change colNames with withRefsNames
|
|
288
|
+
if (whereClause.endsWith(";")) {
|
|
289
|
+
whereClause = whereClause.substring(0, whereClause.length() - 1);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
StringBuilder resultString = new StringBuilder();
|
|
293
|
+
for (int index = 0; index < t1Names.length; index++) {
|
|
294
|
+
resultString.append(t1Names[index]).append(" = ").append(t2Names[index]);
|
|
295
|
+
if (index < t1Names.length - 1) {
|
|
296
|
+
resultString.append(" AND ");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
String sql =
|
|
301
|
+
"SELECT t1.rowid FROM " +
|
|
302
|
+
updTableName +
|
|
303
|
+
" t1 " +
|
|
304
|
+
"JOIN " +
|
|
305
|
+
tableName +
|
|
306
|
+
" t2 ON " +
|
|
307
|
+
resultString.toString() +
|
|
308
|
+
" " +
|
|
309
|
+
"WHERE " +
|
|
310
|
+
whereClause +
|
|
311
|
+
" AND t1.sql_deleted = 0;";
|
|
312
|
+
|
|
313
|
+
JSArray jsVals = mDB.selectSQL(sql, values);
|
|
314
|
+
if (jsVals.length() > 0) {
|
|
315
|
+
List<Map<String, Object>> mVals = JSArrayToJavaListMap(jsVals);
|
|
316
|
+
key = mVals.get(0).keySet().iterator().next();
|
|
317
|
+
relatedItems.addAll(mVals);
|
|
318
|
+
}
|
|
319
|
+
Map<String, Object> result = new HashMap<>();
|
|
320
|
+
result.put("key", key);
|
|
321
|
+
result.put("relatedItems", relatedItems);
|
|
322
|
+
return result;
|
|
323
|
+
} catch (Exception error) {
|
|
324
|
+
String msg = error.getMessage() != null ? error.getMessage() : error.toString();
|
|
325
|
+
throw new Exception(msg);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
public static List<Map<String, Object>> JSArrayToJavaListMap(JSArray jsArray) throws JSONException {
|
|
330
|
+
List<Map<String, Object>> listMap = new ArrayList<>();
|
|
331
|
+
|
|
332
|
+
for (int i = 0; i < jsArray.length(); i++) {
|
|
333
|
+
JSObject jsObject = (JSObject) jsArray.get(i); // Assuming each element is an object
|
|
334
|
+
Map<String, Object> map = new HashMap<>();
|
|
335
|
+
|
|
336
|
+
// Extract key-value pairs from the JSObject and put them into the Map
|
|
337
|
+
for (Iterator<String> it = jsObject.keys(); it.hasNext();) {
|
|
338
|
+
String key = it.next();
|
|
339
|
+
map.put(key, jsObject.get(key)); // Convert JSValue to Java object
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
listMap.add(map); // Add the map to the list
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return listMap; // Return the List<Map<String, Object>>
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
public static UpdateResults upDateWhereForRestrict(Map<String, Object> results) throws Exception {
|
|
349
|
+
try {
|
|
350
|
+
if (((List<?>) results.get("relatedItems")).size() > 0) {
|
|
351
|
+
String msg = "Restrict mode related items exist, please delete them first";
|
|
352
|
+
throw new Exception(msg);
|
|
353
|
+
}
|
|
354
|
+
return new UpdateResults();
|
|
355
|
+
} catch (Exception error) {
|
|
356
|
+
String msg = error.getMessage() != null ? error.getMessage() : "";
|
|
357
|
+
throw new Exception(msg);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
public static UpdateResults upDateWhereForCascade(Map<String, Object> results) throws Exception {
|
|
362
|
+
String setStmt = "";
|
|
363
|
+
String uWhereStmt = "";
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
String key = (String) results.get("key");
|
|
367
|
+
List<Object> cols = new ArrayList<>();
|
|
368
|
+
List<Map<String, Object>> relatedItems = (List<Map<String, Object>>) results.get("relatedItems");
|
|
369
|
+
|
|
370
|
+
for (Map<String, Object> relItem : relatedItems) {
|
|
371
|
+
Object mVal = relItem.get(key);
|
|
372
|
+
if (mVal != null) {
|
|
373
|
+
cols.add(mVal);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
setStmt += "sql_deleted = 1";
|
|
378
|
+
|
|
379
|
+
// Create the where statement
|
|
380
|
+
StringBuilder uWhereStmtBuilder = new StringBuilder("WHERE " + key + " IN (");
|
|
381
|
+
for (Object col : cols) {
|
|
382
|
+
uWhereStmtBuilder.append(col).append(",");
|
|
383
|
+
}
|
|
384
|
+
if (uWhereStmtBuilder.toString().endsWith(",")) {
|
|
385
|
+
uWhereStmtBuilder.deleteCharAt(uWhereStmtBuilder.length() - 1);
|
|
386
|
+
}
|
|
387
|
+
uWhereStmtBuilder.append(");");
|
|
388
|
+
uWhereStmt = uWhereStmtBuilder.toString();
|
|
389
|
+
} catch (Exception error) {
|
|
390
|
+
String msg = error.getMessage() != null ? error.getMessage() : "";
|
|
391
|
+
throw new Exception(msg);
|
|
392
|
+
}
|
|
393
|
+
return new UpdateResults(setStmt, uWhereStmt);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
public static UpdateResults upDateWhereForDefault(List<String> withRefsNames, Map<String, Object> results) throws Exception {
|
|
397
|
+
String setStmt = "";
|
|
398
|
+
String uWhereStmt = "";
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
String key = (String) results.get("key");
|
|
402
|
+
List<Object> cols = new ArrayList<>();
|
|
403
|
+
List<Map<String, Object>> relatedItems = (List<Map<String, Object>>) results.get("relatedItems");
|
|
404
|
+
|
|
405
|
+
for (Map<String, Object> relItem : relatedItems) {
|
|
406
|
+
Object mVal = relItem.get(key);
|
|
407
|
+
if (mVal != null) {
|
|
408
|
+
cols.add(mVal);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Create the set statement
|
|
413
|
+
for (String name : withRefsNames) {
|
|
414
|
+
setStmt += name + " = NULL, ";
|
|
415
|
+
}
|
|
416
|
+
setStmt += "sql_deleted = 0";
|
|
417
|
+
|
|
418
|
+
// Create the where statement
|
|
419
|
+
StringBuilder uWhereStmtBuilder = new StringBuilder("WHERE " + key + " IN (");
|
|
420
|
+
for (Object col : cols) {
|
|
421
|
+
uWhereStmtBuilder.append(col).append(",");
|
|
422
|
+
}
|
|
423
|
+
if (uWhereStmtBuilder.toString().endsWith(",")) {
|
|
424
|
+
uWhereStmtBuilder.deleteCharAt(uWhereStmtBuilder.length() - 1);
|
|
425
|
+
}
|
|
426
|
+
uWhereStmtBuilder.append(");");
|
|
427
|
+
uWhereStmt = uWhereStmtBuilder.toString();
|
|
428
|
+
} catch (Exception error) {
|
|
429
|
+
String msg = error.getMessage() != null ? error.getMessage() : "";
|
|
430
|
+
throw new Exception(msg);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return new UpdateResults(setStmt, uWhereStmt);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
public static void executeUpdateForDelete(
|
|
437
|
+
Database mDB,
|
|
438
|
+
String tableName,
|
|
439
|
+
String whereStmt,
|
|
440
|
+
String setStmt,
|
|
441
|
+
List<String> colNames,
|
|
442
|
+
ArrayList<Object> values
|
|
443
|
+
) throws Exception {
|
|
444
|
+
try {
|
|
445
|
+
long lastId = -1;
|
|
446
|
+
|
|
447
|
+
// Update sql_deleted for this references
|
|
448
|
+
String stmt = "UPDATE " + tableName + " SET " + setStmt + " " + whereStmt;
|
|
449
|
+
ArrayList<Object> selValues = getSelectedValues(values, whereStmt, colNames);
|
|
450
|
+
|
|
451
|
+
JSObject retObj = mDB.prepareSQL(stmt, selValues, false, "no");
|
|
452
|
+
lastId = retObj.getLong("lastId");
|
|
453
|
+
if (lastId == -1) {
|
|
454
|
+
String msg = "UPDATE sql_deleted failed for table: " + tableName;
|
|
455
|
+
throw new Exception(msg);
|
|
456
|
+
}
|
|
457
|
+
} catch (Exception error) {
|
|
458
|
+
String msg = error.getMessage() != null ? error.getMessage() : "";
|
|
459
|
+
throw new Exception(msg);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
public static ArrayList<Object> getSelectedValues(ArrayList<Object> values, String whereStmt, List<String> colNames) {
|
|
464
|
+
ArrayList<Object> selValues = new ArrayList<>(); // Initialize the selected values ArrayList
|
|
465
|
+
|
|
466
|
+
if (values.size() > 0) {
|
|
467
|
+
String[] arrVal = whereStmt.split("\\?");
|
|
468
|
+
if (arrVal[arrVal.length - 1].equals(";")) {
|
|
469
|
+
arrVal[arrVal.length - 1] = "";
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
for (int jdx = 0; jdx < arrVal.length; jdx++) {
|
|
473
|
+
for (String updVal : colNames) {
|
|
474
|
+
List<Integer> indices = UtilsSQLStatement.indicesOf(arrVal[jdx], updVal, 0);
|
|
475
|
+
if (!indices.isEmpty()) {
|
|
476
|
+
selValues.add(values.get(jdx));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return selValues;
|
|
483
|
+
}
|
|
484
|
+
}
|
package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsDrop.java
CHANGED
|
@@ -190,19 +190,19 @@ public class UtilsDrop {
|
|
|
190
190
|
public void dropAll(Database db) throws Exception {
|
|
191
191
|
Boolean success = false;
|
|
192
192
|
try {
|
|
193
|
-
db.
|
|
193
|
+
db.beginTransaction();
|
|
194
194
|
dropTables(db);
|
|
195
195
|
dropIndexes(db);
|
|
196
196
|
dropTriggers(db);
|
|
197
197
|
dropViews(db);
|
|
198
|
-
db.
|
|
198
|
+
db.commitTransaction();
|
|
199
199
|
success = true;
|
|
200
200
|
} catch (Exception e) {
|
|
201
201
|
String msg = "DropAll failed: " + e;
|
|
202
202
|
Log.d(TAG, msg);
|
|
203
203
|
throw new Exception(msg);
|
|
204
204
|
} finally {
|
|
205
|
-
if (success) db.
|
|
205
|
+
if (success) db.rollbackTransaction();
|
|
206
206
|
try {
|
|
207
207
|
db.getDb().execSQL("VACUUM;");
|
|
208
208
|
} catch (Exception e) {
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
package com.getcapacitor.community.database.sqlite.SQLite;
|
|
2
|
+
|
|
3
|
+
import java.util.ArrayList;
|
|
4
|
+
import java.util.Arrays;
|
|
5
|
+
import java.util.HashSet;
|
|
6
|
+
import java.util.List;
|
|
7
|
+
import java.util.Set;
|
|
8
|
+
import java.util.regex.Matcher;
|
|
9
|
+
import java.util.regex.Pattern;
|
|
10
|
+
|
|
11
|
+
public class UtilsSQLStatement {
|
|
12
|
+
|
|
13
|
+
public static String flattenMultilineString(String input) {
|
|
14
|
+
String[] lines = input.split("\\r?\\n");
|
|
15
|
+
return String.join(" ", lines);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public static String extractTableName(String statement) {
|
|
19
|
+
Pattern pattern = Pattern.compile("(?:INSERT\\s+INTO|UPDATE|DELETE\\s+FROM)\\s+([^\\s]+)", Pattern.CASE_INSENSITIVE);
|
|
20
|
+
Matcher match = pattern.matcher(statement);
|
|
21
|
+
if (match.find() && match.groupCount() > 0) {
|
|
22
|
+
String tableName = match.group(1);
|
|
23
|
+
return tableName;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public static String extractWhereClause(String statement) {
|
|
29
|
+
Pattern pattern = Pattern.compile("WHERE(.+?)(?:ORDER\\s+BY|LIMIT|$)", Pattern.CASE_INSENSITIVE);
|
|
30
|
+
Matcher match = pattern.matcher(statement);
|
|
31
|
+
if (match.find() && match.groupCount() > 0) {
|
|
32
|
+
String whereClause = match.group(1).trim();
|
|
33
|
+
return whereClause;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public static String addPrefixToWhereClause(String whereClause, String[] colNames, String[] refNames, String prefix) {
|
|
39
|
+
String[] columnValuePairs = null;
|
|
40
|
+
String[] logicalOperators = new String[] { "AND", "OR", "NOT" };
|
|
41
|
+
|
|
42
|
+
for (String logicalOperator : logicalOperators) {
|
|
43
|
+
if (whereClause.contains(logicalOperator)) {
|
|
44
|
+
columnValuePairs = whereClause.split("\\s*" + logicalOperator + "\\s*");
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (columnValuePairs == null) {
|
|
50
|
+
columnValuePairs = new String[] { whereClause };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
List<String> modifiedPairs = new ArrayList<>();
|
|
54
|
+
|
|
55
|
+
for (String pair : columnValuePairs) {
|
|
56
|
+
String trimmedPair = pair.trim();
|
|
57
|
+
|
|
58
|
+
int operatorIndex = -1;
|
|
59
|
+
String operator = null;
|
|
60
|
+
for (String op : new String[] { "=", "<>", "<", "<=", ">", ">=", "IN", "BETWEEN", "LIKE" }) {
|
|
61
|
+
operatorIndex = trimmedPair.indexOf(op);
|
|
62
|
+
if (operatorIndex != -1) {
|
|
63
|
+
operator = op;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (operator == null) {
|
|
69
|
+
modifiedPairs.add(trimmedPair);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
String column = trimmedPair.substring(0, operatorIndex).trim();
|
|
74
|
+
String value = trimmedPair.substring(operatorIndex + operator.length()).trim();
|
|
75
|
+
|
|
76
|
+
String newColumn = column;
|
|
77
|
+
int index = findIndexOfStringInArray(column, refNames);
|
|
78
|
+
if (index != -1) {
|
|
79
|
+
newColumn = getStringAtIndex(colNames, index);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
String modifiedColumn = prefix + newColumn;
|
|
83
|
+
String modifiedPair = modifiedColumn + " " + operator + " " + value;
|
|
84
|
+
modifiedPairs.add(modifiedPair);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
String logicalOperatorUsed = logicalOperators[0];
|
|
88
|
+
for (String logicalOperator : logicalOperators) {
|
|
89
|
+
if (whereClause.contains(logicalOperator)) {
|
|
90
|
+
logicalOperatorUsed = logicalOperator;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
String modWhereClause = String.join(" " + logicalOperatorUsed + " ", modifiedPairs);
|
|
95
|
+
return modWhereClause;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public static int findIndexOfStringInArray(String target, String[] array) {
|
|
99
|
+
for (int i = 0; i < array.length; i++) {
|
|
100
|
+
if (array[i].equals(target)) {
|
|
101
|
+
return i;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return -1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public static String getStringAtIndex(String[] array, int index) {
|
|
108
|
+
if (index >= 0 && index < array.length) {
|
|
109
|
+
return array[index];
|
|
110
|
+
} else {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public static UtilsDelete.ForeignKeyInfo extractForeignKeyInfo(String sqlStatement) throws Exception {
|
|
116
|
+
// Define the regular expression pattern for extracting the FOREIGN KEY clause
|
|
117
|
+
String foreignKeyPattern =
|
|
118
|
+
"\\bFOREIGN\\s+KEY\\s*\\(([^)]+)\\)\\s+REFERENCES\\s+(\\w+)\\s*\\(([^)]+)\\)\\s+(ON\\s+DELETE\\s+(RESTRICT|CASCADE|SET\\s+NULL|SET\\s+DEFAULT|NO\\s+ACTION))?";
|
|
119
|
+
Pattern pattern = Pattern.compile(foreignKeyPattern);
|
|
120
|
+
Matcher matcher = pattern.matcher(sqlStatement);
|
|
121
|
+
|
|
122
|
+
if (matcher.find()) {
|
|
123
|
+
String[] forKeys = matcher.group(1).split(",");
|
|
124
|
+
String tableName = matcher.group(2);
|
|
125
|
+
String[] refKeys = matcher.group(3).split(",");
|
|
126
|
+
String action = matcher.group(5) != null ? matcher.group(5) : "NO ACTION";
|
|
127
|
+
List<String> lForKeys = new ArrayList<>(Arrays.asList(forKeys));
|
|
128
|
+
List<String> lRefKeys = new ArrayList<>(Arrays.asList(refKeys));
|
|
129
|
+
return new UtilsDelete.ForeignKeyInfo(lForKeys, tableName, lRefKeys, action);
|
|
130
|
+
} else {
|
|
131
|
+
throw new Exception("extractForeignKeyInfo: No FOREIGN KEY found");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public static List<String> extractColumnNames(String whereClause) {
|
|
136
|
+
Set<String> keywords = new HashSet<>(Arrays.asList("AND", "OR", "IN", "VALUES", "LIKE", "BETWEEN", "NOT"));
|
|
137
|
+
String[] tokens = whereClause.split("\\s|,|\\(|\\)");
|
|
138
|
+
|
|
139
|
+
List<String> columns = new ArrayList<>();
|
|
140
|
+
boolean inClause = false;
|
|
141
|
+
boolean inValues = false;
|
|
142
|
+
|
|
143
|
+
for (String token : tokens) {
|
|
144
|
+
if (token.equals("IN")) {
|
|
145
|
+
inClause = true;
|
|
146
|
+
} else if (inClause && token.equals("(")) {
|
|
147
|
+
inValues = true;
|
|
148
|
+
} else if (inValues && token.equals(")")) {
|
|
149
|
+
inValues = false;
|
|
150
|
+
} else if (token.matches("\\b[a-zA-Z]\\w*\\b") && !inValues && !keywords.contains(token.toUpperCase())) {
|
|
151
|
+
columns.add(token);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return new ArrayList<>(new HashSet<>(columns));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public static List<Integer> indicesOf(String str, String searchStr, int fromIndex) {
|
|
159
|
+
List<Integer> indices = new ArrayList<>();
|
|
160
|
+
|
|
161
|
+
int currentIndex = str.indexOf(searchStr, fromIndex);
|
|
162
|
+
while (currentIndex != -1) {
|
|
163
|
+
indices.add(currentIndex);
|
|
164
|
+
currentIndex = str.indexOf(searchStr, currentIndex + 1);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return indices;
|
|
168
|
+
}
|
|
169
|
+
}
|
package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsUpgrade.java
CHANGED
|
@@ -69,15 +69,15 @@ public class UtilsUpgrade {
|
|
|
69
69
|
* @throws Exception
|
|
70
70
|
*/
|
|
71
71
|
private void executeStatementsProcess(Database db, String[] statements) throws Exception {
|
|
72
|
-
db.
|
|
72
|
+
db.beginTransaction();
|
|
73
73
|
try {
|
|
74
|
-
db.execute(statements);
|
|
74
|
+
db.execute(statements, false);
|
|
75
75
|
|
|
76
|
-
db.
|
|
76
|
+
db.commitTransaction();
|
|
77
77
|
} catch (Exception e) {
|
|
78
78
|
throw new Exception("Error: executeStatementsProcess " + " failed " + e);
|
|
79
79
|
} finally {
|
|
80
|
-
db.
|
|
80
|
+
db.rollbackTransaction();
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|