首页 > 解决方案 > 为什么我无法在连接到 C 的 SQLite 中创建两个新用户?它不适用于两个电话

问题描述

我无法弄清楚为什么会发生这种情况。什么可能是逻辑错误或我该如何解决。实际上问题是即使我执行客户登录(不是这里的代码的一部分)然后尝试注册同样的问题。但我可以进行多次登录和注销。我可以创建一个新用户并使用它登录

#include<stdlib.h>
#include<string.h>
#include "sqlite3.c" 
char output[5][30];//to save result
int temp;//global variable to be used in callback again
typedef struct usr{char name[15],pass[15];int uid;}USER;
static int callback(void *data, int argc, char **argv, char **azColName)
{
    int i;
    temp=argc;//stores number of return values
    printf("\n*%d*\n",argc);
    for(i=0;i<argc;i++)
    {
        strcpy(output[i],argv[i]);
        printf("*%s* ",argv[i]);
    }
    return 0;
}
void INSERTC()
{
    printf("\n\n\t\t\t\t\t\t\t\t\t\t\t\t\tCustomer Signup");
    sqlite3 *db;
    char *zErrMsg = 0;
    int t,rc,*data;
    char sql[150],name[30],pass[30];
    printf("\n\tEnter your Username : ");
    scanf("%s",name);
    printf("\n\tEnter your Password : ");
    scanf("%s",pass);
    rc = sqlite3_open("trail1.db", &db);
    sprintf(sql, "SELECT userid FROM customer WHERE username='%s';",name);
    rc = sqlite3_exec(db, sql,callback,(void*)data, &zErrMsg);//callback is called for every line in result
    if(temp==0)
    {   
        strcpy(sql,"SELECT COUNT(*) FROM customer;");
        rc = sqlite3_exec(db, sql,callback,(void*)data, &zErrMsg);
        t=atoi(output[0]);
        sprintf(sql,"INSERT INTO customer(userid,username,password) VALUES(%d,'%s','%s');",t,name,pass);
        rc = sqlite3_exec(db, sql,callback,(void*)data, &zErrMsg);
        printf("\n\tSuccessfully Registered.\n");
        printf("\n\tUser Id Alloted : %d",t);
        sqlite3_close(db);
    }
    else
        printf("\n\tUsername already taken!");
    printf("\n\n\tPress Enter to continue...");
    getchar();getchar();
}

int main(int argc, char* argv[])
{
    INSERTC();//First call
    INSERTC();//Second call
    return 0;
}

代码执行前的表 代码执行

在代码中我所做的是搜索给定的用户名,如果查询没有返回结果,我插入记录。如果它确实返回,那么它会打印用户名已经被占用。

标签: sqlcdatabasesqlite

解决方案


问题 1

您可以根据变量来决定是否已使用用户名temp

这个设置为回调的argc参数。当您运行第一个 INSERTC 调用时,以下语句的回调SELECT COUNT(*) FROM customer设置temp为 1,因为有一个 result column COUNT(*)。实际结果是带有回调的 argv 参数的字符串。

文档说:

sqlite3_exec() 回调函数的第二个参数是结果中的列数。sqlite3_exec() 回调的第三个参数是一个指向字符串的指针数组,就像从 sqlite3_column_text() 获得的一样,每列一个。

https://www.sqlite.org/c3ref/exec.html

问题 2

但实际上,您似乎想tempSELECT userid FROM customer WHERE username='%s'之前进行检查。但是如果没有找到匹配用户名的记录,则不会调用回调。

数据指针

指针 *data 永远不会被初始化。

sqlite3_exec() 的第四个参数传递到每个回调调用的第一个参数。

由于您不使用数据指针,您可以只传递 NULL。如果要使用它,请确保初始化它。

返回代码

sqlite3 函数返回一个指示操作是否成功的代码。您应该检查操作是否成功并在失败时采取适当的措施(例如,将错误消息打印到 stderr 并以错误代码结束)。

关闭数据库连接

您只在 if 分支中调用 sqlite3_close 。但是您应该独立于结果关闭它。

更好地使用准备好的语句

您应该使用准备好的语句,而不是使用 sprintf 创建您自己的包含未经检查的外部用户输入的 SQL。使用未经检查的用户输入可能会导致最严重的安全风险之一,即 SQL 注入。

因此最好使用 sqlite3_prepare_v2()、sqlite3_step() 和 sqlite3_finalize()。基本上 sqlite3_exec 只是这些调用的方便包装器。有关如何使用它的示例,您可以查看https://stackoverflow.com/a/57505795/2331445

这种方法的另一个优点是您可以在同一个地方处理 SQL 调用和相关结果。


推荐阅读