0821 sqlite3_get_table函数(数据库函数的补充)

Part 1.电子词典代码

一.功能

客户端可以注册登录退出(一级导航栏),查词查找自己查询的记录和返回上一级导航栏(二级导航栏)

服务器端需创建用户数据库(信息表和记录表)和单词数据库,并完成与客户端的反馈和完成其功能。

二.服务器端

cs 复制代码
#include<myhead.h>

#define SER_PORT 8888
#define SER_IP "192.168.109.31"

//创建单词数据库和数据表
sqlite3 * create_cindb()
{
    sqlite3 * dicp = NULL;
    if(sqlite3_open("./dic.db",&dicp) != SQLITE_OK)
    {    
        printf("dic.db sqlite3_open error, errcode = %d,errmsg = %s\n",sqlite3_errcode(dicp),sqlite3_errmsg(dicp));
        return NULL;
    }
    printf("单词数据库创建完成\n");

    char *sql = "create table if not exists DICTABLE(dic char,dir char);";
    char *errmsg = NULL;
    if(sqlite3_exec(dicp,sql,NULL,NULL,&errmsg) != SQLITE_OK)
    {
        printf("dic.db.DICTABLE create table error:%s\n",errmsg);
        sqlite3_free(errmsg);
        return NULL;
    }
    return dicp;
}

//创建用户数据库和数据表
sqlite3 * create_usrdb()
{
    sqlite3 * usrp = NULL;
    if(sqlite3_open("./usr.db",&usrp) != SQLITE_OK)
    {
        printf("usr.db sqlite3_open error, errcode = %d,errmsg = %s\n",sqlite3_errcode(usrp),sqlite3_errmsg(usrp));
        return NULL;
    }
    printf("用户数据表创建成功\n");

    //用户信息表
    char *msgsql = "create table if not exists USRMSG(usrname char,usrpwd char,usrtext int);";
    char *msgerrmsg = NULL;
    if(sqlite3_exec(usrp,msgsql,NULL,NULL,&msgerrmsg) != SQLITE_OK)
    {
        printf("usr.db.USRMSG create table error\n");
        sqlite3_free(msgerrmsg);
        return NULL;
    }

    //用户记录表
    char *mrysql = "create table if not exists USRMRY(usrname char,memory char,time char);";
    char *mryerrmsg = NULL;
    if(sqlite3_exec(usrp,mrysql,NULL,NULL,&mryerrmsg) != SQLITE_OK)
    {
        printf("usr.db.USRMSG create table error\n");
        sqlite3_free(mryerrmsg);
        return NULL;
    }

    return usrp;
}

//读取文件录入单词和注释
int dicin(FILE * fp,sqlite3 * dicp)
{
    char str[128] = "";    
    char dic[128] = "";
    char dir[128] = "";
    
    while(fgets(str, sizeof(str), fp) != NULL) 
    {
        // 去除换行符
        str[strcspn(str, "\n")] = '\0';

        // 重置变量
        dic[0] = '\0';
        dir[0] = '\0';

        int word_len = 0;
        // 找到第一个空格的位置
        for(int i = 0; i < strlen(str); i++) 
        {
            if(str[i] == ' ') 
            {
                word_len = i;
                break;
            }
        }
        // 将单词复制到dic内
        if(word_len > 0) 
        {
            strncpy(dic, str, word_len);
            dic[word_len] = '\0';
        } 
        else 
            strcpy(dic, str);
        //将注释复制到dir内
        if(word_len > 0 && word_len < strlen(str)) 
        {
            int comment_start = word_len + 1;
            strcpy(dir, str + comment_start);
        }
        char sql[128] = "";
        sprintf(sql,"insert into DICTABLE values(\"%s\",\"%s\");",dic,dir);
        char * errmsg = NULL;
        if(sqlite3_exec(dicp,sql,NULL,NULL,&errmsg) != SQLITE_OK)
        {
            printf("insert error :%s\n",errmsg);
            sqlite3_free(errmsg);
            return -1;
        }
    }
    printf("单词录入完成\n");
    return 0;
}

//登录函数
int login(sqlite3 * usrp, int num, char *name, char *pwd, int new_fd)
{        
    char createsql[128] = "";        
    char * createerrmsg = NULL;        
    char loginsql[128] = "";        
    char * loginerrmsg = NULL;    
    char **resPtr = NULL;    
    int rows = 0;
    int clos = 0;
    char response[2] = "";
    
    switch(num)
    {
    case 1: // 注册
        sprintf(createsql,"insert into USRMSG values(\"%s\",\"%s\",%d);",name,pwd,0);

        if(sqlite3_exec(usrp,createsql,NULL,NULL,&createerrmsg) != SQLITE_OK)
        {
            printf("create error :%s\n",createerrmsg);
            sqlite3_free(createerrmsg);
            strcpy(response, "0"); // 注册失败
            send(new_fd, response, strlen(response), 0);
            return -1;
        }
        strcpy(response, "1"); // 注册成功
        send(new_fd, response, strlen(response), 0);
        break;
        
    case 2: // 登录
        sprintf(loginsql,"select * from USRMSG where usrname = \"%s\";",name);
        if(sqlite3_get_table(usrp,loginsql,&resPtr,&rows,&clos,&loginerrmsg) != SQLITE_OK)
        {
            printf("login select error:%s\n",loginerrmsg);
            sqlite3_free(loginerrmsg);
            strcpy(response, "0"); // 登录失败
            send(new_fd, response, strlen(response), 0);
            return -1;
        }
        
        // 检查是否找到用户
        if(rows == 0)
        {
            strcpy(response, "0"); // 用户不存在
            send(new_fd, response, strlen(response), 0);
            sqlite3_free_table(resPtr);
            return 0;
        }
        char *db_pwd = resPtr[clos + 1]; // 密码列
        char *db_status = resPtr[clos + 2]; // 状态列
        
        if(strcmp(db_status, "0") == 0) // 检查是否为已登录状态
        {
            if(strcmp(db_pwd, pwd) == 0) // 检查密码是否正确
            {
                char updsql[128] = "";
                sprintf(updsql,"update USRMSG set usrtext = 1 where usrname = \"%s\";",name);
                char * upderrmsg = NULL;
                if(sqlite3_exec(usrp,updsql,NULL,NULL,&upderrmsg) != SQLITE_OK)
                {
                    printf("update error :%s\n",upderrmsg);
                    sqlite3_free(upderrmsg);
                    strcpy(response, "0"); // 更新状态失败
                    send(new_fd, response, strlen(response), 0);
                    sqlite3_free_table(resPtr);
                    return -1;
                }
                strcpy(response, "1"); // 登录成功
                send(new_fd, response, strlen(response), 0);
                sqlite3_free_table(resPtr);
                return 1;
            }
            else
            {
                strcpy(response, "0"); // 密码错误
                send(new_fd, response, strlen(response), 0);
                sqlite3_free_table(resPtr);
                return 0;
            }
        }
        else if(strcmp(db_status, "1") == 0)
        {
            strcpy(response, "2"); // 已有账号在线
            send(new_fd, response, strlen(response), 0);
            sqlite3_free_table(resPtr);
            return 2;
        }
        sqlite3_free_table(resPtr);
        return 0;
    }
    return 0;
}

//时间函数
char* mymktime()
{
    time_t a = time(NULL);
    struct tm *p = localtime(&a);
    static char str[128] = "";
    sprintf(str,"%d.%d.%d %02d:%02d:%02d",p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
    return str;
}

//查询单词和查询数据函数
int dic_select(int num,sqlite3 * dicp,sqlite3 * usrp,char * str,char * name,int new_fd)
{
    char dicslg[128] = "";
    char imeyslg[128] = "";
    char smeyslg[128] = "";
    char *errmsg = NULL;
    char *mrymsg = NULL;
    char **resPtr = NULL;
    int rows = 0;
    int clos = 0;
    char rbuf[128] = "\0";
    switch(num)
    {
        case 1:
            sprintf(dicslg,"select * from DICTABLE where dic = \"%s\";",str);
            if(sqlite3_get_table(dicp,dicslg,&resPtr,&rows,&clos,&errmsg) != SQLITE_OK)//查询单词注释
            {
                printf("dic select error:%s\n",errmsg);
                sqlite3_free(errmsg);
                return -1;
            }
            
            if(rows > 0)
            {
                char *time =  mymktime();//时间函数
                sprintf(imeyslg,"insert into USRMRY values(\"%s\",\"%s\",\"%s\");",name,str,time);//记录插入到数据库(usrp.USRMRY),格式:用户名 单词 时间
                if(sqlite3_exec(usrp,imeyslg,NULL,NULL,&mrymsg) != SQLITE_OK)
                {
                    printf("memory insert error :%s\n",mrymsg);
                    sqlite3_free(mrymsg);
                }
                sprintf(rbuf,"%s\t%s",resPtr[clos], resPtr[clos+1]); // 使用动态索引
                send(new_fd,rbuf,strlen(rbuf),0);
            }
            else
            {
                sprintf(rbuf, "未找到单词: %s", str);
                send(new_fd, rbuf, strlen(rbuf), 0);
            }
            sqlite3_free_table(resPtr);
            break;
        case 2:
            sprintf(smeyslg,"select * from USRMRY where usrname = \"%s\";",name);//查询数据
            if(sqlite3_get_table(usrp,smeyslg,&resPtr,&rows,&clos,&errmsg) != SQLITE_OK)
            {
                printf("memory select error:%s\n",errmsg);
                sqlite3_free(errmsg);
                return -1;
            }
            for(int i = 1; i <= rows; i++) // 从1开始,跳过列名
            {
                memset(rbuf,0,sizeof(rbuf));
                for(int j = 0; j < clos; j++)
                {
                    strcat(rbuf,resPtr[i*clos+j]);
                    if(j < clos -1)
                        strcat(rbuf,"\t");
                }
                strcat(rbuf,"\n");
                send(new_fd,rbuf,strlen(rbuf),0);
            }
            sqlite3_free_table(resPtr);
            break;
    }
    return 0;
}

// 更新用户登录状态为离线
void update_user_offline(sqlite3 *usrp, char *username)
{
    if(username[0] != '\0')
    {
        char updsql[128] = "";
        sprintf(updsql,"update USRMSG set usrtext = 0 where usrname = \"%s\";",username);
        char * upderrmsg = NULL;
        if(sqlite3_exec(usrp,updsql,NULL,NULL,&upderrmsg) != SQLITE_OK)
        {
            printf("update offline error :%s\n",upderrmsg);
            sqlite3_free(upderrmsg);
        }
        else
            printf("用户 %s 已离线\n", username);
    }
}

int main(int argc, const char *argv[])
{
    // 删除旧的数据库文件
    if(access("./dic.db", F_OK) == 0)
    {
        system("rm dic.db");
        printf("单词数据库删除完成\n");
    }
    
    if(access("./usr.db", F_OK) == 0)
    {
        system("rm usr.db");
        printf("用户数据库删除完成\n");
    }
    
    //创建单词数据库和数据表
    sqlite3 * dicp = create_cindb();
    if(dicp == NULL)
    {
        printf("创建单词数据库失败\n");
        return -1;
    }

    //创建用户数据库和数据表
    sqlite3 * usrp = create_usrdb();
    if(usrp == NULL)
    {
        printf("创建用户数据库失败\n");
        sqlite3_close(dicp);
        return -1;
    }

    FILE* fp = fopen("./dict.txt", "r");
    if (fp == NULL)
    {
        ERR_MSG("open error");
        sqlite3_close(dicp);
        sqlite3_close(usrp);
        return -1;
    }
    dicin(fp,dicp);
    fclose(fp);

    int sfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == sfd)
    {
        ERR_MSG("socket error");
        sqlite3_close(dicp);
        sqlite3_close(usrp);
        return -1;
    }

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);
    if(-1 == bind(sfd,(struct sockaddr *)&sin,sizeof(sin)))
    {
        ERR_MSG("bind error");
        close(sfd);
        sqlite3_close(dicp);
        sqlite3_close(usrp);
        return -1;
    }

    if(-1 == listen(sfd,128))
    {
        ERR_MSG("listen error");
        close(sfd);
        sqlite3_close(dicp);
        sqlite3_close(usrp);
        return -1;
    }

    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);
    while(1)
    {
        int new_fd = accept(sfd,(struct sockaddr *)&cin,&addrlen);
        if(-1 == new_fd)
        {
            ERR_MSG("accept error");
            continue;
        }

        pid_t pid = fork();

        if(pid > 0)
            close(new_fd);
        else if(pid == 0)
        {    
            close(sfd);
            int flag = 0;
            char logname[128] = ""; // 存储登录的用户名
            
            while(1)//用户可以注册或者登录或者退出
            {
                char rbuf[128] = "";
                int res = recv(new_fd,rbuf,sizeof(rbuf)-1,0);
                if(res <= 0)
                {
                    if(res == 0)
                        printf("客户端断开连接\n");
                    else
                    {
                        perror("recv error");
                    }
                    // 更新用户状态为离线
                    update_user_offline(usrp, logname);
                    close(new_fd);
                    exit(0);
                }
                rbuf[res] = '\0'; // 确保字符串结束
                
                if(rbuf[0] == '1')//注册
                {
                    int createnum = 1;
                    char crename[128] = "";
                    char crepwd[128] = "";
                    if(sscanf(rbuf + 2,"%s %s",crename,crepwd) == 2) 
                        login(usrp,createnum,crename,crepwd,new_fd);
                }
                else if(rbuf[0] == '2')//登录
                {
                    int loginnum = 2;
                    char logpwd[128] = "";
                    if(sscanf(rbuf + 2,"%s %s",logname,logpwd) == 2) 
                    {
                         flag = login(usrp,loginnum,logname,logpwd,new_fd);
                         if(flag == 1)
                            printf("%s登录成功\n",logname);
                    }
                    if(flag == 1)//如果成功登录,则可以进行查词或者查记录或者退出
                    {
                        while(1)
                        {
                            char newrbuf[128] = "";
                            int res = recv(new_fd,newrbuf,sizeof(newrbuf)-1,0);
                            if(res <= 0)
                            {
                                if(res == 0)
                                    printf("客户端断开连接\n");
                                else
                                    perror("recv error");
                                // 更新用户状态为离线
                                update_user_offline(usrp, logname);
                                close(new_fd);
                                exit(0);
                            }
                            newrbuf[res] = '\0'; // 确保字符串结束
                            
                            if(newrbuf[0] == '1') // 查单词
                            {
                                int dicnum2 = 1;
                                char dicstr[128] = "";
                                strcpy(dicstr,newrbuf+2);
                                dic_select(dicnum2,dicp,usrp,dicstr,logname,new_fd);
                            }
                            else if(newrbuf[0] == '2') // 查记录
                            {
                                int mrynum2 = 2;
                                char mrystr[128] = "";
                                strcpy(mrystr,newrbuf+2);
                                dic_select(mrynum2,dicp,usrp,mrystr,logname,new_fd);
                            }
                            else if(newrbuf[0] == '3') // 返回主菜单
                            {
                                // 更新用户状态为离线
                                update_user_offline(usrp, logname);
                                flag = 0;
                                break;
                            }
                        }
                    }
                }
            }        
        }
        else
            ERR_MSG("fork error");
    }

    sqlite3_close(dicp);
    sqlite3_close(usrp);
    close(sfd);

    return 0;
}

三.客户端

cs 复制代码
#define SER_PORT 8888
#define SER_IP "192.168.109.31"

#include<myhead.h>

// 连接服务器
int connect_server() 
{
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sfd)
	{
        ERR_MSG("socket error");
    }

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);

    if (-1 == connect(sfd, (struct sockaddr*)&sin, sizeof(sin))) 
        ERR_MSG("connect error");

    return sfd;
}

// 主菜单
int main_menu() {
    printf("\n========== 电子词典 ==========\n");
    printf("1. 注册\n");
    printf("2. 登录\n");
    printf("3. 退出\n");
    printf("请选择操作: ");

    int choice;
    scanf("%d", &choice);
    while (getchar() != '\n'); 
    return choice;
}

// 二级菜单
int second_menu() 
{
    printf("\n========== 功能菜单 ==========\n");
    printf("1. 查单词\n");
    printf("2. 查记录\n");
    printf("3. 返回主菜单\n");
    printf("请选择操作: ");

    int choice;
    scanf("%d", &choice);
    while (getchar() != '\n'); 
    return choice;
}

// 注册功能
int register_user(int sfd) 
{
    char username[128] = "";
    char password[128] = "";
    char send_buf[256] = "";

    printf("\n========== 用户注册 ==========\n");
    printf("请输入用户名: ");
    scanf("%s", username);
    printf("请输入密码: ");
    scanf("%s", password);

    snprintf(send_buf, sizeof(send_buf), "1 %s %s", username, password);
    
    if (send(sfd, send_buf, strlen(send_buf), 0) < 0)
        ERR_MSG("send error");

    printf("注册请求已发送,等待服务器响应...\n");
}

// 登录功能
int login_user(int sfd, char *username) 
{
    char password[128] = "";
    char send_buf[256] = "";
    char recv_buf[128] = "";

    printf("\n========== 用户登录 ==========\n");
    printf("请输入用户名: ");
    scanf("%s", username);
    printf("请输入密码: ");
    scanf("%s", password);

    // 格式化发送数据: "2 用户名 密码"
    snprintf(send_buf, sizeof(send_buf), "2 %s %s", username, password);
    
    // 发送登录请求
    if (send(sfd, send_buf, strlen(send_buf), 0) < 0) 
        ERR_MSG("send error");

    // 接收服务器响应
    int res = recv(sfd, recv_buf, sizeof(recv_buf) - 1, 0);
    if (res < 0) 
        ERR_MSG("recv error");
    recv_buf[res] = '\0';

    // 解析服务器响应
    if (strcmp(recv_buf, "1") == 0) 
	{
        printf("登录成功!\n");
        return 1;
    } else if (strcmp(recv_buf, "2") == 0) 
	{
        printf("该用户已在线!\n");
        return 0;
    } else 
	{
        printf("用户名或密码错误!\n");
        return 0;
    }
}

// 查询单词功能
int query_word(int sfd, const char *username) 
{
    char word[128] = "";
    char send_buf[256] = "";
    char recv_buf[512] = "";

    printf("\n========== 查询单词 ==========\n");
    printf("请输入要查询的单词: ");
    scanf("%s", word);

    snprintf(send_buf, sizeof(send_buf), "1 %s", word);
    
    // 发送查询请求
    if (send(sfd, send_buf, strlen(send_buf), 0) < 0) 
        ERR_MSG("send error");
    int res = recv(sfd, recv_buf, sizeof(recv_buf) - 1, 0);
    if (res < 0) 
        ERR_MSG("recv error");
    recv_buf[res] = '\0';

    printf("查询结果: %s\n", recv_buf);
}

// 查询记录功能
int query_history(int sfd, const char *username) 
{
    char send_buf[256] = "";
    char recv_buf[1024] = "";

    printf("\n========== 查询记录 ==========\n");

    // 格式化发送数据: "2 用户名"
    snprintf(send_buf, sizeof(send_buf), "2 %s", username);
    
    // 发送查询请求
    if (send(sfd, send_buf, strlen(send_buf), 0) < 0) 
        ERR_MSG("send error");

    // 接收服务器响应
    printf("查询记录:\n");
    while (1) {
        int res = recv(sfd, recv_buf, sizeof(recv_buf) - 1, 0);
        if (res < 0)
            ERR_MSG("recv error");
        
        if (res == 0) 
            break;         
        recv_buf[res] = '\0';
        
        if (strstr(recv_buf, "END") != NULL) 
		{
            char *end_pos = strstr(recv_buf, "END");
            *end_pos = '\0';
            printf("%s", recv_buf);
            break;
        }
        
        printf("%s", recv_buf);
    }
}

int main() 
{
    int sfd;
    int logged_in = 0;
    char username[128] = "";
    while (1) {
        if (!logged_in) 
		{
            int choice = main_menu();

            sfd = connect_server();

            switch (choice) 
			{
                case 1: 
                    register_user(sfd);
                    close(sfd);
                    break;
                case 2: 
                    if (login_user(sfd, username))
					{
                        logged_in = 1;
                    } else 
					{
                        close(sfd);
                    }
                    break;
                case 3: 
                    exit(0);
                default:
                    printf("无效选择,请重新输入!\n");
                    close(sfd);
                    break;
            }
        } 
		else 
		{
            int choice = second_menu();

            switch (choice) 
			{
                case 1: 
                    query_word(sfd, username);
                    break;
                case 2: 
                    query_history(sfd, username);
                    break;
                case 3: 
                    printf("返回主菜单...\n");
                    close(sfd);
                    logged_in = 0;
                    break;
                default:
                    printf("无效选择,请重新输入!\n");
                    break;
            }
        }
    }

    return 0;
}

Part 2.sqlite3_get_table函数

一.功能

功能:通过执行sql语句,得到结果集中的内容

二.函数原型

int sqlite3_get_table( sqlite3 *db,

const char *zSql,

char ***pazResult,

int *pnRow,

int *pnColumn,

char **pzErrmsg

);

三.参数

sqlite3 *db:数据库句柄

const char *zSql:要执行的sql语句

char ***pazResult:查询结果的起始地址,需要定义一个二级指针变量,将地址进行传递

int *pnRow: 查询结果的行数(不包括表头)

int *pnColumn:查询结果的列数

char **pzErrmsg :错误信息

相关推荐
smilejingwei1 小时前
数据分析编程第二步: 最简单的数据分析尝试
数据库·算法·数据分析·esprocspl
bing.shao2 小时前
gRPC 选型 etcd 的核心优势分析
数据库·微服务·云原生·golang·etcd
TDengine (老段)2 小时前
TDengine IDMP 应用场景:微电网监控
大数据·数据库·物联网·ai·时序数据库·tdengine·涛思数据
不叫猫先生3 小时前
Amazon Lambda:无服务器时代的计算革命,解锁多样化应用场景
服务器·数据库·人工智能·amazon lambda
秋天枫叶353 小时前
【AI应用】修改向量数据库Milvus默认密码
运维·服务器·数据库·ubuntu·milvus·milvus_cli
王伯爵4 小时前
go语言中的select的用法和使用场景
开发语言·数据库·golang
凯子坚持 c4 小时前
Redis 数据类型:List 列表的深度解析与应用
数据库·redis·list
DarkAthena4 小时前
【GaussDB】使用gdb定位GaussDB编译package报错
数据库·gaussdb
DONG9134 小时前
Redis内存架构解析与性能优化实战
数据库·redis·sql·database