无法使用sqlite3_bind_text插入数据库

时间:2019-03-18 09:46:40

标签: c sqlite

您好,我对此功能recup()有疑问。 recup()的目的是将在字符串chaine中找到的所有单词逐字地插入数据库。这些单词来自用户使用fgets设置的chaine。我面临的问题是,它仅插入与chaine的第一个单词相同长度的单词。 例如,如果我写“我想要一只猫”,则只会插入“ I”和“ a”。

int recup(char *chaine){

    char tab[30] ={0};
    char delim[] = " ";
    char *ptr = strtok(chaine,delim);

    int rc =0;
    char *sql ="INSERT INTO newTable SELECT * FROM dbTable where lemme =?";

    sqlite3_stmt *stmt = 0;

    rc = sqlite3_prepare_v2(db,sql,-1,&stmt,0); 

    do {
        // Expected word is printed here
        printf("%s\n",ptr);
        strcpy(tab,ptr);

        // For some reason, only words that match the length
        // of the first word are being inserted
        rc = sqlite3_bind_text(stmt,1,tab,-1,SQLITE_STATIC);  
        rc = sqlite3_step(stmt);
        ptr = strtok(NULL,delim);
    } while(ptr != NULL);
    rc = sqlite3_finalize(stmt); 
    return 0;
}


#include <ansi_c.h>
#include <sqlite3.h>
#include "fdata.h"
sqlite3 *db;   

int main(int argc, char* argv[]) { 
      int rc = 0;
      char chaine[100] = {0};
      rc = sqlite3_open("lexique.db",&db);
      check(rc);
      createNewT();
      question(&chaine);
      recup(&chaine);
      sqlite3_close(db); 
      return 0;
}

3 个答案:

答案 0 :(得分:1)

这是mcve,显示了如何使用strtok来标记示例字符串:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char *test = "I want a cat";
    char chaime[strlen(test) + 1];
    char *delim = " ";
    char *ptr = NULL;

    strcpy(chaime, test);
    ptr = strtok(chaime, delim);
    while (ptr) {
        printf("%s\n", ptr);
        ptr = strtok(NULL, delim);
    }
    return 0;
}

输出

[user@machine]: ./program
I
want
a
cat

注意

如果您能给我们这样的东西来证明您的问题,那么它将很容易为您提供帮助。

答案 1 :(得分:1)

strtok()函数修改传递给它的字符串。因此,有必要创建输入字符串的副本。请参阅@David Cullen的出色答案,该答案创建了mcve。

请参阅更正后的代码中的注释,以解释正在发生的事情。

#include <stdio.h>
#include <string.h>

int recup(char *chaine){


  char tab[30] ={0};
  char delim[] = " ";
  ///// strtok will modify its inut string argument, so create a copy of the input
  strcpy(tab, chaine);
  // ptr will contain the current last token that was parsed
  char *ptr = strtok(tab,delim); // pass the copy to strtok, ptr points to first word

  int rc =0;
  char *sql ="INSERT INTO newTable SELECT * FROM dbTable where lemme =?";

  sqlite3_stmt *stmt = 0;

  rc = sqlite3_prepare_v2(db,sql,-1,&stmt,0);


  while (ptr) {
    printf("%s\n",ptr);  // print the word that was just tokenized

    rc = sqlite3_bind_text(stmt,1,ptr,-1,SQLITE_STATIC);
    rc = sqlite3_step(stmt);
    ptr = strtok(NULL,delim);
  }
  rc = sqlite3_finalize(stmt);
  return 0;
}

答案 2 :(得分:1)

C SQLite API不太宽容,并且需要严格的语义。在这里,您的问题是您尝试在循环中重用SQL语句(正确)而不重置(错误)。当前流为:

sqlite3_open
sqlite3_prepare_v2
sqlite3_bind
sqlite3_step
sqlite3_bind => ERROR SQLITE_MISUSE

sqlite3_step的文档中说(强调我的):

  

SQLITE_DONE表示该语句已成功完成执行。在未首先调用sqlite3_reset()来将虚拟机重置回其初始状态之前,不应在此虚拟机上再次调用 sqlite3_step()

我认为以下sqlite3_step会导致语句重置,这将允许处理第三个单词,但您每第二个单词都会丢失。

循环应为:

do {
    printf("%s\n",ptr);
    strcpy(tab,ptr);


    rc = sqlite3_bind_text(stmt,1,tab,-1,SQLITE_STATIC);
    if (rc) {
        // process error
    }
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        // process error
    }
    sqlite3_reset(stmt);
    ptr = strtok(NULL,delim);
} while(ptr);