Skip to content

Commit 57e11ee

Browse files
committed
[RFC] Add validate statement bridge method
1 parent 0ac9a3c commit 57e11ee

File tree

3 files changed

+112
-45
lines changed

3 files changed

+112
-45
lines changed

AIBSQLite.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77

88

9-
#import <RCTBridgeModule.h>
9+
#import "./node_modules/react-native/React/Base/RCTBridgeModule.h"
1010

1111
@interface AIBSQLite : NSObject <RCTBridgeModule>
1212

AIBSQLite.m

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
//
77

88
#import "AIBSQLite.h"
9-
#import "RCTLog.h"
10-
#import "RCTUtils.h"
9+
#import "./node_modules/react-native/React/Base/RCTLog.h"
10+
#import "./node_modules/react-native/React/Base/RCTUtils.h"
1111
#import <Foundation/Foundation.h>
12-
#import "RCTBridge.h"
13-
#import "RCTEventDispatcher.h"
12+
#import "./node_modules/react-native/React/Base/RCTBridge.h"
13+
#import "./node_modules/react-native/React/Base/RCTEventDispatcher.h"
1414

1515
#import <sqlite3.h>
1616

@@ -159,50 +159,101 @@ - (id) init
159159
});
160160
}
161161

162+
RCT_EXPORT_METHOD(validateStatement: (NSString *)databaseId sql: (NSString *)sql andParams: (NSArray *)params callback: (RCTResponseSenderBlock)callback)
163+
{
164+
if (!callback) {
165+
RCTLogError(@"Called prepareStatement without a callback.");
166+
}
167+
168+
dispatch_async(AIBSQLiteQueue(), ^{
169+
Database *database = [openDatabases valueForKey:databaseId];
170+
if (database == nil) {
171+
callback(@[@"No open database found", [NSNull null]]);
172+
return;
173+
}
174+
175+
sqlite3 *db = [database db];
176+
sqlite3_stmt *stmt;
177+
178+
int rc = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
179+
if (rc != SQLITE_OK) {
180+
callback(@[[NSString stringWithUTF8String:sqlite3_errmsg(db)]]);
181+
}
182+
183+
for (int i=0; i < [params count]; i++){
184+
NSObject *param = [params objectAtIndex: i];
185+
if ([param isKindOfClass: [NSString class]]) {
186+
NSString *str = (NSString*) param;
187+
int strLength = (int) [str lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
188+
sqlite3_bind_text(stmt, i+1, [str UTF8String], strLength, SQLITE_TRANSIENT);
189+
} else if ([param isKindOfClass: [NSNumber class]]) {
190+
sqlite3_bind_double(stmt, i+1, [(NSNumber *)param doubleValue]);
191+
} else if ([param isKindOfClass: [NSNull class]]) {
192+
sqlite3_bind_null(stmt, i+1);
193+
} else {
194+
sqlite3_finalize(stmt);
195+
callback(@[@"Parameters must be either numbers or strings" ]);
196+
return;
197+
}
198+
}
199+
200+
// Step once to see if we catch any errors
201+
rc = sqlite3_step(stmt);
202+
if (rc != SQLITE_OK) {
203+
callback(@[[NSString stringWithUTF8String:sqlite3_errmsg(db)]]);
204+
return;
205+
}
206+
207+
// We are done validating so close out the statement and return success
208+
sqlite3_finalize(stmt);
209+
callback(@[[NSNull null]]);
210+
});
211+
}
212+
162213
RCT_EXPORT_METHOD(prepareStatement: (NSString *)databaseId sql: (NSString *)sql andParams: (NSArray *)params callback: (RCTResponseSenderBlock)callback)
163214
{
164-
if (!callback) {
165-
RCTLogError(@"Called prepareStatement without a callback.");
215+
if (!callback) {
216+
RCTLogError(@"Called prepareStatement without a callback.");
217+
}
218+
219+
dispatch_async(AIBSQLiteQueue(), ^{
220+
Database *database = [openDatabases valueForKey:databaseId];
221+
if (database == nil) {
222+
callback(@[@"No open database found", [NSNull null]]);
223+
return;
166224
}
225+
sqlite3 *db = [database db];
226+
sqlite3_stmt *stmt;
167227

168-
dispatch_async(AIBSQLiteQueue(), ^{
169-
Database *database = [openDatabases valueForKey:databaseId];
170-
if (database == nil) {
171-
callback(@[@"No open database found", [NSNull null]]);
172-
return;
173-
}
174-
sqlite3 *db = [database db];
175-
sqlite3_stmt *stmt;
176-
177-
int rc = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
178-
if (rc != SQLITE_OK) {
179-
callback(@[[NSString stringWithUTF8String:sqlite3_errmsg(db)]]);
180-
return;
181-
}
182-
183-
for (int i=0; i < [params count]; i++){
184-
NSObject *param = [params objectAtIndex: i];
185-
if ([param isKindOfClass: [NSString class]]) {
186-
NSString *str = (NSString*) param;
187-
int strLength = (int) [str lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
188-
sqlite3_bind_text(stmt, i+1, [str UTF8String], strLength, SQLITE_TRANSIENT);
189-
} else if ([param isKindOfClass: [NSNumber class]]) {
190-
sqlite3_bind_double(stmt, i+1, [(NSNumber *)param doubleValue]);
191-
} else if ([param isKindOfClass: [NSNull class]]) {
192-
sqlite3_bind_null(stmt, i+1);
193-
} else {
194-
sqlite3_finalize(stmt);
195-
callback(@[@"Parameters must be either numbers or strings" ]);
196-
return;
197-
}
198-
}
199-
200-
NSString *statementId = [[NSNumber numberWithInt: nextId++] stringValue];
201-
Statement *statement = [[Statement alloc] initWithSqliteStmt: stmt];
202-
[[database statements] setValue: statement forKey:statementId];
203-
204-
callback(@[[NSNull null], statementId]);
205-
});
228+
int rc = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL);
229+
if (rc != SQLITE_OK) {
230+
callback(@[[NSString stringWithUTF8String:sqlite3_errmsg(db)]]);
231+
return;
232+
}
233+
234+
for (int i=0; i < [params count]; i++){
235+
NSObject *param = [params objectAtIndex: i];
236+
if ([param isKindOfClass: [NSString class]]) {
237+
NSString *str = (NSString*) param;
238+
int strLength = (int) [str lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
239+
sqlite3_bind_text(stmt, i+1, [str UTF8String], strLength, SQLITE_TRANSIENT);
240+
} else if ([param isKindOfClass: [NSNumber class]]) {
241+
sqlite3_bind_double(stmt, i+1, [(NSNumber *)param doubleValue]);
242+
} else if ([param isKindOfClass: [NSNull class]]) {
243+
sqlite3_bind_null(stmt, i+1);
244+
} else {
245+
sqlite3_finalize(stmt);
246+
callback(@[@"Parameters must be either numbers or strings" ]);
247+
return;
248+
}
249+
}
250+
251+
NSString *statementId = [[NSNumber numberWithInt: nextId++] stringValue];
252+
Statement *statement = [[Statement alloc] initWithSqliteStmt: stmt];
253+
[[database statements] setValue: statement forKey:statementId];
254+
255+
callback(@[[NSNull null], statementId]);
256+
});
206257
}
207258

208259
RCT_EXPORT_METHOD(stepStatement:(NSString *)databaseId statementId: (NSString *) statementId callback:(RCTResponseSenderBlock)callback)

sqlite3.ios.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ Database.prototype = {
3333
return this._databaseName;
3434
},
3535

36+
validateSQL (
37+
sql: string,
38+
params: Array<?(number|string)>,
39+
completeCallback: ((error: ?SQLite3Error) => void)
40+
): void {
41+
this._addAction(completeCallback, (callback) => {
42+
NativeModules.AIBSQLite.validateStatement(this._databaseId, sql, params, (error) => {
43+
if (error) {
44+
completeCallback(new SQLite3Error(error));
45+
return;
46+
}
47+
completeCallback(null);
48+
});
49+
});
50+
},
51+
3652
executeSQL (
3753
sql: string,
3854
params: Array<?(number|string)>,

0 commit comments

Comments
 (0)