SQLITE更新失败,错误代码为1(SQLITE_错误)

SQLITE更新失败,错误代码为1(SQLITE_错误),sqlite,unicode,rtf,Sqlite,Unicode,Rtf,我的sqlite db有一个奇怪的问题,或者可能不是那么奇怪。我有一个“文本”类型的字段,它对任何英语文本都很有吸引力 字段中的文本过去来自MFC CEdit。现在我切换到CRichEditCtrl以支持格式化和UNICODE文本。CRICHEDITCRL以十六进制形式转储格式化文本,如:{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 MS Shell Dlg 2;}}}等 一旦重新访问sqlite,它大

我的sqlite db有一个奇怪的问题,或者可能不是那么奇怪。我有一个“文本”类型的字段,它对任何英语文本都很有吸引力

字段中的文本过去来自MFC CEdit。现在我切换到CRichEditCtrl以支持格式化和UNICODE文本。CRICHEDITCRL以十六进制形式转储格式化文本,如:{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 MS Shell Dlg 2;}}}等

一旦重新访问sqlite,它大部分时间都保存得很好。但有时它不会给出错误代码sqlite_error/*SQL error或missing database*/。该消息并没有太大帮助。数据库存在并保存了大部分时间???如图所示。 代码如下:

error = sqlite3_exec(db,cmd,0,0,0);
if (error != SQLITE_OK){
    errMsg.Format("Unable to save notes to: %s\nSQLite Error: %d",filename,error);
    AfxMessageBox(_T(errMsg));
    sqlite3_close(db);
    return false;
    }
我想没什么不寻常的

如果你有任何想法,请告诉我。这可能是因为RTF格式中有很多反斜杠,使sqlite混淆了吗?哦,这与保存的文本大小无关。 谢谢。
Val

如果一个反斜杠起作用,那么几个反斜杠也应该起作用。但如果文本包含撇号或双引号,则可能是您没有正确转义文本,这会中断查询

如果你没有转义引号,那么这可能就是问题所在

{blabla\'somethingelse}
然后再次转义该字符串以保留反斜杠(否则它们将在与数据库的通信中丢失),这将产生

{blabla\\'somethingelse}
然后瞧,你有一个撇号在上面


解决方法是先转义反斜杠,然后转义撇号和引号。

如果一个反斜杠有效,那么应该转义多个。但如果文本包含撇号或双引号,则可能无法正确转义文本,这会中断查询

如果你没有转义引号,那么这可能就是问题所在

{blabla\'somethingelse}
然后再次转义该字符串以保留反斜杠(否则它们将在与数据库的通信中丢失),这将产生

{blabla\\'somethingelse}
然后瞧,你有一个撇号在上面


解决方案是首先转义反斜杠,然后转义撇号和引号。

问题显然是由于没有转义代码中的特殊字符。我建议您对准备好的语句使用sqlite API,以避免大量字符串处理麻烦。它们将为您和handl在查询中插入值e自动转义

与此相反:

error = sqlite3_exec(db,cmd,0,0,0);
您需要这样做:

sqlite3_stmt *stmt;
error = sqlite3_prepare_v2(database, "INSERT INTO table (field) VALUES (?)", -1, &stmt, NULL);
if (error != SQLITE_OK) { ...
error = sqlite3_bind_text(stmt, 1, rtfString, -1, SQLITE_STATIC);
if (error != SQLITE_OK) { ...
error = sqlite3_step(stmt);
if (error != SQLITE_DONE) { ...
sqlite3_finalize(stmt);
sqlite将自动获取
rtfString
的值,正确地引用它,然后将它插入到查询中以代替问号


这种方法的另一个优点是可以重用
stmt
对象。每次使用后只需调用
sqlite3\u reset()
,记住调用
sqlite3\u finalize()
当你做得很好时。

问题显然是因为没有转义代码中的特殊字符。我建议你使用sqlite API来准备语句,以避免大量字符串处理麻烦。它们将为你在查询中插入值并自动处理转义

与此相反:

error = sqlite3_exec(db,cmd,0,0,0);
您需要这样做:

sqlite3_stmt *stmt;
error = sqlite3_prepare_v2(database, "INSERT INTO table (field) VALUES (?)", -1, &stmt, NULL);
if (error != SQLITE_OK) { ...
error = sqlite3_bind_text(stmt, 1, rtfString, -1, SQLITE_STATIC);
if (error != SQLITE_OK) { ...
error = sqlite3_step(stmt);
if (error != SQLITE_DONE) { ...
sqlite3_finalize(stmt);
sqlite将自动获取
rtfString
的值,正确地引用它,然后将它插入到查询中以代替问号


这种方法的另一个优点是可以重用
stmt
对象。每次使用后只需调用
sqlite3\u reset()
,记住调用
sqlite3\u finalize()
当你做得很好的时候。

嘿,Tor,我也怀疑反斜杠。因此,你可以确定,如果我的文本包含一些东西,sqlite可能会尝试解释它,而不是在我的更新字段“value…”中将其视为文本。你可能希望将cmd var打印到某个日志中,以便在发送时可以准确地看到它的外观。嘿Tor,我也怀疑是反斜杠。因此,您可以确定,如果我的文本包含某些内容,sqlite可能会尝试对其进行解释,而不是将其作为更新字段“value…”中的文本处理?您可能希望将cmd var打印到某个日志中,以便您可以确切地看到它在发送时的外观。谢谢benzado,因此我不需要sqlite3\u exec,不是吗?而是一系列sqlite\u prepare\u v2、sqlite3\u bind\u text、sqlite3\u step和finalize。哇,我将在周一第一件事尝试它。干杯,这并不是说你不需要它;
sqlite3\u exec本身调用
prepare
step
、和
finalize
。通过自己调用这些函数,你就可以得到对情况有更多的控制,可以使用
bind
,这就解决了你的报价问题。我迫不及待地要等到星期一。我刚试过,效果很好。谢谢大家。周末愉快。你们知道我是否应该在SELECT上对RTF字符串进行特殊处理吗?谢谢benzado,所以我根本不需要sqlite3_执行器,对吗t?取而代之的是一系列sqlite\u prepare\u v2、sqlite3\u bind\u text、sqlite3\u step和finalize。哇,我将在周一第一件事尝试它。干杯,这并不是说你不需要它;
sqlite3\u exec
本身调用
prepare
step
,以及
finalize
。通过自己调用这些函数,你可以获得更多的控制权r这种情况下,可以使用
bind
,这就解决了你的报价问题。我迫不及待地要到星期一。我刚试用过,效果很好。谢谢大家。祝你们周末愉快。你们知道我是否应该在SELECT上特别处理RTF字符串吗?