Error with Firebase/Messaging in iOS when create table - xcode
I have a error in iOS with xcode 12.5.1.
When I open the app it crashed.
This happens when execute line FirebaseApp.configure() in AppDelegate.swift class
pod 'Firebase/Messaging' - FirebaseMessaging (7.11.0)
Error: 2021-08-16 01:13:02.476120-0500 bm[7585:1201692] [logging] file
is not a database in "create TABLE IF NOT EXISTS incomingSyncMessages
(_id INTEGER PRIMARY KEY, rmq_id TEXT, expiration_ts INTEGER,
apns_recv INTEGER, mcs_recv INTEGER)"
2021-08-16 01:13:11.138855-0500 bm[7585:1201692] *** Assertion failure
in -[FIRMessagingRmqManager createTableWithName:command:],
FIRMessagingRmqManager.m:456
2021-08-16 01:13:11.140170-0500 bm[7585:1201692] *** Terminating app
due to uncaught exception 'NSInternalInconsistencyException', reason:
'Couldn't create table: create TABLE IF NOT EXISTS Couldn't create
table: create TABLE IF NOT EXISTS %#%# (_id INTEGER PRIMARY KEY,
rmq_id INTEGER, type INTEGER, ts INTEGER, data BLOB) file is not a
database34-62-25736 (_id INTEGER PRIMARY KEY, rmq_id INTEGER, type
INTEGER, ts INTEGER, data BLOB) file is not a database'
*** First throw call stack: (0x1a82b725c 0x1bc04c480 0x1a81c4c98 0x1a94fcef8 0x10510283c 0x1051030b0 0x108063ae8 0x10806532c
0x10806c38c 0x10806d010 0x108078820 0x1f07e95bc 0x1f07ec86c)
libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Couldn't create table:
create TABLE IF NOT EXISTS Couldn't create table: create TABLE IF NOT
EXISTS %#%# (_id INTEGER PRIMARY KEY, rmq_id INTEGER, type INTEGER, ts
INTEGER, data BLOB) file is not a database34-62-25736 (_id INTEGER
PRIMARY KEY, rmq_id INTEGER, type INTEGER, ts INTEGER, data BLOB) file
is not a database' terminating with uncaught exception of type
NSException
FIRMessagingRmqManager.m:
/*
* Copyright 2017 Google
*
* 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.
*/
#import "FirebaseMessaging/Sources/FIRMessagingRmqManager.h"
#import <sqlite3.h>
#import "FirebaseMessaging/Sources/FIRMessagingConstants.h"
#import "FirebaseMessaging/Sources/FIRMessagingDefines.h"
#import "FirebaseMessaging/Sources/FIRMessagingLogger.h"
#import "FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h"
#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h"
#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h"
#ifndef _FIRMessagingRmqLogAndExit
#define _FIRMessagingRmqLogAndExit(stmt, return_value) \
do { \
[self logErrorAndFinalizeStatement:stmt]; \
return return_value; \
} while (0)
#endif
#ifndef FIRMessagingRmqLogAndReturn
#define FIRMessagingRmqLogAndReturn(stmt) \
do { \
[self logErrorAndFinalizeStatement:stmt]; \
return; \
} while (0)
#endif
#ifndef FIRMessaging_MUST_NOT_BE_MAIN_THREAD
#define FIRMessaging_MUST_NOT_BE_MAIN_THREAD() \
do { \
NSAssert(![NSThread isMainThread], #"Must not be executing on the main thread."); \
} while (0);
#endif
// table names
NSString *const kTableOutgoingRmqMessages = #"outgoingRmqMessages";
NSString *const kTableLastRmqId = #"lastrmqid";
NSString *const kOldTableS2DRmqIds = #"s2dRmqIds";
NSString *const kTableS2DRmqIds = #"s2dRmqIds_1";
// Used to prevent de-duping of sync messages received both via APNS and MCS.
NSString *const kTableSyncMessages = #"incomingSyncMessages";
static NSString *const kTablePrefix = #"";
// create tables
static NSString *const kCreateTableOutgoingRmqMessages = #"create TABLE IF NOT EXISTS %#%# "
#"(_id INTEGER PRIMARY KEY, "
#"rmq_id INTEGER, "
#"type INTEGER, "
#"ts INTEGER, "
#"data BLOB)";
static NSString *const kCreateTableLastRmqId = #"create TABLE IF NOT EXISTS %#%# "
#"(_id INTEGER PRIMARY KEY, "
#"rmq_id INTEGER)";
static NSString *const kCreateTableS2DRmqIds = #"create TABLE IF NOT EXISTS %#%# "
#"(_id INTEGER PRIMARY KEY, "
#"rmq_id TEXT)";
static NSString *const kCreateTableSyncMessages = #"create TABLE IF NOT EXISTS %#%# "
#"(_id INTEGER PRIMARY KEY, "
#"rmq_id TEXT, "
#"expiration_ts INTEGER, "
#"apns_recv INTEGER, "
#"mcs_recv INTEGER)";
static NSString *const kDropTableCommand = #"drop TABLE if exists %#%#";
// table infos
static NSString *const kRmqIdColumn = #"rmq_id";
static NSString *const kDataColumn = #"data";
static NSString *const kProtobufTagColumn = #"type";
static NSString *const kIdColumn = #"_id";
static NSString *const kOutgoingRmqMessagesColumns = #"rmq_id, type, data";
// Sync message columns
static NSString *const kSyncMessagesColumns = #"rmq_id, expiration_ts, apns_recv, mcs_recv";
// Message time expiration in seconds since 1970
static NSString *const kSyncMessageExpirationTimestampColumn = #"expiration_ts";
static NSString *const kSyncMessageAPNSReceivedColumn = #"apns_recv";
static NSString *const kSyncMessageMCSReceivedColumn = #"mcs_recv";
// Utility to create an NSString from a sqlite3 result code
NSString *_Nonnull FIRMessagingStringFromSQLiteResult(int result) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
const char *errorStr = sqlite3_errstr(result);
#pragma clang diagnostic pop
NSString *errorString = [NSString stringWithFormat:#"%d - %s", result, errorStr];
return errorString;
}
#interface FIRMessagingRmqManager () {
sqlite3 *_database;
/// Serial queue for database read/write operations.
dispatch_queue_t _databaseOperationQueue;
}
#property(nonatomic, readwrite, strong) NSString *databaseName;
// map the category of an outgoing message with the number of messages for that category
// should always have two keys -- the app, gcm
#property(nonatomic, readwrite, strong) NSMutableDictionary *outstandingMessages;
// Outgoing RMQ persistent id
#property(nonatomic, readwrite, assign) int64_t rmqId;
#end
#implementation FIRMessagingRmqManager
- (instancetype)initWithDatabaseName:(NSString *)databaseName {
self = [super init];
if (self) {
_databaseOperationQueue =
dispatch_queue_create("com.google.firebase.messaging.database.rmq", DISPATCH_QUEUE_SERIAL);
_databaseName = [databaseName copy];
[self openDatabase];
_outstandingMessages = [NSMutableDictionary dictionaryWithCapacity:2];
_rmqId = -1;
}
return self;
}
- (void)dealloc {
sqlite3_close(_database);
}
#pragma mark - RMQ ID
- (void)loadRmqId {
if (self.rmqId >= 0) {
return; // already done
}
[self loadInitialOutgoingPersistentId];
if (self.outstandingMessages.count) {
FIRMessagingLoggerDebug(kFIRMessagingMessageCodeRmqManager000, #"Outstanding categories %ld",
_FIRMessaging_UL(self.outstandingMessages.count));
}
}
/**
* Initialize the 'initial RMQ':
* - max ID of any message in the queue
* - if the queue is empty, stored value in separate DB.
*
* Stream acks will remove from RMQ, when we remove the highest message we keep track
* of its ID.
*/
- (void)loadInitialOutgoingPersistentId {
// we shouldn't always trust the lastRmqId stored in the LastRmqId table, because
// we only save to the LastRmqId table once in a while (after getting the lastRmqId sent
// by the server after reconnect, and after getting a rmq ack from the server). The
// rmq message with the highest rmq id tells the real story, so check against that first.
__block int64_t rmqId;
dispatch_sync(_databaseOperationQueue, ^{
rmqId = [self queryHighestRmqId];
});
if (rmqId == 0) {
dispatch_sync(_databaseOperationQueue, ^{
rmqId = [self queryLastRmqId];
});
}
self.rmqId = rmqId + 1;
}
/**
* This is called when we delete the largest outgoing message from queue.
*/
- (void)saveLastOutgoingRmqId:(int64_t)rmqID {
dispatch_async(_databaseOperationQueue, ^{
NSString *queryFormat = #"INSERT OR REPLACE INTO %# (%#, %#) VALUES (?, ?)";
NSString *query = [NSString stringWithFormat:queryFormat,
kTableLastRmqId, // table
kIdColumn, kRmqIdColumn]; // columns
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(self->_database, [query UTF8String], -1, &statement, NULL) !=
SQLITE_OK) {
FIRMessagingRmqLogAndReturn(statement);
}
if (sqlite3_bind_int(statement, 1, 1) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(statement);
}
if (sqlite3_bind_int64(statement, 2, rmqID) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(statement);
}
if (sqlite3_step(statement) != SQLITE_DONE) {
FIRMessagingRmqLogAndReturn(statement);
}
sqlite3_finalize(statement);
});
}
- (void)saveS2dMessageWithRmqId:(NSString *)rmqId {
dispatch_async(_databaseOperationQueue, ^{
NSString *insertFormat = #"INSERT INTO %# (%#) VALUES (?)";
NSString *insertSQL = [NSString stringWithFormat:insertFormat, kTableS2DRmqIds, kRmqIdColumn];
sqlite3_stmt *insert_statement;
if (sqlite3_prepare_v2(self->_database, [insertSQL UTF8String], -1, &insert_statement, NULL) !=
SQLITE_OK) {
FIRMessagingRmqLogAndReturn(insert_statement);
}
if (sqlite3_bind_text(insert_statement, 1, [rmqId UTF8String], (int)[rmqId length],
SQLITE_STATIC) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(insert_statement);
}
if (sqlite3_step(insert_statement) != SQLITE_DONE) {
FIRMessagingRmqLogAndReturn(insert_statement);
}
sqlite3_finalize(insert_statement);
});
}
#pragma mark - Query
- (int64_t)queryHighestRmqId {
NSString *queryFormat = #"SELECT %# FROM %# ORDER BY %# DESC LIMIT %d";
NSString *query = [NSString stringWithFormat:queryFormat,
kRmqIdColumn, // column
kTableOutgoingRmqMessages, // table
kRmqIdColumn, // order by column
1]; // limit
sqlite3_stmt *statement;
int64_t highestRmqId = 0;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, NULL) != SQLITE_OK) {
_FIRMessagingRmqLogAndExit(statement, highestRmqId);
}
if (sqlite3_step(statement) == SQLITE_ROW) {
highestRmqId = sqlite3_column_int64(statement, 0);
}
sqlite3_finalize(statement);
return highestRmqId;
}
- (int64_t)queryLastRmqId {
NSString *queryFormat = #"SELECT %# FROM %# ORDER BY %# DESC LIMIT %d";
NSString *query = [NSString stringWithFormat:queryFormat,
kRmqIdColumn, // column
kTableLastRmqId, // table
kRmqIdColumn, // order by column
1]; // limit
sqlite3_stmt *statement;
int64_t lastRmqId = 0;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, NULL) != SQLITE_OK) {
_FIRMessagingRmqLogAndExit(statement, lastRmqId);
}
if (sqlite3_step(statement) == SQLITE_ROW) {
lastRmqId = sqlite3_column_int64(statement, 0);
}
sqlite3_finalize(statement);
return lastRmqId;
}
#pragma mark - Sync Messages
- (FIRMessagingPersistentSyncMessage *)querySyncMessageWithRmqID:(NSString *)rmqID {
__block FIRMessagingPersistentSyncMessage *persistentMessage;
dispatch_sync(_databaseOperationQueue, ^{
NSString *queryFormat = #"SELECT %# FROM %# WHERE %# = '%#'";
NSString *query =
[NSString stringWithFormat:queryFormat,
kSyncMessagesColumns, // SELECT (rmq_id, expiration_ts,
// apns_recv, mcs_recv)
kTableSyncMessages, // FROM sync_rmq
kRmqIdColumn, // WHERE rmq_id
rmqID];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(self->_database, [query UTF8String], -1, &stmt, NULL) != SQLITE_OK) {
[self logError];
sqlite3_finalize(stmt);
return;
}
const int rmqIDColumn = 0;
const int expirationTimestampColumn = 1;
const int apnsReceivedColumn = 2;
const int mcsReceivedColumn = 3;
int count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
NSString *rmqID =
[NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt, rmqIDColumn)];
int64_t expirationTimestamp = sqlite3_column_int64(stmt, expirationTimestampColumn);
BOOL apnsReceived = sqlite3_column_int(stmt, apnsReceivedColumn);
BOOL mcsReceived = sqlite3_column_int(stmt, mcsReceivedColumn);
// create a new persistent message
persistentMessage =
[[FIRMessagingPersistentSyncMessage alloc] initWithRMQID:rmqID
expirationTime:expirationTimestamp];
persistentMessage.apnsReceived = apnsReceived;
persistentMessage.mcsReceived = mcsReceived;
count++;
}
sqlite3_finalize(stmt);
});
return persistentMessage;
}
- (void)deleteExpiredOrFinishedSyncMessages {
dispatch_async(_databaseOperationQueue, ^{
int64_t now = FIRMessagingCurrentTimestampInSeconds();
NSString *deleteSQL = #"DELETE FROM %# "
#"WHERE %# < %lld OR " // expirationTime < now
#"(%# = 1 AND %# = 1)"; // apns_received = 1 AND mcs_received = 1
NSString *query = [NSString
stringWithFormat:deleteSQL, kTableSyncMessages, kSyncMessageExpirationTimestampColumn, now,
kSyncMessageAPNSReceivedColumn, kSyncMessageMCSReceivedColumn];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(self->_database, [query UTF8String], -1, &stmt, NULL) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(stmt);
}
if (sqlite3_step(stmt) != SQLITE_DONE) {
FIRMessagingRmqLogAndReturn(stmt);
}
sqlite3_finalize(stmt);
int deleteCount = sqlite3_changes(self->_database);
if (deleteCount > 0) {
FIRMessagingLoggerDebug(kFIRMessagingMessageCodeSyncMessageManager001,
#"Successfully deleted %d sync messages from store", deleteCount);
}
});
}
- (void)saveSyncMessageWithRmqID:(NSString *)rmqID expirationTime:(int64_t)expirationTime {
BOOL apnsReceived = YES;
BOOL mcsReceived = NO;
dispatch_async(_databaseOperationQueue, ^{
NSString *insertFormat = #"INSERT INTO %# (%#, %#, %#, %#) VALUES (?, ?, ?, ?)";
NSString *insertSQL =
[NSString stringWithFormat:insertFormat,
kTableSyncMessages, // Table name
kRmqIdColumn, // rmq_id
kSyncMessageExpirationTimestampColumn, // expiration_ts
kSyncMessageAPNSReceivedColumn, // apns_recv
kSyncMessageMCSReceivedColumn /* mcs_recv */];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(self->_database, [insertSQL UTF8String], -1, &stmt, NULL) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(stmt);
}
if (sqlite3_bind_text(stmt, 1, [rmqID UTF8String], (int)[rmqID length], NULL) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(stmt);
}
if (sqlite3_bind_int64(stmt, 2, expirationTime) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(stmt);
}
if (sqlite3_bind_int(stmt, 3, apnsReceived ? 1 : 0) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(stmt);
}
if (sqlite3_bind_int(stmt, 4, mcsReceived ? 1 : 0) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(stmt);
}
if (sqlite3_step(stmt) != SQLITE_DONE) {
FIRMessagingRmqLogAndReturn(stmt);
}
sqlite3_finalize(stmt);
FIRMessagingLoggerInfo(kFIRMessagingMessageCodeSyncMessageManager004,
#"Added sync message to cache: %#", rmqID);
});
}
- (void)updateSyncMessageViaAPNSWithRmqID:(NSString *)rmqID {
dispatch_async(_databaseOperationQueue, ^{
if (![self updateSyncMessageWithRmqID:rmqID column:kSyncMessageAPNSReceivedColumn value:YES]) {
FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager005,
#"Failed to update APNS state for sync message %#", rmqID);
}
});
}
- (BOOL)updateSyncMessageWithRmqID:(NSString *)rmqID column:(NSString *)column value:(BOOL)value {
FIRMessaging_MUST_NOT_BE_MAIN_THREAD();
NSString *queryFormat = #"UPDATE %# " // Table name
#"SET %# = %d " // column=value
#"WHERE %# = ?"; // condition
NSString *query = [NSString
stringWithFormat:queryFormat, kTableSyncMessages, column, value ? 1 : 0, kRmqIdColumn];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &stmt, NULL) != SQLITE_OK) {
_FIRMessagingRmqLogAndExit(stmt, NO);
}
if (sqlite3_bind_text(stmt, 1, [rmqID UTF8String], (int)[rmqID length], NULL) != SQLITE_OK) {
_FIRMessagingRmqLogAndExit(stmt, NO);
}
if (sqlite3_step(stmt) != SQLITE_DONE) {
_FIRMessagingRmqLogAndExit(stmt, NO);
}
sqlite3_finalize(stmt);
return YES;
}
#pragma mark - Database
- (NSString *)pathForDatabase {
return [[self class] pathForDatabaseWithName:_databaseName];
}
+ (NSString *)pathForDatabaseWithName:(NSString *)databaseName {
NSString *dbNameWithExtension = [NSString stringWithFormat:#"%#.sqlite", databaseName];
NSArray *paths =
NSSearchPathForDirectoriesInDomains(FIRMessagingSupportedDirectory(), NSUserDomainMask, YES);
NSArray *components = #[ paths.lastObject, kFIRMessagingSubDirectoryName, dbNameWithExtension ];
return [NSString pathWithComponents:components];
}
- (void)createTableWithName:(NSString *)tableName command:(NSString *)command {
FIRMessaging_MUST_NOT_BE_MAIN_THREAD();
char *error;
NSString *createDatabase = [NSString stringWithFormat:command, kTablePrefix, tableName];
if (sqlite3_exec(self->_database, [createDatabase UTF8String], NULL, NULL, &error) != SQLITE_OK) {
// remove db before failing
[self removeDatabase];
NSString *errorMessage = [NSString
stringWithFormat:#"Couldn't create table: %# %#", kCreateTableOutgoingRmqMessages,
[NSString stringWithCString:error encoding:NSUTF8StringEncoding]];
FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStoreErrorCreatingTable, #"%#",
errorMessage);
NSAssert(NO, errorMessage);
}
}
- (void)dropTableWithName:(NSString *)tableName {
FIRMessaging_MUST_NOT_BE_MAIN_THREAD();
char *error;
NSString *dropTableSQL = [NSString stringWithFormat:kDropTableCommand, kTablePrefix, tableName];
if (sqlite3_exec(self->_database, [dropTableSQL UTF8String], NULL, NULL, &error) != SQLITE_OK) {
FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStore002,
#"Failed to remove table %#", tableName);
}
}
- (void)removeDatabase {
// Ensure database is removed in a sync queue as this sometimes makes test have race conditions.
dispatch_async(_databaseOperationQueue, ^{
NSString *path = [self pathForDatabase];
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
});
}
- (void)openDatabase {
dispatch_async(_databaseOperationQueue, ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *path = [self pathForDatabase];
BOOL didOpenDatabase = YES;
if (![fileManager fileExistsAtPath:path]) {
// We've to separate between different versions here because of backwards compatbility issues.
int result = sqlite3_open_v2(
[path UTF8String], &self -> _database,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FILEPROTECTION_NONE, NULL);
if (result != SQLITE_OK) {
NSString *errorString = FIRMessagingStringFromSQLiteResult(result);
NSString *errorMessage = [NSString
stringWithFormat:#"Could not open existing RMQ database at path %#, error: %#", path,
errorString];
FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStoreErrorOpeningDatabase,
#"%#", errorMessage);
NSAssert(NO, errorMessage);
return;
}
[self createTableWithName:kTableOutgoingRmqMessages command:kCreateTableOutgoingRmqMessages];
[self createTableWithName:kTableLastRmqId command:kCreateTableLastRmqId];
[self createTableWithName:kTableS2DRmqIds command:kCreateTableS2DRmqIds];
} else {
// Calling sqlite3_open should create the database, since the file doesn't exist.
int result = sqlite3_open_v2(
[path UTF8String], &self -> _database,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FILEPROTECTION_NONE, NULL);
if (result != SQLITE_OK) {
NSString *errorString = FIRMessagingStringFromSQLiteResult(result);
NSString *errorMessage =
[NSString stringWithFormat:#"Could not create RMQ database at path %#, error: %#", path,
errorString];
FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStoreErrorCreatingDatabase,
#"%#", errorMessage);
NSAssert(NO, errorMessage);
didOpenDatabase = NO;
} else {
[self updateDBWithStringRmqID];
}
}
if (didOpenDatabase) {
[self createTableWithName:kTableSyncMessages command:kCreateTableSyncMessages];
}
});
}
- (void)updateDBWithStringRmqID {
dispatch_async(_databaseOperationQueue, ^{
[self createTableWithName:kTableS2DRmqIds command:kCreateTableS2DRmqIds];
[self dropTableWithName:kOldTableS2DRmqIds];
});
}
#pragma mark - Private
- (BOOL)saveMessageWithRmqId:(int64_t)rmqId tag:(int8_t)tag data:(NSData *)data {
FIRMessaging_MUST_NOT_BE_MAIN_THREAD();
NSString *insertFormat = #"INSERT INTO %# (%#, %#, %#) VALUES (?, ?, ?)";
NSString *insertSQL =
[NSString stringWithFormat:insertFormat,
kTableOutgoingRmqMessages, // table
kRmqIdColumn, kProtobufTagColumn, kDataColumn /* columns */];
sqlite3_stmt *insert_statement;
if (sqlite3_prepare_v2(self->_database, [insertSQL UTF8String], -1, &insert_statement, NULL) !=
SQLITE_OK) {
_FIRMessagingRmqLogAndExit(insert_statement, NO);
}
if (sqlite3_bind_int64(insert_statement, 1, rmqId) != SQLITE_OK) {
_FIRMessagingRmqLogAndExit(insert_statement, NO);
}
if (sqlite3_bind_int(insert_statement, 2, tag) != SQLITE_OK) {
_FIRMessagingRmqLogAndExit(insert_statement, NO);
}
if (sqlite3_bind_blob(insert_statement, 3, [data bytes], (int)[data length], NULL) != SQLITE_OK) {
_FIRMessagingRmqLogAndExit(insert_statement, NO);
}
if (sqlite3_step(insert_statement) != SQLITE_DONE) {
_FIRMessagingRmqLogAndExit(insert_statement, NO);
}
sqlite3_finalize(insert_statement);
return YES;
}
- (void)deleteMessagesFromTable:(NSString *)tableName withRmqIds:(NSArray *)rmqIds {
dispatch_async(_databaseOperationQueue, ^{
BOOL isRmqIDString = NO;
// RmqID is a string only for outgoing messages
if ([tableName isEqualToString:kTableS2DRmqIds] ||
[tableName isEqualToString:kTableSyncMessages]) {
isRmqIDString = YES;
}
NSMutableString *delete =
[NSMutableString stringWithFormat:#"DELETE FROM %# WHERE ", tableName];
NSString *toDeleteArgument = [NSString stringWithFormat:#"%# = ? OR ", kRmqIdColumn];
int toDelete = (int)[rmqIds count];
if (toDelete == 0) {
return;
}
int maxBatchSize = 100;
int start = 0;
int deleteCount = 0;
while (start < toDelete) {
// construct the WHERE argument
int end = MIN(start + maxBatchSize, toDelete);
NSMutableString *whereArgument = [NSMutableString string];
for (int i = start; i < end; i++) {
[whereArgument appendString:toDeleteArgument];
}
// remove the last * OR * from argument
NSRange range = NSMakeRange([whereArgument length] - 4, 4);
[whereArgument deleteCharactersInRange:range];
NSString *deleteQuery = [NSString stringWithFormat:#"%# %#", delete, whereArgument];
// sqlite update
sqlite3_stmt *delete_statement;
if (sqlite3_prepare_v2(self->_database, [deleteQuery UTF8String], -1, &delete_statement,
NULL) != SQLITE_OK) {
FIRMessagingRmqLogAndReturn(delete_statement);
}
// bind values
int rmqIndex = 0;
int placeholderIndex = 1; // placeholders in sqlite3 start with 1
for (NSString *rmqId in rmqIds) { // objectAtIndex: is O(n) -- would make it slow
if (rmqIndex < start) {
rmqIndex++;
continue;
} else if (rmqIndex >= end) {
break;
} else {
if (isRmqIDString) {
if (sqlite3_bind_text(delete_statement, placeholderIndex, [rmqId UTF8String],
(int)[rmqId length], SQLITE_STATIC) != SQLITE_OK) {
FIRMessagingLoggerDebug(kFIRMessagingMessageCodeRmq2PersistentStore003,
#"Failed to bind rmqID %#", rmqId);
FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager007,
#"Failed to delete sync message %#", rmqId);
continue;
}
} else {
int64_t rmqIdValue = [rmqId longLongValue];
sqlite3_bind_int64(delete_statement, placeholderIndex, rmqIdValue);
}
placeholderIndex++;
}
rmqIndex++;
FIRMessagingLoggerInfo(kFIRMessagingMessageCodeSyncMessageManager008,
#"Successfully deleted sync message from cache %#", rmqId);
}
if (sqlite3_step(delete_statement) != SQLITE_DONE) {
FIRMessagingRmqLogAndReturn(delete_statement);
}
sqlite3_finalize(delete_statement);
deleteCount += sqlite3_changes(self->_database);
start = end;
}
// if we are here all of our sqlite queries should have succeeded
FIRMessagingLoggerDebug(kFIRMessagingMessageCodeRmq2PersistentStore004,
#"Trying to delete %d s2D ID's, successfully deleted %d", toDelete,
deleteCount);
});
}
- (int64_t)nextRmqId {
return ++self.rmqId;
}
- (NSString *)lastErrorMessage {
return [NSString stringWithFormat:#"%s", sqlite3_errmsg(_database)];
}
- (int)lastErrorCode {
return sqlite3_errcode(_database);
}
- (void)logError {
FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStore006,
#"Error: code (%d) message: %#", [self lastErrorCode],
[self lastErrorMessage]);
}
- (void)logErrorAndFinalizeStatement:(sqlite3_stmt *)stmt {
[self logError];
sqlite3_finalize(stmt);
}
- (dispatch_queue_t)databaseOperationQueue {
return _databaseOperationQueue;
}
#end
Thanks for your help.
Related
macOS SearchKit CoreService found nothing
im working on an that search in the content of allot of files, i planed to use SearchKit but i can't figure out to make Apple's sample code to work, and i can't find any other ressources (NSHipster code didn't work either), here's my code: #define kSearchMax 1000 #interface ViewController() #property(nonatomic) SKIndexRef mySKIndex; #end #implementation ViewController #synthesize mySKIndex; - (void)viewDidLoad { [super viewDidLoad]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ [self openIndex]; [self addDoc]; SKIndexFlush(self.mySKIndex); // i thought that the indexation may need some time .. sleep(2); dispatch_async(dispatch_get_main_queue(), ^{ [self searchterm:#"var"]; }); }); } - (void) openIndex { NSString *path = [[NSHomeDirectory() stringByAppendingPathComponent:#"index"] stringByAppendingPathExtension:#"txt"]; // 1 NSURL *url = [NSURL fileURLWithPath:path]; NSString *name = #"extension_index"; if ([name length] == 0) name = nil; SKIndexType type = kSKIndexInverted; if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { mySKIndex = SKIndexOpenWithURL ((__bridge CFURLRef) url, (__bridge CFStringRef) name, true ); }else{ self.mySKIndex = SKIndexCreateWithURL((__bridge CFURLRef) url, (__bridge CFStringRef) name, (SKIndexType) type, (CFDictionaryRef) NULL); } } - (void) addDoc { SKLoadDefaultExtractorPlugIns (); NSString *path = [NSBundle.mainBundle pathForResource:#"Products" ofType:#"rtf"]; // 1 NSURL *url = [NSURL fileURLWithPath: path]; // 2 SKDocumentRef doc = SKDocumentCreateWithURL ((__bridge CFURLRef) url); NSString *mimeTypeHint = #"text/rtf"; BOOL added = SKIndexAddDocument ((SKIndexRef) mySKIndex, (SKDocumentRef) doc, (__bridge CFStringRef)mimeTypeHint, (Boolean) true ); NSLog(added ? #"added" : #"not added"); } - (void) searchterm:(NSString*)query{ SKSearchOptions options = kSKSearchOptionDefault; BOOL more = YES; UInt32 totalCount = 0; SKSearchRef search = SKSearchCreate (mySKIndex, (__bridge CFStringRef) query, options); while (more) { SKDocumentID foundDocIDs [kSearchMax]; float foundScores [kSearchMax]; float *scores; Boolean unranked = options & kSKSearchOptionNoRelevanceScores; if (unranked) { scores = NULL; } else { scores = foundScores; } CFIndex foundCount = 0; more = SKSearchFindMatches ( search, kSearchMax, foundDocIDs, scores, 100, &foundCount ); NSLog(#"%#", [NSString stringWithFormat:#"current count = %i", totalCount]); totalCount += foundCount; } } #end it always print "current count = 0" and the loop is executed only one time.
Compare variable with SQLite values
I need to check if a variable has already been inserted on my SQLite db in order to change an image button, I tried to use this method but it's not working properly: sqlite3_stmt *statement; const char *dbpath = [databasePath UTF8String]; if (sqlite3_open(dbpath, &Preferiti) == SQLITE_OK) { NSString *checkSQL = [NSString stringWithFormat: #"SELECT * FROM ListaEventi WHERE idEvento=%#", [DettagliEvento objectAtIndex:7]]; const char *insert_stmt = [checkSQL UTF8String]; sqlite3_prepare_v2(Preferiti, insert_stmt, -1, &statement, NULL); if (sqlite3_step(statement) == SQLITE_DONE) { [_preferito setImage:[UIImage imageNamed:#"staroff.png"] forState:UIControlStateNormal]; _preferito.tag=0; } else { [_preferito setImage:[UIImage imageNamed:#"staron.png"] forState:UIControlStateNormal]; _preferito.tag=1; } sqlite3_finalize(statement); sqlite3_close(Preferiti); } Is there any other way to write the statement to compare a variable with values inside my SQLite table?
GCDasyncUdpSocket can't reveive packets after changing from broadcast to unicast mode
Developing an iPAD app which communicates via WiFi to a UDP to serial converter. App starts out in broadcast mode and retrieves a list of responding units (requestPodIds). The received data maps a SN to the units IP address. The selected IP address is then used to communicate point-to-point between the iPad and the UDP/serial converter. My code works fine on the broadcast communications. And the unicast message I send out (requestStatus) to the units IP address is being received by the converter and it is responding as expected. However, I do not get any data back into the didReceiveData method. I do not understand why I am not getting the data back in the method: - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext My socket connections are located in the AppDelegate and the calls are mode from a viewController. Buttons on viewController are pressed as follows: 1. button1Click 2. button2Click; this calls requestPodIds; works fine; data returned which fills ten other button labels with pod ids; one is clicked; 3. getPodIdsClick; this loads the IP address of the UDP/Serial converter; 4. getStatusClick; this is where the problem occurs. The UDP message goes out, the UDP converter receives the message and responds, I never see the response data in didReceiveData. AppDelegate code: - (int) udpServiceStart { NSError * UDPError; if(GCDUdpSocket == nil) { GCDUdpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; } GCDUdpSocket.delegate = self; [GCDUdpSocket setIPv4Enabled:YES]; [GCDUdpSocket setIPv6Enabled:NO]; [GCDUdpSocket enableBroadcast:YES error:&UDPError]; if (![GCDUdpSocket bindToPort:udpPort error:&UDPError]) { NSLog(#"Error starting server (bind): %#", UDPError); return -1; } if (![GCDUdpSocket beginReceiving:&UDPError]) // if (![GCDUdpSocket receiveOnce:&UDPError]) { [GCDUdpSocket close]; NSLog(#"Error starting server (recv): %#", UDPError); return -1; } NSLog(#"UDP Link started on port %hu", [GCDUdpSocket localPort]); return 0; } - (void) connectToPodAtAddress: (NSString *) ipAddress { NSError * UDPError; [GCDUdpSocket enableBroadcast:NO error:&UDPError]; podIp = ipAddress; // if (![GCDUdpSocket connectToHost:podIp onPort:udpPort error:&UDPError]) // { // [GCDUdpSocket close]; // NSLog(#"Error connecting to host: %#", UDPError); // return; // } // if (![GCDUdpSocket beginReceiving:&UDPError]) // // if (![GCDUdpSocket receiveOnce:&UDPError]) // { // [GCDUdpSocket close]; // NSLog(#"Error starting server (recv): %#", UDPError); // return; // } } - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext { // NSError * UDPError; NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; if (msg) { NSLog(#"RCV: %#", msg); if(!commandBuffer) commandBuffer = [[NSMutableString alloc] initWithString:#""]; // Append the current message portion to the total message [commandBuffer appendString:msg]; NSString * commands = [[NSString alloc] initWithString: commandBuffer]; NSInteger cr_index = [commands rangeOfString:#"\r"].location; if([commands rangeOfString:#"\r"].location == NSNotFound) { if([commands rangeOfString:#"~~~ds"].location != NSNotFound) { [commandBuffer setString:#""]; } } else { [self decodeMessage:commands]; } } else { NSString *host = nil; uint16_t thePort = 0; [GCDAsyncUdpSocket getHost:&host port:&thePort fromAddress:address]; NSLog(#"Unknown message from : %#:%hu", host, thePort); } // // Queue up to Read Next Message // // if (![GCDUdpSocket receiveOnce:&UDPError]) // { // [GCDUdpSocket close]; // NSLog(#"Error starting server (recv): %#", UDPError); // return; // } } - (void)udpSendToHost:(NSString *)host onPort:(int) thePort theMessage: (NSString *) msg { NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding]; tag = 0; [GCDUdpSocket sendData:data toHost:host port:thePort withTimeout:-1 tag:tag]; NSLog(#"SENT message for tag (%i) to host %#:%i", (int)tag, host, thePort); NSLog(#"Message sent = (%#)", msg); } - (void) requestPodIds { #ifdef LOGFUNCTIONCALLS NSLog(logString,__FUNCTION__); #endif [podTable removeAllObjects]; // pod_table.Clear(); // Empty table of any previous responses if (GCDUdpSocket != nil) // null happens on startup if wireless adapter not found { // PodMessage to_pod = new PodMessage(PodCommands.ucget, PodParameters.serial_number); PodMessage *to_pod = [[PodMessage alloc] initWithCommand:ucget andParams:serial_number]; // int bytes = udp_socket.SendTo(Encoding.ASCII.GetBytes(to_pod.Message()), // new IPEndPoint(IPAddress.Broadcast, port)); [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod.message]; // Debug.Assert(bytes == to_pod.Message().Length); } } - (void) requestStatus { if (GCDUdpSocket != nil) // null happens on startup if wireless adapter not found { // PodMessage to_pod = new PodMessage(PodCommands.ucget, PodParameters.serial_number); PodMessage *to_pod1 = [[PodMessage alloc] initWithCommand:ucget andParams:status_pod]; [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod1.message]; // PodMessage *to_pod2 = [[PodMessage alloc] initWithCommand:ucget andParams:status_line0]; // [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod2.message]; // PodMessage *to_pod3 = [[PodMessage alloc] initWithCommand:ucget andParams:status_line1]; // [self udpSendToHost:podIp onPort:udpPort theMessage:to_pod3.message]; // Debug.Assert(bytes == to_pod.Message().Length); } } Access from the ViewController is as follows: wifiTestAppDelegate *appDelegate; appDelegate = (wifiTestAppDelegate *)[[UIApplication sharedApplication] delegate]; - (IBAction)button1Click:(id)sender { [appDelegate udpServiceStart]; } - (IBAction)button2Click:(id)sender { if([GCDUdpSocket isClosed]) { NSLog(#"Socket is Closed!"); } else { if([GCDUdpSocket isConnected]) { NSLog(#"Socket is Connected! Can't Broadcast!"); } else { [appDelegate requestPodIds]; } } } - (IBAction)podSelectClick:(id)sender { NSLog(#"Button with label %#",((UIButton *)sender).titleLabel.text); NSLog(#"Button with tag %i",((UIButton *)sender).tag); // UIButton *button = (UIButton *)[self.view viewWithTag:buttonTag++]; // [button setTitle:[podTable objectForKey:key] forState:UIControlStateNormal]; NSString * ipAddress = [podTable objectForKey:((UIButton *)sender).titleLabel.text]; NSLog(#"IP Address = %#",ipAddress); podIp = ipAddress; pod_sn = ((UIButton *)sender).titleLabel.text; [appDelegate connectToPodAtAddress:ipAddress]; getStatusButton.hidden = NO; [selectPodButton setTitle:ipAddress forState:UIControlStateNormal]; } - (IBAction)getPodIdsClick:(id)sender { int buttonTag = 101; NSMutableArray * sortArray = [[NSMutableArray alloc] initWithCapacity:100]; if([podTable count] > 0) { for (NSString *key in podTable) { [sortArray addObject:key]; } [sortArray sortUsingSelector:#selector(compare:)]; for(int i=0; i < [podTable count]; i++) { UIButton *button = (UIButton *)[self.view viewWithTag:buttonTag++]; [button setTitle:[sortArray objectAtIndex:i] forState:UIControlStateNormal]; } } } - (IBAction)getStatusClick:(id)sender { [appDelegate requestStatus]; }
No luck in getting GCDAsyncUdpSocket to send other than class broadcast. Resolved with implementation of BSD sockets solution for broadcast portion of code: int fd; int err; int junk; struct sockaddr_in addr; NSData * data; ssize_t bytesSent; static const int kOne = 1; fd = socket(AF_INET, SOCK_DGRAM, 0); assert(fd >= 0); err = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &kOne, sizeof(kOne)); assert(err == 0); data = [#"hello" dataUsingEncoding:NSUTF8StringEncoding]; assert(data != nil); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_len = sizeof(addr); addr.sin_port = htons(8023); addr.sin_addr.s_addr = htonl(0xffffffff); // 255.255.255.255 bytesSent = sendto(fd, [data bytes], [data length], 0, (const struct sockaddr *) &addr, sizeof(addr)); NSLog(#"bytes sent = %zd", bytesSent); junk = close(fd); assert(junk == 0);
can't figure why insert sqlite sql statement is not being executed , Xcode
everything looks good for me, but the prepare_v2 doesn't get SQLITE_OK the sql instruction is pretty basic, if I copy and paste it on the sqlite manager, it inserts fine is there anything I am missing? //from view controller - (void)viewDidLoad { [super viewDidLoad]; DBConnection* dbCon = [DBConnection alloc]; [dbCon init]; [dbCon InsertDataRollNo:#"888"]; } -(id)init { //[super init]; DBName = #"FoodDB2.sqlite"; NSArray* documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* documentsDir = [documentsPath objectAtIndex:0]; DBPath = [documentsDir stringByAppendingPathComponent:DBName]; return self; } -(void)InsertDataRollNo:(NSString*)theName { [self CheckAndCreateDB]; sqlite3* database; if(sqlite3_open([DBPath UTF8String], &database)== SQLITE_OK) { NSString* statement; sqlite3_stmt* compliedStatement; //statement = [[NSString alloc]initWithFormat:#"insert into Category(TheName)values('%d')",#"epa"]; statement = #"insert into Category(TheName)values('aaa')"; const char* sqlStatement = [statement UTF8String]; if(sqlite3_prepare_v2(database, sqlStatement, -1, &compliedStatement, NULL) == SQLITE_OK) { if(SQLITE_DONE!=sqlite3_step(compliedStatement)) { NSAssert1(0,#"Error by inserting '%s' ", sqlite3_errmsg(database)); } else { NSAssert1(0,#"cool '%s' ", #"ope"); } } sqlite3_finalize(compliedStatement); } sqlite3_close(database); } -(void)CheckAndCreateDB { BOOL success; NSFileManager* fileManager = [NSFileManager defaultManager]; success = [fileManager fileExistsAtPath:DBPath]; if(success) return; NSString* databasePathFromApp = [[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:DBName]; [fileManager copyItemAtPath:databasePathFromApp toPath:DBPath error:nil]; //[fileManager release]; }
I figure it out, actually I was not copying the sqlite file to iPhone project, running good now
help needed with sqlite manager
hi i m using sqlite manager now the manager is showing me tables inside the database but when i m running my code it says that the table is not found. Here is my code. please can someone point out my mistake. - (IBAction)saveDatabase { float x = [_openingBalance.text floatValue]; NSNumber *amount = [NSNumber numberWithFloat:x]; float y = [_monthlyBudget.text floatValue]; NSNumber *budget = [NSNumber numberWithFloat:y]; _uuid = [[UIDevice currentDevice] uniqueIdentifier]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsPath = [paths objectAtIndex:0]; NSString *filePath = [documentsPath stringByAppendingPathComponent:#"Accounts.sqlite"]; sqlite3 *database; if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) { const char *sqlStatement = "insert into Account (name, type , currencyCode , parentAccount , currentBalance , monthlyBudget , monthlyBudgetPercentage ) VALUES ( ? , ? , ? , ? , ? , ? , ?)"; sqlite3_stmt *compiledStatement; if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) { sqlite3_bind_text( compiledStatement, 1, [_accountName.text UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_int(compiledStatement, 2, 1); sqlite3_bind_text(compiledStatement, 3, [#"PKR" UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_int(compiledStatement, 4, 1); sqlite3_bind_double(compiledStatement, 5, [amount doubleValue]); sqlite3_bind_double(compiledStatement, 6, [budget doubleValue]); sqlite3_bind_int(compiledStatement, 7, 0); } if(sqlite3_step(compiledStatement) != SQLITE_DONE ) { NSLog( #"Error: %s", sqlite3_errmsg(database) ); } else { NSLog( #"Insert into row id = %lld", sqlite3_last_insert_rowid(database)); } char* errmsg; sqlite3_exec(database, "COMMIT", NULL, NULL, &errmsg); sqlite3_finalize(compiledStatement); sqlite3_close(database); } } The error is Error: no such table: Account
Use this for your file path.. NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Accounts.sqlite"];