From 5967ebf3b75bb5817199178263b9cddab459af1d Mon Sep 17 00:00:00 2001 From: Jonathan Schleifer Date: Thu, 1 Oct 2020 23:43:39 +0000 Subject: [PATCH] Add support for retrieving columns FossilOrigin-Name: 727a6838a567ab678c28cb0dfc2b95aaa4fa9b5af7b29e9f9833ffd81cea8d9d --- src/SL3PreparedStatement.h | 5 +++- src/SL3PreparedStatement.m | 48 +++++++++++++++++++++++++++++++++++++- tests/Tests.m | 31 ++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/SL3PreparedStatement.h b/src/SL3PreparedStatement.h index aede8fe..73480fa 100644 --- a/src/SL3PreparedStatement.h +++ b/src/SL3PreparedStatement.h @@ -41,7 +41,10 @@ OF_ASSUME_NONNULL_BEGIN - (void)bindWithDictionary: (OFDictionary OF_GENERIC(OFString *, id) *)dictionary; - (void)clearBindings; -- (void)step; +- (id)objectForColumn: (size_t)column; +- (size_t)columnCount; +- (OFString *)nameForColumn: (size_t)column; +- (bool)step; - (void)reset; @end diff --git a/src/SL3PreparedStatement.m b/src/SL3PreparedStatement.m index 8fa6d34..e979092 100644 --- a/src/SL3PreparedStatement.m +++ b/src/SL3PreparedStatement.m @@ -161,7 +161,7 @@ bindObject(SL3PreparedStatement *statement, int column, id object) errorCode: code]; } -- (void)step +- (bool)step { int code = sqlite3_step(_stmt); @@ -169,6 +169,52 @@ bindObject(SL3PreparedStatement *statement, int column, id object) @throw [SL3ExecuteStatementFailedException exceptionWithStatement: self errorCode: code]; + + return (code == SQLITE_ROW); +} + +- (id)objectForColumn: (size_t)column +{ + if (column > INT_MAX) + @throw [OFOutOfRangeException exception]; + + switch (sqlite3_column_type(_stmt, column)) { + case SQLITE_INTEGER: + return [OFNumber numberWithLongLong: + sqlite3_column_int64(_stmt, column)]; + case SQLITE_FLOAT: + return [OFNumber numberWithDouble: + sqlite3_column_double(_stmt, column)]; + case SQLITE_TEXT: + return [OFString stringWithUTF8String: + (const char *)sqlite3_column_text(_stmt, column)]; + case SQLITE_BLOB: + return [OFData + dataWithItems: sqlite3_column_blob(_stmt, column) + count: sqlite3_column_bytes(_stmt, column)]; + case SQLITE_NULL: + return [OFNull null]; + default: + OF_ENSURE(0); + } +} + +- (size_t)columnCount +{ + return sqlite3_column_count(_stmt); +} + +- (OFString *)nameForColumn: (size_t)column +{ + const char *name; + + if (column > [self columnCount]) + @throw [OFOutOfRangeException exception]; + + if ((name = sqlite3_column_name(_stmt, column)) == NULL) + @throw [OFOutOfMemoryException exception]; + + return [OFString stringWithUTF8String: name]; } - (void)reset diff --git a/tests/Tests.m b/tests/Tests.m index 4e71719..6c224ac 100644 --- a/tests/Tests.m +++ b/tests/Tests.m @@ -64,6 +64,37 @@ OF_APPLICATION_DELEGATE(Tests) nil]]; [stmt step]; + stmt = [conn prepareStatement: @"SELECT * FROM test"]; + for (size_t i = 0; [stmt step]; i++) { + OF_ENSURE([stmt columnCount] == 3); + OF_ENSURE([[stmt nameForColumn: 0] isEqual: @"a"]); + OF_ENSURE([[stmt nameForColumn: 1] isEqual: @"b"]); + OF_ENSURE([[stmt nameForColumn: 2] isEqual: @"c"]); + + switch (i) { + case 0: + OF_ENSURE([[stmt objectForColumn: 0] + isEqual: [OFNumber numberWithInt: 5]]); + OF_ENSURE([[stmt objectForColumn: 1] + isEqual: @"String"]); + OF_ENSURE([[stmt objectForColumn: 2] + isEqual: [OFData dataWithItems: "abc" + count: 3]]); + break; + case 1: + OF_ENSURE([[stmt objectForColumn: 0] + isEqual: [OFNumber numberWithInt: 7]]); + OF_ENSURE([[stmt objectForColumn: 1] + isEqual: @"Test"]); + OF_ENSURE([[stmt objectForColumn: 2] + isEqual: [OFData dataWithItems: "xyz" + count: 3]]); + break; + default: + OF_ENSURE(0); + } + } + [OFApplication terminate]; } @end