-
Notifications
You must be signed in to change notification settings - Fork 238
/
GTMSQLite.h
736 lines (663 loc) · 23.7 KB
/
GTMSQLite.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
//
// GTMSQLite.h
//
// Copyright 2006-2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
//
// This class is a convenience wrapper for SQLite storage with
// release/retain semantics. In its most basic form, that is all this
// class offers. You have the option of activating "CFAdditions" on
// init which patches or overrides the following SQLite functionality:
//
// - Strings you pass through the API layer will always be converted
// to precomposed UTF-8 with compatibility mapping
// (kCFStringNormalizationFormKC). This is done in an attempt to
// make SQLite correctly handle string equality for composed
// character sequences. This change applies only to
// NSStrings/CFStrings passed through the GTMSQLiteDatabase or
// GTMSQLiteStatement. Direct access to the database using the
// underlying sqlite3_* handles is not affected.
//
// - The SQL UPPER/LOWER functions are replaced with CFString-based
// implementations which (unlike SQLite's native implementation)
// handle case conversion outside the ASCII range. These
// implementations seem to be 20-30% slower than the SQLite
// implementations but may be worth it for accuracy.
//
// - The SQLite "NOCASE" collation is replaced with a CFString-based
// collation that is case insensitive but still uses literal
// comparison (composition-sensitive).
//
// - Additional collation sequences can be created by using these keywords
// separated by underscores. Each option corresponds to a CFStringCompareFlags
// option.
// NOCASE (kCFCompareCaseInsensitive)
// NONLITERAL (kCFCompareNonliteral)
// LOCALIZED (kCFCompareLocalized)
// NUMERIC (kCFCompareNumerically)
// These additional options are available when linking with the 10.5 SDK:
// NODIACRITIC (kCFCompareDiacriticInsensitive)
// WIDTHINSENSITIVE (kCFCompareWidthInsensitive)
//
// Ordering of the above options can be changed by adding "REVERSE".
//
// Thus, for a case-insensitive, width-insensitive, composition-insensitive
// comparison that ignores diacritical marks and sorts in reverse use:
//
// NOCASE_NONLITERAL_NODIACRITIC_WIDTHINSENSITIVE_REVERSE
//
// - SQL LIKE and GLOB commands are implemented with CFString/CFCharacterSet
// comparisons. As with the other CF additions, this gives us better handling
// of case and composed character sequences. However, whereever reasonable,
// SQLite semantics have been retained. Specific notes:
//
// * LIKE is case insensitive and uses non-literal comparison
// (kCFCompareNonliteral) by default. It is possible to modify this
// behavior using the accessor methods. You must use those methods
// instead of the SQLite "PRAGMA case_sensitive_like" in order for them
// to interact properly with our CFString implementations.
//
// * ESCAPE clauses to LIKE are honored, but the escape character must
// be expressable as a single UniChar (UTF16). The escaped characters in
// LIKE only escape the following UniChar, not a composed character
// sequence. This is not viewed as a limitation since the use of ESCAPE
// is typically only for characters with meaning to SQL LIKE ('%', '_')
// all of which can be expressed as a single UniChar.
//
// * GLOB is by default case sensitive but non-literal. Again, accessor
// methods are available to change this behavior.
//
// * Single character pattern matches ('_' for LIKE, '?' for GLOB) will
// always consume a full composed character sequence.
//
// * As with the standard SQLite implementation, character set comparisons
// are only available for GLOB.
//
// * Character set comparisons are always literal and case sensitive and do
// not take into account composed character sequences. Essentially
// character sets should always be expressed as a set of single UniChars
// or ranges between single UniChars.
//
#import <Foundation/Foundation.h>
#import <sqlite3.h>
NS_ASSUME_NONNULL_BEGIN
/// Wrapper for SQLite with release/retain semantics and CFString convenience features
@interface GTMSQLiteDatabase : NSObject {
@protected
sqlite3 *db_; // strong
NSString *path_; // strong
int timeoutMS_;
BOOL hasCFAdditions_;
CFOptionFlags likeOptions_;
CFOptionFlags globOptions_;
NSMutableArray *userArgDataPool_; // strong
}
// Get the numeric version number of the SQLite library (compiled in value
// for SQLITE_VERSION_NUMBER).
//
// Returns:
// Integer version number
//
+ (int)sqliteVersionNumber;
// Get the string version number of the SQLite library.
//
// Returns:
// Autoreleased NSString version string
//
+ (NSString *)sqliteVersionString;
// Open a database instance on a file-based database.
//
// Args:
// path: Path to the database. If it does not exist, an empty database will be created only if
// the SQLITE_OPEN_CREATE flag is specified.
// withCFAdditions: If true, the SQLite database will include CFString
// based string functions and collation sequences. See
// the class header for information on these differences
// and performance impact.
// utf8: If true, the path argument is interpreted as UTF-8. If false, it's interpreted as
// UTF-16 in the native byte order.
// flags: The SQLite flags to use when opening a DB file (e.g. SQLITE_OPEN_READWRITE). This
// argument is ignored if utf8 is false.
// err: Result code from SQLite. If nil is returned by this function
// check the result code for the error. If NULL no result code is
// reported.
//
- (nullable instancetype)initWithPath:(NSString *)path
withCFAdditions:(BOOL)additions
utf8:(BOOL)useUTF8
flags:(int)flags
errorCode:(nullable int *)err;
// Create and open a database instance on a file-based database.
//
// Args:
// path: Path to the database. If it does not exist an empty database
// will be created.
// withCFAdditions: If true, the SQLite database will include CFString
// based string functions and collation sequences. See
// the class header for information on these differences
// and performance impact.
// utf8: If true, the path argument is interpreted as UTF-8. If false, it's interpreted as
// UTF-16 in the native byte order.
// err: Result code from SQLite. If nil is returned by this function
// check the result code for the error. If NULL no result code is
// reported.
//
- (nullable instancetype)initWithPath:(NSString *)path
withCFAdditions:(BOOL)additions
utf8:(BOOL)useUTF8
errorCode:(nullable int *)err;
// Create and open a memory-based database. Memory-based databases
// cannot be shared amongst threads, and each instance is unique. See
// SQLite documentation for details.
//
// For argument details see [... initWithPath:withCFAdditions:errorCode:]
//
- (nullable instancetype)initInMemoryWithCFAdditions:(BOOL)additions
utf8:(BOOL)useUTF8
errorCode:(nullable int *)err;
// Get the underlying SQLite database handle. In general you should
// never do this, if you do use this be careful with how you compose
// and decompse strings you pass to the database.
//
// Returns:
// sqlite3 pointer
//
- (sqlite3 *)sqlite3DB;
// Enable/Disable the database synchronous mode. Disabling
// synchronous mode results in much faster insert throughput at the
// cost of safety. See the SQlite documentation for details.
//
// Args:
// enable: Boolean flag to determine mode.
//
- (void)synchronousMode:(BOOL)enable;
// Check if this database instance has our CFString functions and collation
// sequences (see top of file for details).
//
// Returns:
// YES if the GTMSQLiteDatabase instance has our CF additions
//
- (BOOL)hasCFAdditions;
// Set comparison options for the "LIKE" operator for databases with
// our CF addtions active.
//
// Args:
// options: CFStringCompareFlags value. Note that a limited list
// of options are supported. For example one cannot
// use kCFCompareBackwards as an option.
//
- (void)setLikeComparisonOptions:(CFOptionFlags)options;
// Get current comparison options for the "LIKE" operator in a database
// with our CF additions active.
//
// Returns:
// Current comparison options or zero if CF additions are inactive.
//
- (CFOptionFlags)likeComparisonOptions;
// Set comparison options for the "GLOB" operator for databases with
// our CF addtions active.
//
// Args:
// options: CFStringCompareFlags value. Note that a limited list
// of options are supported. For example one cannot
// use kCFCompareBackwards as an option.
//
- (void)setGlobComparisonOptions:(CFOptionFlags)options;
// Get current comparison options for the "GLOB" operator in a database
// with our CF additions active.
//
// Returns:
// Current comparison options or zero if CF additions are inactive.
//
- (CFOptionFlags)globComparisonOptions;
// Obtain the last error code from the database
//
// Returns:
// SQLite error code, if no error is pending returns SQLITE_OK
//
- (int)lastErrorCode;
// Obtain an error string for the last error from the database
//
// Returns:
// Autoreleased NSString error message
//
- (nullable NSString *)lastErrorString;
// Obtain a count of rows added, mmodified or deleted by the most recent
// statement. See sqlite3_changes() for details and limitations.
//
// Returns:
// Row count
//
- (int)lastChangeCount;
// Obtain a count of rows added, mmodified or deleted since the database
// was opened. See sqlite3_total_changes() for details and limitations.
//
// Returns:
// Row count
//
- (int)totalChangeCount;
// Obtain the last insert row ID
//
// Returns:
// 64-bit row ID
//
- (unsigned long long)lastInsertRowID;
// Interrupt any currently running database operations as soon as possible.
// Running operations will receive a SQLITE_INTERRUPT and will need to
// handle it correctly (this is the callers problem to deal with).
//
- (void)interrupt;
// Set the timeout value in milliseconds. This is a database global affecting
// all running and future statements.
//
// Args:
// timeoutMS: Integer count in ms SQLite will wait for the database to
// unlock before giving up and returning SQLITE_BUSY. A value
// of 0 or less means the database always returns immediately.
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)setBusyTimeoutMS:(int)timeoutMS;
// Get the current busy timeout in milliseconds.
//
// Returns:
// Current database busy timeout value in ms, 0 or less means no timeout.
//
- (int)busyTimeoutMS;
// Execute a string containing one or more SQL statements. No returned data
// is available, use GTMSQLiteStatement for that usage.
//
// Args:
// sql: Raw SQL statement to prepare. It is the caller's responsibility
// to properly escape the SQL.
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)executeSQL:(NSString *)sql;
// Convenience method to start a deferred transaction (most common case).
//
// Returns:
// YES if the transaction started successfully
//
- (BOOL)beginDeferredTransaction;
// Convenience method to roll back a transaction.
//
// Returns:
// YES if the transaction rolled back successfully
//
- (BOOL)rollback;
// Convenience method to commit a transaction.
//
// Returns:
// YES if the transaction committed successfully
//
- (BOOL)commit;
@end
// Wrapper class for SQLite statements with retain/release semantics.
// Attempts to behave like an NSEnumerator, however you should bind
// your values before beginning enumeration and unlike NSEnumerator,
// a reset is supported.
//
// The GTMSQLiteDatabase class has options to modify some SQL
// functions and force particular string representations. This class
// honors the database preferences for those options. See the
// GTMSQLiteDatabase header for details.
/// Wrapper class for SQLite statements with retain/release
/// semantics.
@interface GTMSQLiteStatement : NSObject {
@protected
sqlite3_stmt *statement_;
BOOL hasCFAdditions_;
}
#pragma mark Creation, Access and Finalization
// Create an autoreleased prepared statement, see initWithSQL: for arguments.
//
// NOTE: Even though this object is autoreleased you MUST call
// [finalizeStatement] on this when your done. See the init for explanation.
//
// Returns:
// Autoreleased GTMSQLiteStatement
//
+ (nullable instancetype)statementWithSQL:(NSString *)sql
inDatabase:(GTMSQLiteDatabase *)gtmdb
errorCode:(nullable int *)err;
// Designated initializer, create a prepared statement. Positional and named
// parameters are supported, see the SQLite documentation.
//
// NOTE: Although this object will clean up its statement when deallocated,
// you are REQUIRED to "finalize" the statement when you are
// through with it. Failing to do this will prevent the database from allowing
// new transactions or queries. In other words, leaving an instance on the
// autorelease pool unfinalized may interfere with other database usage if any
// caller sharing the database uses transactions.
//
// Args:
// sql: Raw SQL statement to prepare. It is the caller's responsibility
// to properly escape the SQL and make sure that the SQL contains
// only _one_ statement. Additional statements are silently ignored.
// db: The GTMSQLiteDatabase (not retained)
// err: Result code from SQLite. If nil is returned by this function
// check the result code for the error. If NULL no result code is
// reported.
//
- (nullable instancetype)initWithSQL:(NSString *)sql
inDatabase:(GTMSQLiteDatabase *)gtmdb
errorCode:(nullable int *)err;
// Get the underlying SQLite statement handle. In general you should never
// do this, if you do use this be careful with how you compose and
// decompse strings you pass to the database.
//
// Returns:
// sqlite3_stmt pointer
//
- (sqlite3_stmt *)sqlite3Statement;
// Finalize the statement, allowing other transactions to start on the database
// This method MUST be called when you are done with a statement. Failure to
// do so means that the database will not be torn down properly when it's
// retain count drops to 0 or GC collects it.
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)finalizeStatement;
#pragma mark Parameters and Binding
// Get the number of parameters that can be bound in the prepared statement.
//
// Returns:
// Integer count of parameters or -1 on error
//
- (int)parameterCount;
// Get the position of a parameter with a given name.
//
// Args:
// paramName: String name of the parameter, including any leading punctuation
// (see SQLite docs)
//
// Returns:
// 1-based parameter position index or -1 on error
//
- (int)positionOfParameterNamed:(NSString *)paramName;
// Get the name of a parameter at a particular index.
//
// Args:
// position: Parameter position (1-based index)
//
// Returns:
// Autoreleased string name of the parameter, including any leading
// punctuation (see SQLite docs) or nil on error.
//
- (nullable NSString *)nameOfParameterAtPosition:(int)position;
// Bind a NULL at a given position
//
// Args:
// position: Parameter position (1-based index)
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindSQLNullAtPosition:(int)position;
// Bind a blob parameter at a given position index to a raw pointer and
// length. The data will be copied by SQLite
//
// Args:
// position: Parameter position (1-based index)
// bytes: Raw pointer to the data to copy/bind
// length: Number of bytes in the blob
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindBlobAtPosition:(int)position bytes:(void *)bytes length:(int)length;
// Bind an NSData as a blob at a given position. The data will be copied
// by SQLite.
//
// Args:
// position: Parameter position (1-based index)
// data: NSData to convert to blob
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindBlobAtPosition:(int)position data:(NSData *)data;
// Bind a double at the given position (for floats convert to double).
//
// Args:
// position: Parameter position (1-based index)
// value: Double to bind
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindDoubleAtPosition:(int)position value:(double)value;
// Bind an NSNumber as a double value at the given position.
//
// Args:
// position: Parameter position (1-based index)
// number: NSNumber to bind
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindNumberAsDoubleAtPosition:(int)position number:(NSNumber *)number;
// Bind a 32-bit integer at the given position.
//
// Args:
// position: Parameter position (1-based index)
// value: Integer to bind
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindInt32AtPosition:(int)position value:(int)value;
// Bind an NSNumber as a 32-bit integer value at the given position.
//
// Args:
// position: Parameter position (1-based index)
// number: NSNumber to bind
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindNumberAsInt32AtPosition:(int)position number:(NSNumber *)number;
// Bind a 64-bit integer at the given position.
//
// Args:
// position: Parameter position (1-based index)
// value: Int64 value to bind
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindLongLongAtPosition:(int)position value:(long long)value;
// Bind an NSNumber as a 64-bit integer value at the given position.
//
// Args:
// position: Parameter position (1-based index)
// number: NSNumber to bind
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindNumberAsLongLongAtPosition:(int)position number:(NSNumber *)number;
// Bind a string at the given position.
//
// Args:
// position: Parameter position (1-based index)
// string: String to bind (string will be converted to UTF8 and copied).
// NOTE: For bindings it is not necessary for you to SQL escape
// your strings.
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)bindStringAtPosition:(int)position string:(NSString *)string;
#pragma mark Results
// Get the number of result columns per row this statement will generate.
//
// Returns:
// Column count, 0 if no columns will be returned ("UPDATE.." etc.),
// -1 on error.
//
- (int)resultColumnCount;
// Get the name of result colument at a given index.
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Autoreleased NSString column name or nil if no column exists at that
// position or error.
//
- (nullable NSString *)resultColumnNameAtPosition:(int)position;
// Get the number of data values in the current row of this statement.
// Generally this will be the same as resultColumnCount:, except when row
// iteration is done (see SQLite docs for sqlite3_data_count()).
//
// Returns:
// Data count or 0 if no data will be returned, -1 on error.
//
- (int)rowDataCount;
// Get the SQLite type constant for a column in a row. Note that because
// SQLite does not enforce column type restrictions the type of a particular
// column in a row may not match the declared type of the column.
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// SQLite data type constant (i.e. SQLITE_INTEGER, SQLITE_FLOAT, etc.) or
// -1 on error.
//
- (int)resultColumnTypeAtPosition:(int)position;
// Get the data for a result row blob column as an NSData
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Autoreleased NSData, nil on error
//
- (nullable NSData *)resultBlobDataAtPosition:(int)position;
// Get the data for a result row blob column as a double
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Double value
//
- (double)resultDoubleAtPosition:(int)position;
// Get the data for a result row blob column as an integer
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Integer value
//
- (int)resultInt32AtPosition:(int)position;
// Get the data for a result row blob column as a long long
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Long long value
//
- (long long)resultLongLongAtPosition:(int)position;
// Get the data for a result row blob column as an NSNumber
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Autoreleased NSNumber value or nil on error
//
- (nullable NSNumber *)resultNumberAtPosition:(int)position;
// Get the data for a result row blob column as an NSString
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Autoreleased NSString value or nil on error
//
- (nullable NSString *)resultStringAtPosition:(int)position;
// Get a Foundation object (NSData, NSNumber, NSString, NSNull) for the column,
// autodetecting the most appropriate representation.
//
// Args:
// position: Column position (0-based index)
//
// Returns:
// Autoreleased Foundation type, nil on error
//
- (nullable id)resultFoundationObjectAtPosition:(int)position;
// Get an array of Foundation objects for the row in query column order.
//
// Returns:
// Autoreleased array of Foundation types or nil if there is no
// data in the row or error
//
- (nullable NSArray *)resultRowArray;
// Get a dictionary of Foundation objects for the row keyed by column name.
//
// Returns:
// Autoreleased dictionary of Foundation types or nil if there is no
// data in the row or error.
//
- (nullable NSDictionary *)resultRowDictionary;
#pragma mark Rows
// Step the statement forward one row, potentially spinning forever till
// the row can be located (if database is SQLITE_BUSY).
//
// Returns:
// SQLite result code, SQLITE_ROW if a row was found or SQLITE_DONE if
// no further rows match the statement.
//
- (int)stepRow;
// Step the statement forward one row, waiting at most the currrent database
// busy timeout (see [GTMSQLiteDatabase setBusyTimeoutMS]).
//
// Returns:
// SQLite result code, SQLITE_ROW if a row was found or SQLITE_DONE if
// no further rows match the statement. If SQLITE_BUSY is returned the
// database did not unlock during the timeout.
//
- (int)stepRowWithTimeout;
// Reset the statement starting again at the first row
//
// Returns:
// SQLite result code, SQLITE_OK on no error
//
- (int)reset;
// Check if the SQLite parser recognizes the receiver as one or more valid
// SQLite statements.
//
// Returns:
// YES if the string is a complete and valid SQLite statement
//
+ (BOOL)isCompleteStatement:(NSString *)string;
// Quote and escape the receiver for SQL.
// Example: "This is wild! It's fun!"
// Becomes: "'This is wild! It''s fun!'"
//
// Returns:
// Autoreleased NSString
+ (NSString *)quoteAndEscapeString:(NSString *)string;
@end
NS_ASSUME_NONNULL_END