2 * Copyright (c) 2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "keychain/securityd/SecDbItem.h"
25 #include <utilities/SecDb.h>
27 #define CKKSNilToNSNull(obj) \
30 o ? o : [NSNull null]; \
33 #define CKKSIsNull(x) \
36 ((y == nil) || ([y isEqual:[NSNull null]])); \
38 #define CKKSUnbase64NullableString(x) (!CKKSIsNull(x) ? [[NSData alloc] initWithBase64EncodedString:x options:0] : nil)
40 NS_ASSUME_NONNULL_BEGIN
42 // A holder of a possibly-present string value.
43 // Also includes some convenience methods for parsing the string in different manners.
44 // If the value is nil, then the convenience methods return nil (or false/0).
45 @interface CKKSSQLResult
: NSObject
46 - (instancetype
)init
:(NSString
* _Nullable
)value
;
49 - (NSInteger
)asNSInteger
;
50 - (NSString
* _Nullable
)asString
;
51 - (NSNumber
* _Nullable
)asNSNumberInteger
;
52 - (NSDate
* _Nullable
)asISO8601Date
;
53 - (NSData
* _Nullable
)asBase64DecodedData
;
56 // These thread-local variables should be set by your database layer
57 // This ensures that all SQL write operations are performed under the protection of a transaction.
58 // Use [CKKSSQLDatabaseObject +performCKKSTransaction] to get one of these if you don't have any other mechanism.
59 extern __thread
bool CKKSSQLInTransaction
;
60 extern __thread
bool CKKSSQLInWriteTransaction
;
62 typedef NS_ENUM(uint8_t, CKKSDatabaseTransactionResult
) {
63 CKKSDatabaseTransactionRollback
= 0,
64 CKKSDatabaseTransactionCommit
= 1,
67 // A database provider must provide these operations.
68 @protocol CKKSDatabaseProviderProtocol
69 - (void)dispatchSyncWithSQLTransaction
:(CKKSDatabaseTransactionResult (^)(void))block
;
70 - (void)dispatchSyncWithReadOnlySQLTransaction
:(void (^)(void))block
;
72 // Used to maintain lock ordering.
73 - (BOOL
)insideSQLTransaction
;
76 @interface CKKSSQLDatabaseObject
: NSObject
<NSCopying
>
78 @
property (copy
) NSDictionary
<NSString
*, NSString
*>* originalSelfWhereClause
;
80 - (bool)saveToDatabase
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
81 - (bool)saveToDatabaseWithConnection
:(SecDbConnectionRef _Nullable
)conn
82 error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
83 - (bool)deleteFromDatabase
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
84 + (bool)deleteAll
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
86 // Load the object from the database, and error if it doesn't exist
87 + (instancetype _Nullable
)fromDatabaseWhere
:(NSDictionary
*)whereDict error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
89 // Load the object from the database, and return nil if it doesn't exist
90 + (instancetype _Nullable
)tryFromDatabaseWhere
:(NSDictionary
*)whereDict
91 error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
93 + (NSArray
*)all
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
94 + (NSArray
*)allWhere
:(NSDictionary
* _Nullable
)whereDict error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
96 // Like all() above, but with limits on how many will return
97 + (NSArray
*)fetch
:(size_t)count error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
98 + (NSArray
*)fetch
:(size_t)count
99 where
:(NSDictionary
* _Nullable
)whereDict
100 error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
101 + (NSArray
*)fetch
:(size_t)count
102 where
:(NSDictionary
* _Nullable
)whereDict
103 orderBy
:(NSArray
* _Nullable
)orderColumns
104 error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
107 + (bool)saveToDatabaseTable
:(NSString
*)table
108 row
:(NSDictionary
*)row
109 connection
:(SecDbConnectionRef _Nullable
)dbconn
110 error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
111 + (bool)deleteFromTable
:(NSString
*)table
112 where
:(NSDictionary
* _Nullable
)whereDict
113 connection
:(SecDbConnectionRef _Nullable
)dbconn
114 error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
116 + (bool)queryDatabaseTable
:(NSString
*)table
117 where
:(NSDictionary
* _Nullable
)whereDict
118 columns
:(NSArray
*)names
119 groupBy
:(NSArray
* _Nullable
)groupColumns
120 orderBy
:(NSArray
* _Nullable
)orderColumns
122 processRow
:(void (^)(NSDictionary
<NSString
*, CKKSSQLResult
*>*))processRow
123 error
:(NSError
* _Nullable __autoreleasing
* _Nullable
)error
;
125 + (bool)queryMaxValueForField
:(NSString
*)maxField
126 inTable
:(NSString
*)table
127 where
:(NSDictionary
* _Nullable
)whereDict
128 columns
:(NSArray
*)names
129 processRow
:(void (^)(NSDictionary
<NSString
*, CKKSSQLResult
*>*))processRow
;
131 // Note: if you don't use the SQLDatabase methods of loading yourself,
132 // make sure you call this directly after loading.
133 - (instancetype
)memoizeOriginalSelfWhereClause
;
135 + (NSString
*)quotedString
:(NSString
*)string
;
137 + (BOOL
)performCKKSTransaction
:(CKKSDatabaseTransactionResult (^)(void))block
;
139 #pragma mark - Subclasses must implement the following:
141 // Given a row from the database, make this object
142 + (instancetype _Nullable
)fromDatabaseRow
:(NSDictionary
<NSString
*, CKKSSQLResult
*>*)row
;
144 // Return the columns, in order, that this row wants to fetch
145 + (NSArray
<NSString
*>*)sqlColumns
;
147 // Return the table name for objects of this class
148 + (NSString
*)sqlTable
;
150 // Return the columns and values, in order, that this row wants to save
151 - (NSDictionary
<NSString
*, NSString
*>*)sqlValues
;
153 // Return a set of key-value pairs that will uniquely find This Row in the table
154 - (NSDictionary
<NSString
*, NSString
*>*)whereClauseToFindSelf
;
156 //- (instancetype)copyWithZone:(NSZone* _Nullable)zone;
159 // Helper class to use with where clauses
160 // If you pass in one of these in a where dictionary instead of a concrete value, columnName will be
161 // used directly, instead of binding as a named parameter. Therefore, it's essential to use
162 // compile-time constants for both fields.
164 typedef NS_ENUM(uint64_t, CKKSSQLWhereComparator
) {
165 CKKSSQLWhereComparatorEquals
= 1,
166 CKKSSQLWhereComparatorNotEquals
= 2,
167 CKKSSQLWhereComparatorGreaterThan
= 3,
168 CKKSSQLWhereComparatorLessThan
= 4,
171 NSString
* CKKSSQLWhereComparatorAsString(CKKSSQLWhereComparator comparator
);
173 // This typedef is to ensure that CKKSSQLWhereColumn can only ever produce static strings
174 typedef NS_ENUM(uint64_t, CKKSSQLWhereColumnName
) {
175 CKKSSQLWhereColumnNameUUID
= 1,
176 CKKSSQLWhereColumnNameParentKeyUUID
= 2,
178 NSString
* CKKSSQLWhereColumnNameAsString(CKKSSQLWhereColumnName columnName
);
180 @interface CKKSSQLWhereColumn
: NSObject
181 @property CKKSSQLWhereComparator sqlOp
;
182 @property CKKSSQLWhereColumnName columnName
;
183 - (instancetype
)initWithOperation
:(CKKSSQLWhereComparator
)op columnName
:(CKKSSQLWhereColumnName
)column
;
184 + (instancetype
)op
:(CKKSSQLWhereComparator
)op column
:(CKKSSQLWhereColumnName
)columnName
;
187 // Unlike CKKSSQLWhereColumn, this will insert the value as a parameter in a prepared statement
188 // but gives you the flexbility to inject a sqlOp. sqlOp must be a compile-time constant.
189 @interface CKKSSQLWhereValue
: NSObject
190 @property CKKSSQLWhereComparator sqlOp
;
191 @property NSString
* value
;
192 - (instancetype
)initWithOperation
:(CKKSSQLWhereComparator
)op value
:(NSString
*)value
;
193 + (instancetype
)op
:(CKKSSQLWhereComparator
)op value
:(NSString
*)value
;
196 @interface CKKSSQLWhereIn
: NSObject
197 @property NSArray
<NSString
*>* values
;
198 - (instancetype
)initWithValues
:(NSArray
<NSString
*>*)values
;
202 NS_ASSUME_NONNULL_END