两个数据库文件对比

 

如下图所示,函数首先打开两个数据库,然后获取两个数据库的版本信息。根据数据库各个表名称来打开相应的表,然后判断两个表的具体内容是否相同,如果不同的话则打印出该表名,如果用户选择打印具体内容的话,则分别打印两个表的具体内容(由于表的内容可能会比较多,且查看单个表内容的话使用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;
}
		


 

你可能感兴趣的:(两个数据库文件对比)