private static int GetFileVersion(string filePath) { if (IsVersion1(filePath)) { return(1); } // Versions 2+ are SQLite databases. Open it and read the version number inside. var sqlite = IntPtr.Zero; //sqlite3* var stmt = IntPtr.Zero; // sqlite3_stmt* try { using NativeString filePathNative = new(filePath); using NativeBuffer sqliteBuffer = new(IntPtr.Size); var result = NativeMethods.sqlite3_open(filePathNative.Ptr, sqliteBuffer.Ptr); if (result != NativeMethods.SQLITE_OK) { throw new Exception("This is not an SQL Notebook file."); } sqlite = Marshal.ReadIntPtr(sqliteBuffer.Ptr); var versionSql = "SELECT version FROM _sqlnotebook_version"; using NativeString versionSqlNative = new(versionSql); using NativeBuffer versionStmtNative = new(IntPtr.Size); result = NativeMethods.sqlite3_prepare_v2(sqlite, versionSqlNative.Ptr, versionSqlNative.ByteCount, versionStmtNative.Ptr, IntPtr.Zero); stmt = Marshal.ReadIntPtr(versionStmtNative.Ptr); // sqlite3_stmt* if (result != NativeMethods.SQLITE_OK || stmt == IntPtr.Zero) { // it's ok, a plain SQLite database is a valid version 2 SQL Notebook file return(2); } if (NativeMethods.sqlite3_step(stmt) == NativeMethods.SQLITE_ROW) { return(NativeMethods.sqlite3_column_int(stmt, 0)); } return(2); // missing version row; it's still a valid version 2 file } finally { if (stmt != IntPtr.Zero) { SqliteUtil.ThrowIfError(sqlite, NativeMethods.sqlite3_finalize(stmt)); } if (sqlite != IntPtr.Zero) { SqliteUtil.ThrowIfError(IntPtr.Zero, NativeMethods.sqlite3_close(sqlite)); } } }