diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index 5d6a73c..a407417 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -643,6 +643,24 @@ public: */ int getColumnIndex(const char* apName) const; + + /** + * @brief Return the declared type of the specified result column for a SELECT statement. + * + * This is the type given at creation of the column and not the actual data type. + * SQLite stores data types dynamically for each value and not per column. + * + * @param[in] aIndex Index of the column in the range [0, getColumnCount()). + * + * Throw an exception if the type can't be determined because: + * - the specified index is out of the [0, getColumnCount()) range + * - the statement is not a SELECT query + * - the column at aIndex is not a table column but an expression or subquery + */ + const char * getColumnDeclaredType(const int aIndex) const; + + + //////////////////////////////////////////////////////////////////////////// /// Return the UTF-8 SQL Query. diff --git a/src/Statement.cpp b/src/Statement.cpp index c981ccb..8ab6862 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -296,6 +296,20 @@ int Statement::getColumnIndex(const char* apName) const return (*iIndex).second; } +const char * Statement::getColumnDeclaredType(const int aIndex) const +{ + checkIndex(aIndex); + const char * result = sqlite3_column_decltype(mStmtPtr, aIndex); + if (!result) + { + throw SQLite::Exception("Could not determine declared column type."); + } + else + { + return result; + } +} + int Statement::getBindParameterCount() const noexcept { return sqlite3_bind_parameter_count(mStmtPtr); diff --git a/tests/Statement_test.cpp b/tests/Statement_test.cpp index b80b35d..fbaec4b 100644 --- a/tests/Statement_test.cpp +++ b/tests/Statement_test.cpp @@ -918,6 +918,32 @@ TEST(Statement, getName) #endif } +TEST(Statement, getColumnDeclaredType) +{ + // Create a new database + SQLite::Database db(":memory:", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); + EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT, value DOUBLE)")); + + SQLite::Statement query(db, "SELECT *, 1 FROM test"); + + const std::string decltype0 = query.getColumnDeclaredType(0); + const std::string decltype1 = query.getColumnDeclaredType(1); + const std::string decltype2 = query.getColumnDeclaredType(2); + EXPECT_EQ("INTEGER", decltype0); + EXPECT_EQ("TEXT", decltype1); + EXPECT_EQ("DOUBLE", decltype2); + + // The column at index 3 is not a table column. + EXPECT_THROW(query.getColumnDeclaredType(3), SQLite::Exception); + + // Index out of bounds. + EXPECT_THROW(query.getColumnDeclaredType(4), SQLite::Exception); + + // Not a select statement. + SQLite::Statement pragma(db,"PRAGMA compile_options"); + EXPECT_THROW(pragma.getColumnDeclaredType(0), SQLite::Exception); +} + #if __cplusplus >= 201402L || (defined(_MSC_VER) && _MSC_VER >= 1900) TEST(Statement, getColumns) {