首页 > 解决方案 > sqlite3 会产生非确定性错误吗?

问题描述

在 Sqlite3 数据库(VS 2015 Express 测试)中保存和读取数据时出现随机错误。

做了简单的跟踪,有时可以看到更新后 select 读取的内容有所修改,但不确定它来自哪里或是什么原因。有时它们很频繁,但现在它们非常罕见 - 例如,在短时间内同一测试用例的几次手动运行期间,上次 2 倍不同的 uint8_t 值......

我如何检查是什么导致了这个-DB/FS/sqlite3.c 问题或其他问题?

我正在测试仅具有单个 SSD 驱动器的 3 个月大的 NTB。

我的跟踪代码:

sqlite3_trace_v2(数据库,SQLITE_TRACE_STMT | SQLITE_TRACE_ROW,DBtrace::Trace,0);

class DBtrace {
public:
    static bool logNow;
    static std::string log;

    DBtrace(bool enable = false) { logNow = enable; }

    DBtrace & DBtrace::Instance()
    {
        static DBtrace  instance;
        return instance;
    }

    static int Trace(unsigned int d, void *m, void *p, void *x);
};

#include "sqlite3.h"
#include "db_trace.hpp"
#include <stdio.h>
#include <algorithm>

using namespace std;

namespace databaseNS
{
    bool DBtrace::logNow;
    std::string DBtrace::log;

    static int isUseless(int c) { return c < 32; }
    bool BothAreSpaces(char lhs, char rhs) { return (lhs == rhs) && (lhs < 32); }

    int DBtrace::Trace(unsigned int d, void *m, void *p, void *x) {
        if (!logNow) return 0;
        string sql;
        std::string::iterator new_end;
        sqlite3_value *v;
        sqlite3_stmt *pStmt = reinterpret_cast<sqlite3_stmt *>(p);
        int cc = sqlite3_column_count(pStmt);
        switch (d)
        {
        case SQLITE_TRACE_STMT:
            sql = sqlite3_expanded_sql(pStmt);
            new_end = std::unique(sql.begin(), sql.end(), BothAreSpaces);
            sql.erase(new_end, sql.end());
            sql += "\r\n";
            log += sql;
            break;

        case SQLITE_TRACE_ROW:
            int n = sqlite3_bind_parameter_count(pStmt);
            for (int i = 0; i < cc; i++)
            {
                sql = sqlite3_column_name(pStmt, i);
                v = sqlite3_column_value(pStmt, i);
                if (v->flags & MEM_Int) {
                    sql += ":" + std::to_string(v->u.i) + ", ";
                    log += sql;
                }
                if (v->flags & MEM_Str) {
                    sql += ":";
                    sql += v->z;
                    sql += ", ";
                    log += sql;
                };
            }
            log += "\r\n";
            break;

        }

        return 0;
    }
}

并且在 sqlite3.c ( db_trace.hpp )中找到了许多必需的声明

#include <string>

   /**
   * @brief Routine for preparation sql queries needed for data handling
   *
   * @return true if success, false otherwise
   *
   */
   /*
   ** Integers of known sizes.  These typedefs might change for architectures
   ** where the sizes very.  Preprocessor macros are available so that the
   ** types can be conveniently redefined at compile-type.  Like this:
   **
   **         cc '-DUINTPTR_TYPE=long long int' ...
   */
#ifndef UINT32_TYPE
# ifdef HAVE_UINT32_T
#  define UINT32_TYPE uint32_t
# else
#  define UINT32_TYPE unsigned int
# endif
#endif
#ifndef UINT16_TYPE
# ifdef HAVE_UINT16_T
#  define UINT16_TYPE uint16_t
# else
#  define UINT16_TYPE unsigned short int
# endif
#endif
#ifndef INT16_TYPE
# ifdef HAVE_INT16_T
#  define INT16_TYPE int16_t
# else
#  define INT16_TYPE short int
# endif
#endif
#ifndef UINT8_TYPE
# ifdef HAVE_UINT8_T
#  define UINT8_TYPE uint8_t
# else
#  define UINT8_TYPE unsigned char
# endif
#endif
#ifndef INT8_TYPE
# ifdef HAVE_INT8_T
#  define INT8_TYPE int8_t
# else
#  define INT8_TYPE signed char
# endif
#endif
#ifndef LONGDOUBLE_TYPE
# define LONGDOUBLE_TYPE long double
#endif
typedef sqlite_int64 i64;          /* 8-byte signed integer */
typedef sqlite_uint64 u64;         /* 8-byte unsigned integer */
typedef UINT32_TYPE u32;           /* 4-byte unsigned integer */
typedef UINT16_TYPE u16;           /* 2-byte unsigned integer */
typedef INT16_TYPE i16;            /* 2-byte signed integer */
typedef UINT8_TYPE u8;             /* 1-byte unsigned integer */
typedef INT8_TYPE i8;              /* 1-byte signed integer */
typedef struct FuncDef FuncDef;
struct sqlite3_value {
    union MemValue {
        double r;           /* Real value used when MEM_Real is set in flags */
        i64 i;              /* Integer value used when MEM_Int is set in flags */
        int nZero;          /* Extra zero bytes when MEM_Zero and MEM_Blob set */
        const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
        FuncDef *pDef;      /* Used only when flags==MEM_Agg */
    } u;
    u16 flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
    u8  enc;            /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
    u8  eSubtype;       /* Subtype for this value */
    int n;              /* Number of characters in string value, excluding '\0' */
    char *z;            /* String or BLOB value */
                        /* ShallowCopy only needs to copy the information above */
    char *zMalloc;      /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
    int szMalloc;       /* Size of the zMalloc allocation */
    u32 uTemp;          /* Transient storage for serial_type in OP_MakeRecord */
    sqlite3 *db;        /* The associated database connection */
    void(*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
#ifdef SQLITE_DEBUG
    Mem *pScopyFrom;    /* This Mem is a shallow copy of pScopyFrom */
    u16 mScopyFlags;    /* flags value immediately after the shallow copy */
#endif
};
/* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct.
**
** If the MEM_Null flag is set, then the value is an SQL NULL value.
** For a pointer type created using sqlite3_bind_pointer() or
** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.
**
** If the MEM_Str flag is set then Mem.z points at a string representation.
** Usually this is encoded in the same unicode encoding as the main
** database (see below for exceptions). If the MEM_Term flag is also
** set, then the string is nul terminated. The MEM_Int and MEM_Real
** flags may coexist with the MEM_Str flag.
*/
#define MEM_Null      0x0001   /* Value is NULL (or a pointer) */
#define MEM_Str       0x0002   /* Value is a string */
#define MEM_Int       0x0004   /* Value is an integer */
#define MEM_Real      0x0008   /* Value is a real number */
#define MEM_Blob      0x0010   /* Value is a BLOB */
#define MEM_AffMask   0x001f   /* Mask of affinity bits */
/* Available          0x0020   */
/* Available          0x0040   */
#define MEM_Undefined 0x0080   /* Value is undefined */
#define MEM_Cleared   0x0100   /* NULL set by OP_Null, not from data */
#define MEM_TypeMask  0xc1ff   /* Mask of type bits */

标签: c++sqlite

解决方案


推荐阅读