sql - 为什么我无法在连接到 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;
}
在代码中我所做的是搜索给定的用户名,如果查询没有返回结果,我插入记录。如果它确实返回,那么它会打印用户名已经被占用。
解决方案
问题 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
但实际上,您似乎想temp
与SELECT 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 调用和相关结果。
推荐阅读
- office365 - 云端硬盘搜索不适用于客户端凭据令牌
- c - 为什么时间会变?
- sql - 无法创建索引,在物化视图上锁定
- tensorflow - 在 Keras 中连接两个嵌入层时,如何解决“indices[1,0] = 66 is not in [0, 25)”错误?
- javascript - JavaScript 计时器的问题
- eslint - 如何在 VS 代码中关闭 ESlinting 换行符
- r - 构建和扩展预测功能
- c# - C#:解码 Base64 字符串不返回完整结果/乱码
- python - 使用 Python 永久更改 Linux 中接口的 IP 地址
- powershell - 从 IP 地址获取数字的第二部分