@capacitor-community/sqlite 5.0.6 → 5.0.7-2

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.
@@ -25,9 +25,6 @@ enum UtilsSQLCipherError: Error {
25
25
  case execute(message: String)
26
26
  case prepareSQL(message: String)
27
27
  case deleteSQL(message: String)
28
- case findReferencesAndUpdate(message: String)
29
- case getReferences(message: String)
30
- case getRefs(message: String)
31
28
  case querySQL(message: String)
32
29
  case fetchColumnInfo(message: String)
33
30
  case deleteDB(message: String)
@@ -38,8 +35,6 @@ enum UtilsSQLCipherError: Error {
38
35
  case openDBStoredPassword(message: String)
39
36
  case openDBGlobalPassword(message: String)
40
37
  case returningWorkAround(message: String)
41
- case getUpdDelReturnedValues(message: String)
42
- case getFirstPK(message: String)
43
38
  }
44
39
  enum State: String {
45
40
  case DOESNOTEXIST, UNENCRYPTED, ENCRYPTEDSECRET,
@@ -51,6 +46,8 @@ enum State: String {
51
46
  // swiftlint:disable type_body_length
52
47
  class UtilsSQLCipher {
53
48
 
49
+ // MARK: - getDatabaseState
50
+
54
51
  class func getDatabaseState(databaseLocation: String,
55
52
  databaseName: String,
56
53
  account: String) -> State {
@@ -62,17 +59,22 @@ class UtilsSQLCipher {
62
59
  do {
63
60
  try openDBNoPassword(dBPath: path)
64
61
  return State.UNENCRYPTED
65
- } catch UtilsSQLCipherError.openDBNoPassword(let message) {
62
+ } catch UtilsSQLCipherError
63
+ .openDBNoPassword(let message) {
66
64
  if message == "Open" {
67
65
  do {
68
- try openDBStoredPassword(dBPath: path, account: account)
66
+ try openDBStoredPassword(dBPath: path,
67
+ account: account)
69
68
  return State.ENCRYPTEDSECRET
70
- } catch UtilsSQLCipherError.openDBStoredPassword(let message) {
69
+ } catch UtilsSQLCipherError
70
+ .openDBStoredPassword(let message) {
71
71
  if message == "Open" {
72
72
  do {
73
- try openDBGlobalPassword(dBPath: path)
73
+ try openDBGlobalPassword(
74
+ dBPath: path)
74
75
  return State.ENCRYPTEDGLOBALSECRET
75
- } catch UtilsSQLCipherError.openDBGlobalPassword(let message) {
76
+ } catch UtilsSQLCipherError
77
+ .openDBGlobalPassword(let message) {
76
78
  if message == "Open" {
77
79
  return State.UNKNOWN
78
80
  } else {
@@ -95,6 +97,9 @@ class UtilsSQLCipher {
95
97
  return State.UNKNOWN
96
98
  }
97
99
  }
100
+
101
+ // MARK: - openDBNoPassword
102
+
98
103
  class func openDBNoPassword(dBPath: String) throws {
99
104
  do {
100
105
  let oDb: OpaquePointer? = try openOrCreateDatabase(
@@ -105,24 +110,35 @@ class UtilsSQLCipher {
105
110
  } catch UtilsSQLCipherError.openOrCreateDatabase(_) {
106
111
  throw UtilsSQLCipherError.openDBNoPassword(message: "Open")
107
112
  } catch UtilsSQLCipherError.close(_) {
108
- throw UtilsSQLCipherError.openDBNoPassword(message: "Close")
113
+ throw UtilsSQLCipherError
114
+ .openDBNoPassword(message: "Close")
109
115
  }
110
116
 
111
117
  }
112
- class func openDBStoredPassword(dBPath: String, account: String) throws {
118
+
119
+ // MARK: - openDBStoredPassword
120
+
121
+ class func openDBStoredPassword(dBPath: String, account: String)
122
+ throws {
113
123
  do {
114
- let password: String = UtilsSecret.getPassphrase(account: account)
124
+ let password: String = UtilsSecret
125
+ .getPassphrase(account: account)
115
126
  let oDb: OpaquePointer? = try openOrCreateDatabase(
116
127
  filename: dBPath, password: password, readonly: true)
117
128
  try close(oDB: oDb)
118
129
  return
119
130
  } catch UtilsSQLCipherError.openOrCreateDatabase(_) {
120
- throw UtilsSQLCipherError.openDBStoredPassword(message: "Open")
131
+ throw UtilsSQLCipherError
132
+ .openDBStoredPassword(message: "Open")
121
133
  } catch UtilsSQLCipherError.close(_) {
122
- throw UtilsSQLCipherError.openDBStoredPassword(message: "Close")
134
+ throw UtilsSQLCipherError
135
+ .openDBStoredPassword(message: "Close")
123
136
  }
124
137
 
125
138
  }
139
+
140
+ // MARK: - openDBGlobalPassword
141
+
126
142
  class func openDBGlobalPassword(dBPath: String) throws {
127
143
  do {
128
144
  let globalData: GlobalSQLite = GlobalSQLite()
@@ -132,9 +148,11 @@ class UtilsSQLCipher {
132
148
  try close(oDB: oDb)
133
149
  return
134
150
  } catch UtilsSQLCipherError.openOrCreateDatabase(_) {
135
- throw UtilsSQLCipherError.openDBGlobalPassword(message: "Open")
151
+ throw UtilsSQLCipherError
152
+ .openDBGlobalPassword(message: "Open")
136
153
  } catch UtilsSQLCipherError.close(_) {
137
- throw UtilsSQLCipherError.openDBGlobalPassword(message: "Close")
154
+ throw UtilsSQLCipherError
155
+ .openDBGlobalPassword(message: "Close")
138
156
  }
139
157
 
140
158
  }
@@ -159,13 +177,15 @@ class UtilsSQLCipher {
159
177
  if sqlite3_exec(mDB, keyStatementString, nil, nil, nil)
160
178
  != SQLITE_OK {
161
179
  let msg: String = "Wrong Secret"
162
- throw UtilsSQLCipherError.openOrCreateDatabase(message: msg)
180
+ throw UtilsSQLCipherError
181
+ .openOrCreateDatabase(message: msg)
163
182
  }
164
183
  }
165
184
  let retB: Bool = checkDB(mDB: mDB)
166
185
  if !retB {
167
186
  let msg: String = "Cannot open the DB"
168
- throw UtilsSQLCipherError.openOrCreateDatabase(message: msg)
187
+ throw UtilsSQLCipherError
188
+ .openOrCreateDatabase(message: msg)
169
189
  }
170
190
  return mDB
171
191
  } else {
@@ -186,6 +206,7 @@ class UtilsSQLCipher {
186
206
  }
187
207
  return ret
188
208
  }
209
+
189
210
  // MARK: - ChangePassword
190
211
 
191
212
  class func changePassword(filename: String, password: String,
@@ -247,7 +268,8 @@ class UtilsSQLCipher {
247
268
  var msg: String = "Error ForeignKeysState: "
248
269
  if !mDB.isDBOpen() {
249
270
  msg.append("Database not opened")
250
- throw UtilsSQLCipherError.getForeignKeysStateFailed(message: msg)
271
+ throw UtilsSQLCipherError
272
+ .getForeignKeysStateFailed(message: msg)
251
273
  }
252
274
  var fkState: Int = 0
253
275
 
@@ -260,7 +282,8 @@ class UtilsSQLCipher {
260
282
  resForKeys.removeFirst()
261
283
  guard let res: Int64 = resForKeys[0]["foreign_keys"]
262
284
  as? Int64 else {
263
- throw UtilsSQLCipherError.getForeignKeysStateFailed(
285
+ throw UtilsSQLCipherError
286
+ .getForeignKeysStateFailed(
264
287
  message: "Error get foreign keys failed")
265
288
  }
266
289
  if res > 0 {
@@ -417,7 +440,8 @@ class UtilsSQLCipher {
417
440
  // swiftlint:disable function_body_length
418
441
  // swiftlint:disable cyclomatic_complexity
419
442
  class func prepareSQL(mDB: Database, sql: String, values: [Any],
420
- fromJson: Bool, returnMode: String) throws -> (Int64, [[String: Any]]) {
443
+ fromJson: Bool, returnMode: String)
444
+ throws -> (Int64, [[String: Any]]) {
421
445
  var msg: String = "Error prepareSQL: "
422
446
  if !mDB.isDBOpen() {
423
447
  msg.append("Database not opened")
@@ -442,8 +466,9 @@ class UtilsSQLCipher {
442
466
 
443
467
  if (retMode == "no" || retMode.prefix(2) == "wA") &&
444
468
  sqlStmt.uppercased().contains("RETURNING") {
445
- let stmtNames = getStmtAndRetColNames(sqlStmt: sqlStmt,
446
- retMode: retMode)
469
+ let stmtNames = UtilsSQLStatement
470
+ .getStmtAndRetColNames(sqlStmt: sqlStmt,
471
+ retMode: retMode)
447
472
  sqlStmt = stmtNames["stmt"] ?? sqlStmt
448
473
  names = stmtNames["names"] ?? ""
449
474
  }
@@ -487,22 +512,27 @@ class UtilsSQLCipher {
487
512
  } else {
488
513
  if retMode.prefix(2) == "wA" {
489
514
  do {
490
- result = try UtilsSQLCipher.returningWorkAround(
491
- mDB: mDB,
492
- runSQLStatement: runSQLStatement, sqlStmt: sqlStmt,
493
- names: names, returnMode: retMode)
515
+ result = try UtilsSQLCipher
516
+ .returningWorkAround(
517
+ mDB: mDB,
518
+ runSQLStatement: runSQLStatement,
519
+ sqlStmt: sqlStmt,
520
+ names: names, returnMode: retMode)
494
521
  } catch UtilsSQLCipherError
495
522
  .returningWorkAround(let message) {
496
- throw UtilsSQLCipherError.prepareSQL(message: message)
523
+ throw UtilsSQLCipherError
524
+ .prepareSQL(message: message)
497
525
  }
498
526
  } else {
499
527
 
500
528
  do {
501
529
  result = try UtilsSQLCipher.fetchColumnInfo(
502
- handle: runSQLStatement, returnMode: retMode)
530
+ handle: runSQLStatement,
531
+ returnMode: retMode)
503
532
  } catch UtilsSQLCipherError
504
533
  .fetchColumnInfo(let message) {
505
- throw UtilsSQLCipherError.prepareSQL(message: message)
534
+ throw UtilsSQLCipherError
535
+ .prepareSQL(message: message)
506
536
  }
507
537
  }
508
538
  }
@@ -527,44 +557,26 @@ class UtilsSQLCipher {
527
557
  }
528
558
  }
529
559
 
530
- // MARK: - getStmtAndRetColNames
531
-
532
- class func getStmtAndRetColNames(sqlStmt: String, retMode: String) -> [String: String] {
533
- let retWord = "RETURNING"
534
-
535
- var retStmtNames: [String: String] = [:]
536
- retStmtNames["stmt"] = sqlStmt
537
- retStmtNames["names"] = ""
538
- if let range = sqlStmt.uppercased().range(of: retWord) {
539
- let prefix = sqlStmt.prefix(upTo: range.lowerBound)
540
- retStmtNames["stmt"] = "\(prefix);"
541
- retStmtNames["names"] = ""
542
- if retMode.prefix(2) == "wA" {
543
- let suffix = sqlStmt.suffix(from: range.upperBound)
544
- let names = "\(suffix)".trimmingLeadingAndTrailingSpaces()
545
- if names.suffix(1) == ";" {
546
- retStmtNames["names"] = String(names.dropLast())
547
- }
548
- }
549
-
550
- }
551
- return retStmtNames
552
- }
553
-
554
560
  // MARK: - returningWorkAround
555
561
 
556
- class func returningWorkAround(mDB: Database, runSQLStatement: OpaquePointer?,
562
+ class func returningWorkAround(mDB: Database,
563
+ runSQLStatement: OpaquePointer?,
557
564
  sqlStmt: String, names: String,
558
- returnMode: String) throws -> [[String: Any]] {
565
+ returnMode: String)
566
+ throws -> [[String: Any]] {
559
567
  var result: [[String: Any]] = []
560
568
  let initLastId = Int64(sqlite3_last_insert_rowid(mDB.mDb))
561
- if sqlStmt.prefix(6).uppercased() == "DELETE" && names.count > 0 {
569
+ if sqlStmt.prefix(6).uppercased() == "DELETE" &&
570
+ names.count > 0 {
562
571
  do {
563
- result = try getUpdDelReturnedValues(mDB: mDB, sqlStmt: sqlStmt,
564
- names: names )
565
- } catch UtilsSQLCipherError
572
+ result = try UtilsDelete
573
+ .getUpdDelReturnedValues(mDB: mDB,
574
+ sqlStmt: sqlStmt,
575
+ names: names )
576
+ } catch UtilsDeleteError
566
577
  .getUpdDelReturnedValues(let message) {
567
- throw UtilsSQLCipherError.returningWorkAround(message: message)
578
+ throw UtilsSQLCipherError
579
+ .returningWorkAround(message: message)
568
580
  }
569
581
  }
570
582
  let returnCode: Int32 = sqlite3_step(runSQLStatement)
@@ -573,34 +585,42 @@ class UtilsSQLCipher {
573
585
  cString: sqlite3_errmsg(mDB.mDb))
574
586
  var message = "Error: prepareSQL step failed rc: "
575
587
  message.append("\(returnCode) message: \(errmsg)")
576
- throw UtilsSQLCipherError.returningWorkAround(message: message)
588
+ throw UtilsSQLCipherError
589
+ .returningWorkAround(message: message)
577
590
 
578
591
  }
579
592
  if sqlStmt.prefix(6).uppercased() == "INSERT" {
580
593
  let lastId = Int64(sqlite3_last_insert_rowid(mDB.mDb))
581
- let tableName = extractTableName(from: sqlStmt)
594
+ let tableName = UtilsSQLStatement
595
+ .extractTableName(from: sqlStmt)
582
596
  if let tblName = tableName {
583
- var query = "SELECT \(names) FROM \(tblName) WHERE rowid "
597
+ var query = "SELECT \(names) FROM \(tblName) " +
598
+ "WHERE rowid "
584
599
  if returnMode == "wAone" {
585
600
  query += "= \(initLastId + 1);"
586
601
  } else {
587
602
  query += "BETWEEN \(initLastId + 1) AND \(lastId);"
588
603
  }
589
604
  do {
590
- result = try querySQL(mDB: mDB, sql: query, values: [])
605
+ result = try querySQL(mDB: mDB, sql: query,
606
+ values: [])
591
607
  } catch UtilsSQLCipherError.querySQL(let message) {
592
- throw UtilsSQLCipherError.returningWorkAround(message: message)
608
+ throw UtilsSQLCipherError
609
+ .returningWorkAround(message: message)
593
610
  }
594
611
 
595
612
  }
596
613
 
597
614
  } else if sqlStmt.prefix(6).uppercased() == "UPDATE" {
598
615
  do {
599
- result = try getUpdDelReturnedValues(mDB: mDB, sqlStmt: sqlStmt,
600
- names: names )
601
- } catch UtilsSQLCipherError
616
+ result = try UtilsDelete
617
+ .getUpdDelReturnedValues(mDB: mDB,
618
+ sqlStmt: sqlStmt,
619
+ names: names )
620
+ } catch UtilsDeleteError
602
621
  .getUpdDelReturnedValues(let message) {
603
- throw UtilsSQLCipherError.returningWorkAround(message: message)
622
+ throw UtilsSQLCipherError
623
+ .returningWorkAround(message: message)
604
624
  }
605
625
 
606
626
  }
@@ -608,107 +628,66 @@ class UtilsSQLCipher {
608
628
  return result
609
629
  }
610
630
 
611
- // MARK: - getUpdDelReturnedValues
612
-
613
- class func getUpdDelReturnedValues(mDB: Database, sqlStmt: String,
614
- names: String ) throws -> [[String: Any]] {
615
- var result: [[String: Any]] = []
616
- let tableName = extractTableName(from: sqlStmt)
617
- let whereClause = extractWhereClause(from: sqlStmt)
618
- if let tblName = tableName {
619
- if var wClause = whereClause {
620
- if wClause.suffix(1) == ";" {
621
- wClause = String(wClause.dropLast())
622
- }
623
- do {
624
- var query: String = "SELECT \(names) FROM \(tblName) WHERE "
625
- query += "\(wClause);"
626
- result = try querySQL(mDB: mDB, sql: query, values: [])
627
- } catch UtilsSQLCipherError.querySQL(let message) {
628
- throw UtilsSQLCipherError.getUpdDelReturnedValues(message: message)
629
- }
630
- }
631
- }
632
- return result
633
- }
634
-
635
- // MARK: - extractTableName
636
-
637
- class func extractTableName(from statement: String) -> String? {
638
- let pattern = "(?:INSERT\\s+INTO|UPDATE|DELETE\\s+FROM)\\s+([^\\s]+)"
639
- guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return nil }
640
-
641
- let range = NSRange(location: 0, length: statement.count)
642
- if let match = regex.firstMatch(in: statement, options: [], range: range) {
643
- let tableNameRange = match.range(at: 1)
644
- if let tableNameRange = Range(tableNameRange, in: statement) {
645
- let tableName = String(statement[tableNameRange])
646
- return tableName
647
- }
648
- }
649
-
650
- return nil
651
- }
652
-
653
- // MARK: - extractWhereClause
654
-
655
- class func extractWhereClause(from statement: String) -> String? {
656
- let pattern = "WHERE(.+?)(?:ORDER\\s+BY|LIMIT|$)"
657
- guard let regex = try? NSRegularExpression(
658
- pattern: pattern,
659
- options: [.caseInsensitive, .dotMatchesLineSeparators]) else {
660
- return nil
661
-
662
- }
663
-
664
- let range = NSRange(location: 0, length: statement.count)
665
- if let match = regex.firstMatch(in: statement, options: [], range: range) {
666
- let whereClauseRange = match.range(at: 1)
667
- if let whereClauseRange = Range(whereClauseRange, in: statement) {
668
- let whereClause = String(statement[whereClauseRange])
669
- return whereClause.trimmingCharacters(in: .whitespacesAndNewlines)
670
- }
671
- }
672
-
673
- return nil
674
- }
675
-
676
631
  // swiftlint:enable cyclomatic_complexity
677
632
  // swiftlint:enable function_body_length
678
633
 
679
634
  // MARK: - deleteSQL
680
635
 
681
- class func deleteSQL(mDB: Database, sql: String, values: [Any]) throws -> String {
636
+ class func deleteSQL(mDB: Database, sql: String, values: [Any])
637
+ throws -> String {
682
638
  var sqlStmt = sql
683
639
  do {
684
640
  let isLast: Bool = try UtilsJson.isLastModified(mDB: mDB)
685
641
  let isDel: Bool = try UtilsJson.isSqlDeleted(mDB: mDB)
686
642
  if isLast && isDel {
687
- // Replace DELETE by UPDATE and set sql_deleted to 1
688
- if let range: Range<String.Index> = sql
689
- .range(of: "WHERE", options: .caseInsensitive) {
690
- let index: Int = sql
691
- .distance(from: sql.startIndex, to: range.lowerBound)
692
- let preStmt = String(sql.stringRange(fromIdx: 0,
693
- toIdx: (index - 1)))
694
- let clauseStmt = String(sql.stringRange(fromIdx: index,
695
- toIdx: sql.count))
696
- let tableName = (preStmt.deletingPrefix("DELETE FROM"))
697
- .trimmingLeadingAndTrailingSpaces()
698
- sqlStmt = "UPDATE \(tableName) SET sql_deleted = 1 "
699
- sqlStmt += clauseStmt
700
- // Find REFERENCIES if any and update the sql_deleted column
701
- try findReferencesAndUpdate(mDB: mDB,
702
- tableName: tableName,
703
- whereStmt: clauseStmt,
704
- values: values)
705
- } else {
706
- let msg: String = "deleteSQL cannot find a WHERE clause"
643
+ // Replace DELETE by UPDATE
644
+ // set sql_deleted to 1 and the last_modified to
645
+ // timenow
646
+ guard let whereClause =
647
+ UtilsSQLStatement.extractWhereClause(from: sqlStmt)
648
+ else {
649
+ let msg: String = "deleteSQL cannot find a " +
650
+ "WHERE clause"
651
+ throw UtilsSQLCipherError.deleteSQL(message: msg)
652
+ }
653
+ guard let tableName =
654
+ UtilsSQLStatement.extractTableName(from: sqlStmt)
655
+ else {
656
+ let msg: String = "deleteSQL cannot find a " +
657
+ "WHERE clause"
707
658
  throw UtilsSQLCipherError.deleteSQL(message: msg)
708
659
  }
660
+ guard let colNames = try? UtilsSQLStatement
661
+ .extractColumnNames(from: whereClause)
662
+ else {
663
+ let msg = "Did not find column names in the" +
664
+ "WHERE Statement"
665
+ throw UtilsSQLCipherError.deleteSQL(message: msg)
666
+ }
667
+ let curTime = UtilsDelete.getCurrentTimeAsInteger()
668
+
669
+ let setStmt = "sql_deleted = 1"
670
+ // Find REFERENCIES if any and update the sql_deleted
671
+ // column
672
+ let hasToUpdate: Bool = try UtilsDelete
673
+ .findReferencesAndUpdate(mDB: mDB,
674
+ tableName: tableName,
675
+ whereStmt: whereClause,
676
+ initColNames: colNames,
677
+ values: values)
678
+ if hasToUpdate {
679
+ let whereStmt = whereClause.hasSuffix(";")
680
+ ? String(whereClause.dropLast())
681
+ : whereClause
682
+ sqlStmt = "UPDATE \(tableName) SET \(setStmt) " +
683
+ "WHERE \(whereStmt) " +
684
+ "AND sql_deleted = 0;"
685
+ } else {
686
+ sqlStmt = ""
687
+ }
709
688
  }
710
689
  return sqlStmt
711
- } catch UtilsSQLCipherError.findReferencesAndUpdate(let message) {
690
+ } catch UtilsDeleteError.findReferencesAndUpdate(let message) {
712
691
  throw UtilsSQLCipherError.deleteSQL(message: message)
713
692
  } catch UtilsJsonError.isLastModified(let message) {
714
693
  throw UtilsSQLCipherError.deleteSQL(message: message)
@@ -717,306 +696,6 @@ class UtilsSQLCipher {
717
696
  }
718
697
  }
719
698
 
720
- // MARK: - findReferencesAndUpdate
721
-
722
- // swiftlint:disable function_body_length
723
- // swiftlint:disable cyclomatic_complexity
724
- class func findReferencesAndUpdate(mDB: Database, tableName: String,
725
- whereStmt: String,
726
- values: [Any]) throws {
727
- var lastId: Int64 = -1
728
- do {
729
- var references = try getReferences(mDB: mDB,
730
- tableName: tableName)
731
- if references.count <= 0 {
732
- return
733
- }
734
- guard let tableNameWithRefs = references.last else {
735
- return
736
- }
737
- references.removeLast()
738
- // Loop through references
739
- for ref in references {
740
- // get the tableName of the references
741
- let refTable: String = getReferencesTableName(value: ref)
742
- if refTable.count <= 0 {
743
- continue
744
- }
745
- // get the with ref columnName
746
- let withRefsNames: [String] = getWithRefsColumnName(value: ref)
747
- if withRefsNames.count <= 0 {
748
- continue
749
- }
750
- // get the columnName
751
- let colNames: [String] = getReferencesColumnName(value: ref)
752
- if colNames.count <= 0 {
753
- continue
754
- }
755
- // update the where clause
756
- let uWhereStmt: String = updateWhere(whStmt: whereStmt,
757
- withRefs: withRefsNames,
758
- colNames: colNames)
759
-
760
- if uWhereStmt.count <= 0 {
761
- continue
762
- }
763
- var updTableName: String = tableNameWithRefs
764
- var updColNames: [String] = colNames
765
- if tableNameWithRefs == tableName {
766
- updTableName = refTable
767
- updColNames = withRefsNames
768
- }
769
- //update sql_deleted for this references
770
- let stmt = "UPDATE \(updTableName) SET sql_deleted = 1 " +
771
- uWhereStmt
772
- var selValues: [Any] = []
773
- if !values.isEmpty {
774
- var arrVal: [String] = whereStmt.components(separatedBy: "?")
775
- if arrVal[arrVal.count - 1] == ";" {
776
- arrVal.removeLast()
777
- }
778
- for (jdx, val) in arrVal.enumerated() {
779
- for updVal in updColNames {
780
- let indices: [Int] = val.indicesOf(string: updVal)
781
- if indices.count > 0 {
782
- selValues.append(values[jdx])
783
- }
784
- }
785
- }
786
- }
787
-
788
- let resp = try prepareSQL(mDB: mDB, sql: stmt,
789
- values: selValues,
790
- fromJson: false, returnMode: "no")
791
- lastId = resp.0
792
- if lastId == -1 {
793
- let msg = "UPDATE sql_deleted failed for references " +
794
- "table: \(refTable) "
795
- throw UtilsSQLCipherError
796
- .findReferencesAndUpdate(message: msg)
797
- }
798
- }
799
- return
800
- } catch UtilsSQLCipherError.prepareSQL(let message) {
801
- throw UtilsSQLCipherError
802
- .findReferencesAndUpdate(message: message)
803
- } catch UtilsSQLCipherError.querySQL(let message) {
804
- throw UtilsSQLCipherError
805
- .findReferencesAndUpdate(message: message)
806
- }
807
-
808
- }
809
- // swiftlint:enable cyclomatic_complexity
810
- // swiftlint:enable function_body_length
811
-
812
- // MARK: - getReferences
813
-
814
- class func getReferences(mDB: Database, tableName: String)
815
- throws -> [String] {
816
- // find the REFERENCES
817
- var sqlStmt = "SELECT sql FROM sqlite_master "
818
- sqlStmt += "WHERE sql LIKE('%FOREIGN KEY%') AND "
819
- sqlStmt += "sql LIKE('%REFERENCES%') AND "
820
- sqlStmt += "sql LIKE('%\(tableName)%') AND sql LIKE('%ON DELETE%');"
821
- do {
822
- var references: [[String: Any]] = try querySQL(mDB: mDB,
823
- sql: sqlStmt,
824
- values: [])
825
- var retRefs: [String] = []
826
- if references.count > 1 {
827
- references.removeFirst()
828
- if let refValue = references[0]["sql"] as? String {
829
- retRefs = try getRefs(str: refValue)
830
- }
831
- }
832
- return retRefs
833
- } catch UtilsSQLCipherError.getRefs(let message) {
834
- throw UtilsSQLCipherError
835
- .getReferences(message: message)
836
- } catch UtilsSQLCipherError.querySQL(let message) {
837
- throw UtilsSQLCipherError
838
- .getReferences(message: message)
839
- }
840
- }
841
- class func getRefs(str: String) throws -> [String] {
842
- var retRefs: [String] = []
843
- let indicesFK: [Int] = str.indicesOf(string: "FOREIGN KEY")
844
- let indicesOD: [Int] = str.indicesOf(string: "ON DELETE")
845
- if indicesFK.count > 0 && indicesOD.count > 0
846
- && indicesFK.count != indicesOD.count {
847
- let msg: String = "Indices of FOREIGN KEY and ON DELETE not equal"
848
- throw UtilsSQLCipherError.getRefs(message: msg)
849
-
850
- }
851
- for (idx, iFK) in indicesFK.enumerated() {
852
- let ref: String = String(str.stringRange(fromIdx: iFK + 11,
853
- toIdx: indicesOD[idx]))
854
- .trimmingLeadingAndTrailingSpaces()
855
- retRefs.append(ref)
856
- }
857
-
858
- if let range: Range<String.Index> = str
859
- .range(of: "CREATE TABLE", options: .caseInsensitive) {
860
- let index: Int = str
861
- .distance(from: str.startIndex, to: range.lowerBound)
862
- let stmt = String(str.stringRange(fromIdx: index + 13,
863
- toIdx: str.count))
864
- if let oPar = stmt.firstIndex(of: "(") {
865
- let idx: Int = stmt.distance(from: stmt.startIndex, to: oPar)
866
- let tableName: String = String(stmt.stringRange(fromIdx: 0,
867
- toIdx: idx))
868
- .trimmingLeadingAndTrailingSpaces()
869
- retRefs.append(tableName)
870
- }
871
- }
872
-
873
- return retRefs
874
- }
875
-
876
- // MARK: - getReferencesTableName
877
-
878
- class func getReferencesTableName(value: String) -> String {
879
-
880
- var tableName: String = ""
881
- if value.isEmpty {
882
- return tableName
883
- }
884
- let indicesRef: [Int] = value.indicesOf(string: "REFERENCES")
885
- if indicesRef.count > 0 {
886
- let val: String = String(value.stringRange(
887
- fromIdx: indicesRef[0] + 10,
888
- toIdx: value.count))
889
- if let oPar = val.firstIndex(of: "(") {
890
- let idx: Int = val.distance(from: val.startIndex, to: oPar)
891
- tableName = String(val.stringRange(fromIdx: 0,
892
- toIdx: idx))
893
- .trimmingLeadingAndTrailingSpaces()
894
- }
895
- }
896
- return tableName
897
- }
898
-
899
- // MARK: - getWithRefColumnName
900
-
901
- class func getWithRefsColumnName(value: String) -> [String] {
902
-
903
- var colNames: [String] = []
904
- if value.isEmpty {
905
- return colNames
906
- }
907
- let indicesRef: [Int] = value.indicesOf(string: "REFERENCES")
908
- if indicesRef.count > 0 {
909
- let val: String = String(value.stringRange(
910
- fromIdx: 0,
911
- toIdx: indicesRef[0] - 1))
912
- if let oPar = val.firstIndex(of: "(") {
913
- let idxOPar: Int = val.distance(from: val.startIndex, to: oPar)
914
- if let cPar = val.firstIndex(of: ")") {
915
- let idxCPar: Int = val.distance(from: val.startIndex,
916
- to: cPar)
917
-
918
- let colStr: String = String(val
919
- .stringRange(fromIdx: idxOPar + 1,
920
- toIdx: idxCPar))
921
- .trimmingLeadingAndTrailingSpaces()
922
- colNames = colStr.split(separator: ",").map(String.init)
923
- }
924
- }
925
- }
926
- return colNames
927
- }
928
- // MARK: - getReferencesColumnName
929
-
930
- class func getReferencesColumnName(value: String) -> [String] {
931
-
932
- var colNames: [String] = []
933
- if value.isEmpty {
934
- return colNames
935
- }
936
- let indicesRef: [Int] = value.indicesOf(string: "REFERENCES")
937
- if indicesRef.count > 0 {
938
- let val: String = String(value.stringRange(
939
- fromIdx: indicesRef[0] + 10,
940
- toIdx: value.count))
941
- if let oPar = val.firstIndex(of: "(") {
942
- let idxOPar: Int = val.distance(from: val.startIndex, to: oPar)
943
- if let cPar = val.firstIndex(of: ")") {
944
- let idxCPar: Int = val.distance(from: val.startIndex,
945
- to: cPar)
946
-
947
- let colStr: String = String(val
948
- .stringRange(fromIdx: idxOPar + 1,
949
- toIdx: idxCPar))
950
- .trimmingLeadingAndTrailingSpaces()
951
- colNames = colStr.split(separator: ",").map(String.init)
952
-
953
- }
954
- }
955
- }
956
- return colNames
957
- }
958
-
959
- // swiftlint:disable function_body_length
960
- class func updateWhere(whStmt: String, withRefs: [String],
961
- colNames: [String]) -> String {
962
- var whereStmt = ""
963
- if whStmt.count > 0 {
964
- let indicesWhere: [Int] = whStmt.indicesOf(string: "WHERE")
965
- if indicesWhere.count == 0 {
966
- return whereStmt
967
- }
968
- var stmt: String = String(whStmt.stringRange(
969
- fromIdx: indicesWhere[0] + 6,
970
- toIdx: whStmt.count))
971
- if withRefs.count == colNames.count {
972
- for (idx, wRf) in withRefs.enumerated() {
973
- var colType: String = "withRefsNames"
974
- var idxs: [Int] = stmt.indicesOf(string: wRf)
975
- if idxs.count == 0 {
976
- idxs = stmt.indicesOf(string: colNames[idx])
977
- colType = "colNames"
978
- }
979
- if idxs.count > 0 {
980
- var valStr: String = ""
981
- let indicesEqual: [Int] = stmt
982
- .indicesOf(string: "=",
983
- fromIdx: idxs[0])
984
-
985
- if indicesEqual.count > 0 {
986
- let indicesAnd: [Int] = stmt
987
- .indicesOf(string: "AND",
988
- fromIdx: indicesEqual[0])
989
- if indicesAnd.count > 0 {
990
- valStr = String(stmt.stringRange(
991
- fromIdx: indicesEqual[0] + 1,
992
- toIdx: indicesAnd[0] - 1))
993
- stmt = String(stmt.stringRange(
994
- fromIdx: indicesAnd[0] + 3,
995
- toIdx: stmt.count))
996
- } else {
997
- valStr = String(stmt.stringRange(
998
- fromIdx: indicesEqual[0] + 1,
999
- toIdx: stmt.count))
1000
- }
1001
- if idx > 0 {
1002
- whereStmt += " AND "
1003
- }
1004
- if colType == "withRefsNames" {
1005
- whereStmt += colNames[idx] + " = " + valStr
1006
- } else {
1007
- whereStmt += withRefs[idx] + " = " + valStr
1008
- }
1009
- }
1010
- }
1011
-
1012
- }
1013
- whereStmt = "WHERE " + whereStmt
1014
- }
1015
- }
1016
- return whereStmt
1017
- }
1018
- // swiftlint:enable function_body_length
1019
-
1020
699
  // MARK: - querySQL
1021
700
 
1022
701
  class func querySQL(mDB: Database, sql: String,
@@ -1044,7 +723,8 @@ class UtilsSQLCipher {
1044
723
  handle: selectSQLStatement, returnMode: "all")
1045
724
  } catch UtilsSQLCipherError
1046
725
  .fetchColumnInfo(let message) {
1047
- throw UtilsSQLCipherError.querySQL(message: message)
726
+ throw UtilsSQLCipherError
727
+ .querySQL(message: message)
1048
728
  }
1049
729
  }
1050
730
  } else {
@@ -1071,7 +751,8 @@ class UtilsSQLCipher {
1071
751
 
1072
752
  // swiftlint:disable function_body_length
1073
753
  // swiftlint:disable cyclomatic_complexity
1074
- class func fetchColumnInfo(handle: OpaquePointer?, returnMode: String)
754
+ class func fetchColumnInfo(handle: OpaquePointer?,
755
+ returnMode: String)
1075
756
  throws -> [[String: Any]] {
1076
757
  var result: [[String: Any]] = []
1077
758
  var columnCount: Int32 = 0
@@ -1099,17 +780,20 @@ class UtilsSQLCipher {
1099
780
  }
1100
781
  switch sqlite3_column_type(handle, Int32(index)) {
1101
782
  case SQLITE_INTEGER:
1102
- let val: Int64 = sqlite3_column_int64(handle, index)
783
+ let val: Int64 = sqlite3_column_int64(handle,
784
+ index)
1103
785
  rowData[String(cString: name)] = val
1104
786
  case SQLITE_FLOAT:
1105
- let val: Double = sqlite3_column_double(handle, index)
787
+ let val: Double = sqlite3_column_double(handle,
788
+ index)
1106
789
  rowData[String(cString: name)] = val
1107
790
  case SQLITE_BLOB:
1108
- if let dataBlob = sqlite3_column_blob(handle, index) {
1109
- let dataBlobLength = sqlite3_column_bytes(handle, index)
791
+ if let dataBlob = sqlite3_column_blob(handle,
792
+ index) {
793
+ let dataBlobLength = sqlite3_column_bytes(
794
+ handle, index)
1110
795
  let data = Data(bytes: dataBlob,
1111
796
  count: Int(dataBlobLength))
1112
- // rowData[String(cString: name)] = data.base64EncodedString()
1113
797
  rowData[String(cString: name)] = data.bytes
1114
798
  } else {
1115
799
  rowData[String(cString: name)] = NSNull()
@@ -1126,7 +810,8 @@ class UtilsSQLCipher {
1126
810
  case SQLITE_NULL:
1127
811
  rowData[String(cString: name)] = NSNull()
1128
812
  case let type:
1129
- var message = "Error: fetchColumnInfo column_type \(type) "
813
+ var message = "Error: fetchColumnInfo " +
814
+ "column_type \(type) "
1130
815
  message.append("failed")
1131
816
  throw UtilsSQLCipherError
1132
817
  .fetchColumnInfo(message: message)
@@ -1165,14 +850,20 @@ class UtilsSQLCipher {
1165
850
  var resArr: [String] = []
1166
851
  for stmt in stmtArr {
1167
852
  let trimStmt = stmt
1168
- .trimmingLeadingAndTrailingSpaces().prefix(11).uppercased()
853
+ .trimmingLeadingAndTrailingSpaces().prefix(11)
854
+ .uppercased()
1169
855
  if trimStmt == "DELETE FROM" &&
1170
856
  stmt.localizedCaseInsensitiveContains("WHERE") {
1171
- let whereStmt = stmt.trimmingLeadingAndTrailingSpaces()
857
+ let whereStmt = stmt
858
+ .trimmingLeadingAndTrailingSpaces()
1172
859
  do {
1173
- let rStmt: String = try deleteSQL(mDB: mDB, sql: whereStmt, values: [])
1174
- resArr.append(rStmt)
1175
- } catch UtilsSQLCipherError.deleteSQL(let message) {
860
+ let rStmt: String = try deleteSQL(
861
+ mDB: mDB, sql: whereStmt, values: [])
862
+ if !rStmt.isEmpty {
863
+ resArr.append(rStmt)
864
+ }
865
+ } catch UtilsSQLCipherError
866
+ .deleteSQL(let message) {
1176
867
  let msg = "Error: execute \(message)"
1177
868
  throw UtilsSQLCipherError.execute(message: msg)
1178
869
  }
@@ -1182,7 +873,7 @@ class UtilsSQLCipher {
1182
873
  }
1183
874
  sqlStmt = resArr.joined(separator: ";")
1184
875
  }
1185
-
876
+ let curTime = UtilsDelete.getCurrentTimeAsInteger()
1186
877
  let returnCode: Int32 = sqlite3_exec(mDB.mDb, sqlStmt, nil,
1187
878
  nil, nil)
1188
879
  if returnCode != SQLITE_OK {
@@ -1198,7 +889,8 @@ class UtilsSQLCipher {
1198
889
 
1199
890
  // MARK: - DeleteDB
1200
891
 
1201
- class func deleteDB(databaseLocation: String, databaseName: String) throws {
892
+ class func deleteDB(databaseLocation: String,
893
+ databaseName: String) throws {
1202
894
  do {
1203
895
  let dir: URL = try UtilsFile
1204
896
  .getFolderURL(folderPath: databaseLocation)
@@ -1225,7 +917,8 @@ class UtilsSQLCipher {
1225
917
  // MARK: - ExecuteSet
1226
918
 
1227
919
  // swiftlint:disable function_body_length
1228
- class func executeSet(mDB: Database, set: [[String: Any]], returnMode: String)
920
+ class func executeSet(mDB: Database, set: [[String: Any]],
921
+ returnMode: String)
1229
922
  throws -> (Int64, [[String: Any]]) {
1230
923
  var msg: String = "Error executeSet: "
1231
924
  if !mDB.isDBOpen() {
@@ -1247,13 +940,17 @@ class UtilsSQLCipher {
1247
940
  message: "No values given")
1248
941
  }
1249
942
  var respSet: [[String: Any]] = []
1250
- let isArray = values.count > 0 ? UtilsSQLCipher.parse(mVar: values[0]) : false
943
+ var isArray = false
944
+ if values.count > 0 {
945
+ isArray = UtilsSQLCipher.parse(mVar: values[0])
946
+ }
1251
947
  if isArray {
1252
948
  if let arrValues = values as? [[Any]] {
1253
949
  for vals in arrValues {
1254
950
  let resp = try UtilsSQLCipher
1255
951
  .prepareSQL(mDB: mDB, sql: sql,
1256
- values: vals, fromJson: false,
952
+ values: vals,
953
+ fromJson: false,
1257
954
  returnMode: returnMode)
1258
955
  lastId = resp.0
1259
956
  respSet = resp.1