mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
218 lines
7.9 KiB
Objective-C
218 lines
7.9 KiB
Objective-C
//
|
|
// SQLite.swift
|
|
// https://github.com/stephencelis/SQLite.swift
|
|
// Copyright (c) 2014-2015 Stephen Celis.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
//
|
|
|
|
#import "SQLite-Bridging.h"
|
|
|
|
#import "fts3_tokenizer.h"
|
|
|
|
static int __SQLiteBusyHandler(void * context, int tries) {
|
|
return ((__bridge _SQLiteBusyHandlerCallback)context)(tries);
|
|
}
|
|
|
|
int _SQLiteBusyHandler(SQLiteHandle * handle, _SQLiteBusyHandlerCallback callback) {
|
|
if (callback) {
|
|
return sqlite3_busy_handler((sqlite3 *)handle, __SQLiteBusyHandler, (__bridge void *)callback);
|
|
} else {
|
|
return sqlite3_busy_handler((sqlite3 *)handle, 0, 0);
|
|
}
|
|
}
|
|
|
|
static void __SQLiteTrace(void * context, const char * SQL) {
|
|
((__bridge _SQLiteTraceCallback)context)(SQL);
|
|
}
|
|
|
|
void _SQLiteTrace(SQLiteHandle * handle, _SQLiteTraceCallback callback) {
|
|
if (callback) {
|
|
sqlite3_trace((sqlite3 *)handle, __SQLiteTrace, (__bridge void *)callback);
|
|
} else {
|
|
sqlite3_trace((sqlite3 *)handle, 0, 0);
|
|
}
|
|
}
|
|
|
|
static void __SQLiteUpdateHook(void * context, int operation, const char * db, const char * table, long long rowid) {
|
|
((__bridge _SQLiteUpdateHookCallback)context)(operation, db, table, rowid);
|
|
}
|
|
|
|
void _SQLiteUpdateHook(SQLiteHandle * handle, _SQLiteUpdateHookCallback callback) {
|
|
sqlite3_update_hook((sqlite3 *)handle, __SQLiteUpdateHook, (__bridge void *)callback);
|
|
}
|
|
|
|
static int __SQLiteCommitHook(void * context) {
|
|
return ((__bridge _SQLiteCommitHookCallback)context)();
|
|
}
|
|
|
|
void _SQLiteCommitHook(SQLiteHandle * handle, _SQLiteCommitHookCallback callback) {
|
|
sqlite3_commit_hook((sqlite3 *)handle, __SQLiteCommitHook, (__bridge void *)callback);
|
|
}
|
|
|
|
static void __SQLiteRollbackHook(void * context) {
|
|
((__bridge _SQLiteRollbackHookCallback)context)();
|
|
}
|
|
|
|
void _SQLiteRollbackHook(SQLiteHandle * handle, _SQLiteRollbackHookCallback callback) {
|
|
sqlite3_rollback_hook((sqlite3 *)handle, __SQLiteRollbackHook, (__bridge void *)callback);
|
|
}
|
|
|
|
static void __SQLiteCreateFunction(sqlite3_context * context, int argc, sqlite3_value ** argv) {
|
|
((__bridge _SQLiteCreateFunctionCallback)sqlite3_user_data(context))((SQLiteContext *)context, argc, (SQLiteValue **)argv);
|
|
}
|
|
|
|
int _SQLiteCreateFunction(SQLiteHandle * handle, const char * name, int argc, int deterministic, _SQLiteCreateFunctionCallback callback) {
|
|
if (callback) {
|
|
int flags = SQLITE_UTF8;
|
|
if (deterministic) {
|
|
#ifdef SQLITE_DETERMINISTIC
|
|
flags |= SQLITE_DETERMINISTIC;
|
|
#endif
|
|
}
|
|
return sqlite3_create_function_v2((sqlite3 *)handle, name, -1, flags, (__bridge void *)callback, &__SQLiteCreateFunction, 0, 0, 0);
|
|
} else {
|
|
return sqlite3_create_function_v2((sqlite3 *)handle, name, 0, 0, 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
static int __SQLiteCreateCollation(void * context, int len_lhs, const void * lhs, int len_rhs, const void * rhs) {
|
|
return ((__bridge _SQLiteCreateCollationCallback)context)(lhs, rhs);
|
|
}
|
|
|
|
int _SQLiteCreateCollation(SQLiteHandle * handle, const char * name, _SQLiteCreateCollationCallback callback) {
|
|
if (callback) {
|
|
return sqlite3_create_collation_v2((sqlite3 *)handle, name, SQLITE_UTF8, (__bridge void *)callback, &__SQLiteCreateCollation, 0);
|
|
} else {
|
|
return sqlite3_create_collation_v2((sqlite3 *)handle, name, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
#pragma mark - FTS
|
|
|
|
typedef struct __SQLiteTokenizer {
|
|
sqlite3_tokenizer base;
|
|
__unsafe_unretained _SQLiteTokenizerNextCallback callback;
|
|
} __SQLiteTokenizer;
|
|
|
|
typedef struct __SQLiteTokenizerCursor {
|
|
void * base;
|
|
const char * input;
|
|
int inputOffset;
|
|
int inputLength;
|
|
int idx;
|
|
} __SQLiteTokenizerCursor;
|
|
|
|
static NSMutableDictionary * __SQLiteTokenizerMap;
|
|
|
|
static int __SQLiteTokenizerCreate(int argc, const char * const * argv, sqlite3_tokenizer ** ppTokenizer) {
|
|
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)sqlite3_malloc(sizeof(__SQLiteTokenizer));
|
|
if (!tokenizer) {
|
|
return SQLITE_NOMEM;
|
|
}
|
|
memset(tokenizer, 0, sizeof(* tokenizer)); // FIXME: needed?
|
|
|
|
NSString * key = [NSString stringWithUTF8String:argv[0]];
|
|
tokenizer->callback = [__SQLiteTokenizerMap objectForKey:key];
|
|
if (!tokenizer->callback) {
|
|
return SQLITE_ERROR;
|
|
}
|
|
|
|
*ppTokenizer = &tokenizer->base;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int __SQLiteTokenizerDestroy(sqlite3_tokenizer * pTokenizer) {
|
|
sqlite3_free(pTokenizer);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int __SQLiteTokenizerOpen(sqlite3_tokenizer * pTokenizer, const char * pInput, int nBytes, sqlite3_tokenizer_cursor ** ppCursor) {
|
|
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)sqlite3_malloc(sizeof(__SQLiteTokenizerCursor));
|
|
if (!cursor) {
|
|
return SQLITE_NOMEM;
|
|
}
|
|
|
|
cursor->input = pInput;
|
|
cursor->inputOffset = 0;
|
|
cursor->inputLength = 0;
|
|
cursor->idx = 0;
|
|
|
|
*ppCursor = (sqlite3_tokenizer_cursor *)cursor;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int __SQLiteTokenizerClose(sqlite3_tokenizer_cursor * pCursor) {
|
|
sqlite3_free(pCursor);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static int __SQLiteTokenizerNext(sqlite3_tokenizer_cursor * pCursor, const char ** ppToken, int * pnBytes, int * piStartOffset, int * piEndOffset, int * piPosition) {
|
|
__SQLiteTokenizerCursor * cursor = (__SQLiteTokenizerCursor *)pCursor;
|
|
__SQLiteTokenizer * tokenizer = (__SQLiteTokenizer *)cursor->base;
|
|
|
|
cursor->inputOffset += cursor->inputLength;
|
|
const char * input = cursor->input + cursor->inputOffset;
|
|
const char * token = [tokenizer->callback(input, &cursor->inputOffset, &cursor->inputLength) cStringUsingEncoding:NSUTF8StringEncoding];
|
|
if (!token) {
|
|
return SQLITE_DONE;
|
|
}
|
|
|
|
*ppToken = token;
|
|
*pnBytes = (int)strlen(token);
|
|
*piStartOffset = cursor->inputOffset;
|
|
*piEndOffset = cursor->inputOffset + cursor->inputLength;
|
|
*piPosition = cursor->idx++;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
static const sqlite3_tokenizer_module __SQLiteTokenizerModule = {
|
|
0,
|
|
__SQLiteTokenizerCreate,
|
|
__SQLiteTokenizerDestroy,
|
|
__SQLiteTokenizerOpen,
|
|
__SQLiteTokenizerClose,
|
|
__SQLiteTokenizerNext
|
|
};
|
|
|
|
int _SQLiteRegisterTokenizer(SQLiteHandle * db, const char * moduleName, const char * submoduleName, _SQLiteTokenizerNextCallback callback) {
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
__SQLiteTokenizerMap = [NSMutableDictionary new];
|
|
});
|
|
|
|
sqlite3_stmt * stmt;
|
|
int status = sqlite3_prepare_v2((sqlite3 *)db, "SELECT fts3_tokenizer(?, ?)", -1, &stmt, 0);
|
|
if (status != SQLITE_OK ){
|
|
return status;
|
|
}
|
|
const sqlite3_tokenizer_module * pModule = &__SQLiteTokenizerModule;
|
|
sqlite3_bind_text(stmt, 1, moduleName, -1, SQLITE_STATIC);
|
|
sqlite3_bind_blob(stmt, 2, &pModule, sizeof(pModule), SQLITE_STATIC);
|
|
sqlite3_step(stmt);
|
|
status = sqlite3_finalize(stmt);
|
|
if (status != SQLITE_OK ){
|
|
return status;
|
|
}
|
|
|
|
[__SQLiteTokenizerMap setObject:[callback copy] forKey:[NSString stringWithUTF8String:submoduleName]];
|
|
|
|
return SQLITE_OK;
|
|
}
|