[LinuxC & Sqlite database small project] Check-in system based on Sqlite------a small project suitable for beginners to practice

Recently, my little brother is always wanting to mess around and doesn’t want to study hard. This won’t work. I have to find a way and put in some effort, so I wrote a check-in program for myself;

This program is based on the Sqlite database and implements a simple check-in function. This function has the function of automatic initialization. When it is used for the first time, it will automatically create the database and table and assign the original initial value; after entering the interface, it will automatically display the last check-in date and The number of days has been clocked in; the user can choose to open or not to log out according to the prompts;
firstly, the effect picture is as follows:
Effect display
This program is actually a very basic version, with only a simple clock-in record function, so it is also very suitable for beginners who have just learned sqlite. practise;

If you are more proficient, you can enrich various functions based on this program and make a variety of more interesting systems, such as: access to face recognition to make an attendance check-in system; Just email you crazily; or convert it into a dictionary, as long as you have rich imagination, you can do a lot;

Well, before looking at the code formally, let’s briefly understand a few basic functions of sqlite:

sqlite3_open(const char *filename, sqlite3 **ppDb)
打开一个指向 SQLite 数据库文件的连接,返回一个用于其他 SQLite 程序的数据库连接对象。
如果打开时没有该filename的数据库,则会自动创建改名字的数据库

sqlite3_close(sqlite3*)
该例程关闭之前调用 sqlite3_open() 打开的数据库连接。所有与连接相关的语句都应在连接关闭之前完成。
如果还有查询没有完成,sqlite3_close() 将返回 SQLITE_BUSY 禁止关闭的错误消息。

const char *sqlite3_errmsg(sqlite3*);
返回sqlite执行错误的错误信息
sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void *data, char **errmsg)
提供了一个执行 SQL 命令的快捷方式,SQL 命令由 sql 参数提供,可以由多个 SQL 命令组成。

简单来说就是通过该函数来执行sql语句

在这里,第一个参数 sqlite3 是打开的数据库对象,sqlite_callback 是一个回调,
data 作为其第一个参数,errmsg 将被返回用来获取程序生成的任何错误。

The callback function sqlite_callback in sqlite3_exec has a fixed format, as follows:

int callback(void *arg, int column_size, char *column_value[], char *column_name[])

Among them:
void *arg: the fourth parameter of the sqlite3_exec function
column_size: the number of fields in the database
column_value[]: the value of
the column column_name: the name of the field

After understanding the above functions, take a look at the system code, which has been commented in detail;

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <time.h>

#define BUFSIZE 32
char sql[128];

//用于存放打卡天数和打卡时间
struct Data
{
    
    
	int day;
	char date[BUFSIZE];
};
sqlite3 *db;
char dbName[32] = "info.db";	//默认创建的数据库名叫info.db


/*用来判断info.db数据库是否存在,如果不存在则在初始化时创建数据库和表*/
int isExist(void *arg, int column_size, char *column_value[], char *column_name[])
{
    
       
	if (*column_value[0] == '0')
	{
    
    
		*(int*)arg = 0;		//即将existFlag置为0,表示不存在info表格,需要创建		
	}
    return 0; 
}


/*初始化数据库:如果已经存在info.db和info表格则不操作,如果不存在,则自动创建数据库和表,并赋初值*/
int db_init()
{
    
    
	int ret;
	int existFlag = 1;	//先默认数据库info.db是存在的
	char *errMesg = NULL;
	if ((ret = sqlite3_open(dbName,&db)) == SQLITE_OK)
	{
    
    
		printf("open %s success\n",dbName);
	}else{
    
    
		printf("error:%s,%d\n",sqlite3_errmsg(db),ret);
		return -1;
	}	

//查询表格是否存在
	strcpy(sql,"SELECT count(*) FROM sqlite_master WHERE type='table' AND name = 'info'");
	ret = sqlite3_exec(db,sql,isExist,&existFlag,&errMesg);
	if (ret != SQLITE_OK)
	{
    
    
		fprintf(stderr,"SQL error:%s\n",errMesg);
		sqlite3_free(errMesg);	//释放掉内存空间
	}
	
	if (existFlag == 0 )
	{
    
    	
		//创建表
		strcpy(sql,"create table info(day integer,date char);");
		ret = sqlite3_exec(db,sql,NULL,NULL,&errMesg);
		if (ret != SQLITE_OK)
		{
    
    
			fprintf(stderr,"SQL error:%s\n",errMesg);
		    sqlite3_free(errMesg);
		}
		
		//往表中插入原始数据
		strcpy(sql,"insert into info values(0,'20200101');");
		ret = sqlite3_exec(db,sql,NULL,NULL,&errMesg);
		if (ret != SQLITE_OK)
		{
    
    
			fprintf(stderr,"SQL error:%s\n",errMesg);
		    sqlite3_free(errMesg);
		}
	}
	sqlite3_free(errMesg);
}

/*用来从数据库中捞取数据*/
int get_data(void *arg, int column_size, char *column_value[], char *column_name[])
{
    
    
	int i;
	struct Data *dataInfoTmp;
	dataInfoTmp = (struct Data *)arg;	//将void型强制转化为 struct Data*型
	strcpy(dataInfoTmp->date,column_value[1]); 	//将数据库存放的第二列的值,即日期赋给dataInfoTmp->date 
	dataInfoTmp->day = atoi(column_value[0]);	//将打开天数赋给dataInfoTmp->day,atoi() :Convert char into int
	return 0;
}

/*用户确认打卡后,刷新数据库数据*/
int sign_in(struct Data *arg)
{
    
    
	struct Data *infoDataTmp = NULL;
	infoDataTmp = arg;
	char *errMesg = NULL;	
	int ret;	

    //日期相关
	time_t timep;
	struct tm* tm;
	time(&timep);
	tm = localtime(&timep);
	strftime(infoDataTmp->date,BUFSIZE,"%Y-%m-%d %H:%M",tm);	//将日期字符串制作成自己想要的格式
	
	//update the day
	infoDataTmp->day += 1;
    
    //刷新数据库数据
	memset(sql,0,sizeof(sql));
	sprintf(sql,"update info set day=%d,date='%s';",infoDataTmp->day,infoDataTmp->date);
    ret = sqlite3_exec(db,sql,get_data,&infoDataTmp,&errMesg);	
	if (ret != SQLITE_OK)
	{
    
    
		fprintf(stderr,"SQL error:%s\n",errMesg);
	    sqlite3_free(errMesg);

	}
	return 0;
}

int main()
{
    
    

	int ret,len;
	char cmd[BUFSIZE] = {
    
    '\0'};	//存放用户输入的指令
	char *errMesg = NULL;	
	struct Data infoData;

	db_init();	//初始化数据库
	
    //捞取数据库数据到结构体infoData中
	strcpy(sql,"select * from info;");
	ret = sqlite3_exec(db,sql,get_data,&infoData,&errMesg);	
	if (ret != SQLITE_OK)
	{
    
    
		fprintf(stderr,"SQL error:%s\n",errMesg);
	    sqlite3_free(errMesg);
	}
    
	//初始化界面    
	printf("========欢迎来打卡========\n");
	printf("上次打卡是:%s,已打卡%d天\n",infoData.date,infoData.day);

	while(1)
	{
    
    
		memset(cmd,'\0',sizeof(cmd));
		printf("确认打卡请输入Y,退出输入Q:\n");
		scanf("%s",cmd);
		getchar();	
		if(strcmp(cmd,"Y") == 0)
		{
    
    
			sign_in(&infoData);
			printf("已打卡\n");
			break;	

		}
		else if	(strcmp(cmd,"Q") == 0)
		{
    
    
			sqlite3_free(errMesg);
			printf("退出打卡\n");
			break;
		}
		else
		{
    
    
			printf("输入错误,请重新输入:\n");	
		}		
	}
	return 0;
}

In fact, the while(1) process in this program can be considered to open one more thread or encapsulate it into a function, so that the code will be more concise, and the little brother here is too lazy to change it, and everyone can modify it by themselves; it is purely for fun, so If there are bad things written, everyone is welcome to correct and criticize;

Guess you like

Origin blog.csdn.net/weixin_44517500/article/details/129966815