如下图所示,函数首先打开两个数据库,然后获取两个数据库的版本信息。根据数据库各个表名称来打开相应的表,然后判断两个表的具体内容是否相同,如果不同的话则打印出该表名,如果用户选择打印具体内容的话,则分别打印两个表的具体内容(由于表的内容可能会比较多,且查看单个表内容的话使用SQLite软件看更直观,所以这个功能默认关闭)。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> #include "sqlite3.h" #include "database_table.h" #define OK 0 #define ERROR -1 #define TRUE 1 #define FALSE 0 #define TABLE_START_STR "CREATE TABLE IF NOT EXISTS" /**@brief 数据库查询返回结构 */ typedef struct{ int rows; ///> 查询结果的行数 int column; ///> 查询结果的列数 char ** data; ///> 查询结果的数据,一维数组,先是列名,然后是数据 }QUERY_TABLE; /**@brief 根据要查询的内容输入sql语句,返回要查询的数据集 * @param[in] DATABASE * db 数据库的连接句柄,不能为NULL * @param[in] char *sql 要查询的sql语句,可以在数据库中正常运行的,不能为NULL * @param[out] QUERY_TABLE *ds 返回的查询结果结构体 * @return int SQLITE_OK 查询获取成功; 其他都是失败 */ int db_query_open_v2 (sqlite3 *db, const char *table_name, QUERY_TABLE *ds) { int ret = -1; char * errmsg = NULL; char sql[128] = { 0 }; if( (NULL == db)||(NULL == table_name) ) { return ret; } sprintf(sql, "select * from %s", table_name); ret = sqlite3_get_table(db, sql, &(ds->data), &(ds->rows), &(ds->column), &errmsg); if (ret != SQLITE_OK) { printf("sqlite3_get_table:%d, %s\n",ret, errmsg); sqlite3_free(errmsg); } return ret; } /**@brief 关闭并释放查询返回的数据 * @param[in] QUERY_TABLE *ds 返回的查询结果结构体 * @return 无 */ void db_query_close_v2 (QUERY_TABLE *ds) { if(ds != NULL) { sqlite3_free_table(ds->data); } } /**@brief 比较两个表是否不同 * @param[in] QUERY_TABLE *table1 数据库1的表 * @param[in] QUERY_TABLE *table2 数据库2的表 * @param[out] * @return FALSE:两个表不同 TRUE:两个表相同 */ int compare_tables(QUERY_TABLE *table1, QUERY_TABLE *table2) { int ret = 0; int row = 0, col = 0; char *str1 = NULL, *str2 = NULL; if(NULL == table1 || NULL == table2) { return FALSE; } /*两个表的行列数不同,则肯定不相等*/ if (table1->rows != table2->rows || table1->column != table2->column) { return FALSE; } for (row = 1; row <= table1->rows; row++) { for (col = 0; col < table1->column; col++) { str1 = (table1->data)[row * table1->column + col]; str2 = (table2->data)[row * table2->column + col]; /*两个表的内容都为空,则表示相等,不需要strcmp判断*/ if (str1 == NULL && str2 == NULL) { continue; } else if(str1 == NULL || str2 == NULL) { return FALSE; } else { ret = strcmp(str1, str2); if (ret != 0) { return FALSE; } } } } return TRUE; } /**@brief 打印两个表的信息 * @param[in] int is_show_content:是否需要显示表的具体内容 * @param[in] const char *table_name:需要打印的表名称 * @param[in] QUERY_TABLE *table 数据库1的表 * @param[in] QUERY_TABLE *table1 数据库2的表 * @param[out] * @return */ void print_table(int is_show_content, const char *table_name, QUERY_TABLE *table, QUERY_TABLE *table1) { int row = 0, col = 0; if(NULL == table_name || NULL == table || NULL == table1) { return ; } printf("different table: <%s>\n", table_name); if(is_show_content) { for (row = 0; row <= table->rows; row++) { for (col = 0; col < table->column; col++) { printf("%s | ", (table->data)[row * table->column + col]); } printf("\n"); } printf("\n"); for (row = 0; row <= table1->rows; row++) { for (col = 0; col < table1->column; col++) { printf("%s | ", (table1->data)[row * table1->column + col]); } printf("\n"); } printf("\n"); } } /**@brief 提取表中的表名 * @param[in] char *p_database_table:表具体定义的字符串 * @param[in] char *p_table_names:需要返回的表名称 * @param[out] char *p_table_names:获取到的表名称 * @return 0:获取成功 -1:获取失败 */ int parse_table_names(char *p_database_table, char *p_table_names) { char input[1024]; char *p_tmp_str = NULL; memset(input, 0, sizeof(input)); memcpy(input, p_database_table, sizeof(input)); if(NULL == p_table_names || NULL == p_database_table) { printf("table name is null\n"); return -1; } p_tmp_str = strtok(input, TABLE_START_STR); if(p_tmp_str) { memcpy(p_table_names, p_tmp_str, strlen(p_tmp_str)); return 0; } return -1; } /**@brief 获取数据库的版本 * @param[in] sqlite3 *db:打开的数据库 * @param[in] char *p_db_name:数据库名称 * @param[out] * @return */ void get_db_version(sqlite3 *db, char *p_db_name) { QUERY_TABLE table; int ret = 0; if(NULL == db || NULL == p_db_name) { return ; } ret = db_query_open_v2(db, "db_version", &table); printf("db name:<%s> version:<%s>\n", p_db_name, (table.data)[1]); db_query_close_v2(&table); } int main(int argc, char **argv) { sqlite3 *db1 = NULL; sqlite3 *db2 = NULL; QUERY_TABLE table1, table2; int i = 0; int ret = 0, ret1 = 0, ret2 = 0; int table_num = 0, is_show_content = 0; char table_names[64] = {0}; if (argc < 3) { printf("%s db_name1 db_name2 show_content<0/1> \n", argv[0]); return -1; } // 打开两个数据库 // 打开指定的数据库文件,如果不存在将创建一个同名的数据库文件 ret = sqlite3_open(argv[1], &db1); if (ret != SQLITE_OK) { printf("can not open db %s\n", argv[1]); return -1; } ret = sqlite3_open(argv[2], &db2); if (ret != SQLITE_OK) { printf("can not open db %s\n", argv[2]); return -1; } get_db_version(db1, argv[1]); get_db_version(db2, argv[2]); /*是否需要显示数据库内容*/ if((argc == 4) &&memcmp(argv[3], "1", sizeof("1")) == 0) { is_show_content = 1; } table_num = sizeof(create_tables) / sizeof(char *); // 分别读取两个数据库的内容 for (i = 0; i < table_num; i++) { memset(table_names, 0, sizeof(table_names)); if(parse_table_names(create_tables[i], table_names) != 0) { continue; } ret1 = db_query_open_v2(db1, table_names, &table1); ret2 = db_query_open_v2(db2, table_names, &table2); if (ret1 != OK || ret2 != OK) { printf("query table %s error\n", table_names); continue; } /*比较如果两个表不同的话则打印相应信息*/ if (!compare_tables(&table1, &table2)) { print_table(is_show_content, table_names, &table1, &table2); } db_query_close_v2(&table1); db_query_close_v2(&table2); } sqlite3_close(db1); sqlite3_close(db2); return 0; }