当前位置:   article > 正文

linux下C语言编程操作数据库(sqlite3)_linux c程序移植 sqlite3详细步骤

linux c程序移植 sqlite3详细步骤

前言:C语言中通过调用 sqlite 的函数接口来实现对数据库的管理(创建数据库、创建表格、插入数据、查询、数据、删除数据等),掌握sqlite数据库的语法,以及sqlite提供的函数接口,那么在linux下C语言编程操作数据库就变得简单了。

   Centos系统一般默认是没有安装sqlite3数据库的,所以我们要到其官网下载,我下载的版本是 sqlite-3.6.16.tar.gz  

[zoulei@CentOS sqlite]$ wget http://www.sqlite.org/sqlite-3.6.16.tar.gz
    进入下载目录,解压文件sqlite-3.6.16.tar.gz解压后生成sqlite-3.6.16目录. cd 进入sqlite-3.6.16

[zoulei@CentOS sqlite]$ tar -xzvf sqlite-3.6.16.tar.gz
[zoulei@CentOS sqlite]$ cd sqlite-3.6.16
[zoulei@CentOS sqlite-3.6.16]$

执行配置脚本,生成相关文件之后使用make命令编译

[zoulei@CentOS sqlite-3.6.16]$ ./configure
[zoulei@CentOS sqlite-3.6.16]$ make
[zoulei@CentOS sqlite-3.6.16]$ sudo make install
安装完成之后会在sqlite-3.6.16目录下生成sqlite3等文件

在linux下sqlite3具体怎么操作,可以参考这篇博客:点击打开链接

看代码:sqlite.c

  1. /*********************************************************************************
  2. * Copyright: (C) 2017 zoulei
  3. * All rights reserved.
  4. *
  5. * Filename: insert.c
  6. * Description: This file i
  7. *
  8. * Version: 1.0.0(2017年06月22日)
  9. * Author: zoulei <zoulei121@gmail.com>
  10. * ChangeLog: 1, Release initial version on "2017年06月22日 19时31分12秒"
  11. *
  12. ********************************************************************************/
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include "sqlite3.h"
  16. #define _DEBUG_
  17. int main(int argc, char**argv)
  18. {
  19. sqlite3 *db=NULL;
  20. int len;
  21. int i=0;
  22. int nrow=0;
  23. int ncolumn = 0;
  24. char *zErrMsg =NULL;
  25. char **azResult=NULL; //二维数组存放结果
  26. /* 打开数据库 */
  27. len = sqlite3_open("user",&db);
  28. if( len )
  29. {
  30. /* fprintf函数格式化输出错误信息到指定的stderr文件流中 */
  31. fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));//sqlite3_errmsg(db)用以获得数据库打开错误码的英文描述。
  32. sqlite3_close(db);
  33. exit(1);
  34. }
  35. else printf("You have opened a sqlite3 database named user successfully!\n");
  36. /* 创建表 */
  37. char *sql = " CREATE TABLE SensorData(\
  38. ID INTEDER PRIMARY KEY,\
  39. SensorID INTEGER,\
  40. siteNum INTEGER,\
  41. Time VARCHAR(12),\
  42. SensorParameter REAL\
  43. );" ;
  44. sqlite3_exec(db,sql,NULL,NULL,&zErrMsg);
  45. #ifdef _DEBUG_
  46. printf("%s\n",zErrMsg);
  47. sqlite3_free(zErrMsg);
  48. #endif
  49. /*插入数据 */
  50. char*sql1 ="INSERT INTO 'SensorData'VALUES(NULL,1,2,201430506201,13.5);";
  51. sqlite3_exec(db,sql1,NULL,NULL,&zErrMsg);
  52. char*sql2 ="INSERT INTO 'SensorData'VALUES(NULL,3,4,201530506302,14.5);";
  53. sqlite3_exec(db,sql2,NULL,NULL,&zErrMsg);
  54. char*sql3 ="INSERT INTO 'SensorData'VALUES(NULL,5,6,201630506413,18.6);";
  55. sqlite3_exec(db,sql3,NULL,NULL,&zErrMsg);
  56. /* 查询数据 */
  57. sql="select *from SensorData";
  58. sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
  59. printf("nrow=%d ncolumn=%d\n",nrow,ncolumn);
  60. printf("the result is:\n");
  61. for(i=0;i<(nrow+1)*ncolumn;i++)
  62. {
  63. printf("azResult[%d]=%s\n",i,azResult[i]);
  64. }
  65. /* 删除某个特定的数据 */
  66. sql="delete from SensorData where SensorID = 1 ;";
  67. sqlite3_exec( db , sql , NULL , NULL , &zErrMsg );
  68. #ifdef _DEBUG_
  69. printf("zErrMsg = %s \n", zErrMsg);
  70. sqlite3_free(zErrMsg);
  71. #endif
  72. /* 查询删除后的数据 */
  73. sql = "SELECT * FROM SensorData ";
  74. sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
  75. printf( "row:%d column=%d\n " , nrow , ncolumn );
  76. printf( "After deleting , the result is : \n" );
  77. for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
  78. {
  79. printf( "azResult[%d] = %s\n", i , azResult[i] );
  80. }
  81. sqlite3_free_table(azResult);
  82. #ifdef _DEBUG_
  83. printf("zErrMsg = %s \n", zErrMsg);
  84. sqlite3_free(zErrMsg);
  85. #endif
  86. sqlite3_close(db);
  87. return 0;
  88. }

 代码分析:

其实操作数据库无非就是如何调用sqlite3提供的API,以及如何使用相应的语句操作sqlite3数据库进行增,删,改,查等。那么下面我们着重分析

一下sqlite3提供的函数接口。

1.打开数据库函数接口

原型:int sqlite3_open(const char * filename, sqlite3 **ppDb);

  1. int sqlite3_open(
  2. const char *filename, /* Database filename (UTF-8) */
  3. sqlite3 **ppDb /* OUT: SQLite db handle */
  4. );

用这个函数开始数据库操作。需要传入两个参数,一是数据库文件名,比如:我的虚拟机~/sqlite/路径下的user文件,文件名不需要一定存在,如果此文件不存在,sqlite会自动建立它。如果它存在,就尝试把它当数据库文件来打开。二是sqlite3**,即前面提到的关键数据结构。这个结构底层细节如何,不需要管它。函数返回值表示操作是否正确,如果是SQLITE_OK则表示操作正常。相关的返回值sqlite定义了一些宏。具体这些宏的含义可以参考sqlite3.h 文件。

2.关闭数据库函数接口

原型:int sqlite3_close(sqlite3**ppDb);

ppDb为我们使用sqlite3_open()函数打开的数据库链接(对应我写的程序中的db变量)。

3.执行sql语句函数接口

原型:int sqlite3_exec(sqlite3*,const char*sql,sqlite_callback,void*data,char**errmsg);

  1. int sqlite3_exec(
  2. sqlite3*, /* An open database */
  3. const char *sql, /* SQL to be executed */
  4. sqlite_callback, /* Callback function */
  5. void *, /* 1st argument to callback function */
  6. char **errmsg /* Error msg written here */
  7. );

这就是执行一条sql 语句的函数,

第1个参数不再说了,是前面open函数得到的指针。说了是关键数据结构。
第2个参数const char*sql是一条sql 语句,以\0结尾。
第3个参数sqlite3_callback 是回调,当这条语句执行之后,sqlite3会去调用你提供的这个函数。通常设为NULL。
第4个参数void*是你所提供的指针,你可以传递任何一个指针参数到这里,这个参数最终会传到回调函数里面,如果不需要传递指针给回调函数,可以填NULL。
第5个参数char** errmsg 是错误信息。注意是指针的指针。sqlite3里面有很多固定的错误信息。执行sqlite3_exec 之后,执行失败时可以查阅这个指针(直接 printf("zErrMsg = %s \n", zErrMsg)得到一串字符串信息,这串信息告诉你错在什么地方。sqlite3_exec函数通过修改你传入的指针的指针,把你提供的指针指向错误提示信息,这样sqlite3_exec函数外面就可以通过这个char*得到具体错误提示。

************************************************************************************************************************

说明:通常,sqlite3_callback 和它后面的void*这两个位置都可以填NULL。填NULL表示你不需要回调。比如你做insert 操作,做delete操作,就没有必要使用回调。而当你做select 时,就要使用回调,因为sqlite3 把数据查出来,得通过回调告诉你查出了什么数据。虽然回调显得代码整齐,但有时候你还是想要非回调的select 查询。这可以通过sqlite3_get_table 函数做到。

原型:sqlite3_get_table(sqlite3*db,const char*zsql,char***pazResult,int*nrow,int*ncolumn,char**zErrmsg);

  1. int sqlite3_get_table(
  2. sqlite3 *db, /* An open database */
  3. const char *zSql, /* SQL to be evaluated */
  4. char ***pazResult, /* Results of the query */
  5. int *pnRow, /* Number of result rows written here */
  6. int *pnColumn, /* Number of result columns written here */
  7. char **pzErrmsg /* Error msg written here */
  8. );
  9. void sqlite3_free_table(char **result);

第1个参数不再多说,看前面的例子。
第2个参数是sql 语句,跟sqlite3_exec 里的sql 是一样的。是一个很普通的以\0结尾的char*字符串。
第3个参数是查询结果,它依然一维数组(不要以为是二维数组,更不要以为是三维数组)。它内存布局是:字段名称,后面是紧接着是每个字段值。
第4个参数是查询出多少条记录(即查出多少行,不包括字段名那行)。
第5个参数是多少个字段(多少列)。
第6个参数是错误信息,跟前面一样,这里不多说了。

pazResult返回的字符串数量实际上是(*pnRow+1)*(*pnColumn),因为前(*pnColumn)个是字段名。

注意:如果提供 了errmsg,用来创建错误消息的内存是在堆上分布的。 故在调用后,应该检查一下是否为null值,如果有错误发生,使用sqlite3_free()释放errmsg占用的内存。

*************************************************************************************************************************************************************************

编译运行

[zoulei@CentOS sqlite]$ gcc sqlite.c -o sqlite -l sqlite3

[zoulei@CentOS sqlite]$ ./sqlite
You have opened a sqlite3 database named user successfully!
table SensorData already exists
nrow=3 ncolumn=5
the result is:
azResult[0]=ID
azResult[1]=SensorID
azResult[2]=siteNum
azResult[3]=Time
azResult[4]=SensorParameter
azResult[5]=(null)
azResult[6]=1
azResult[7]=2
azResult[8]=201430506201
azResult[9]=13.5
azResult[10]=(null)
azResult[11]=3
azResult[12]=4
azResult[13]=201530506302
azResult[14]=14.5
azResult[15]=(null)
azResult[16]=5
azResult[17]=6
azResult[18]=201630506413
azResult[19]=18.6
zErrMsg = (null)
row:2 column=5
 After deleting , the result is :
azResult[0] = ID
azResult[1] = SensorID
azResult[2] = siteNum
azResult[3] = Time
azResult[4] = SensorParameter
azResult[5] = (null)
azResult[6] = 3
azResult[7] = 4
azResult[8] = 201530506302
azResult[9] = 14.5
azResult[10] = (null)
azResult[11] = 5
azResult[12] = 6
azResult[13] = 201630506413
azResult[14] = 18.6
zErrMsg = (null)

从程序输出结果就可以看出,在删除数据前,我们有三条记录,删除数据后我们发现,数据库内记录少了。从而实现了我们的删除数据目的。

****************************************************************************************************************************************************************************************

注意:这里我们可以看到,azResult 的前面 5 个数据正好是我们的表 SensorData 的列属性,之后才是我们要查询的数据。所以我们

的程序中才有 i<( nrow + 1 ) * ncolumn  的判断条件:
  for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
  printf( "azResult[%d] = %s/n", i , azResult[i] );

 输出中有 zErrMsg = (null) 这样的字句,这是 zErrMsg 保留的错误信息,正如你所看到的,zErrMsg 为空,表明在执行过程中没有错误信息。

***************************************************************************************************************************************************************************

遇到的问题:

[zoulei@CentOS sqlite]$ gcc sqlite.c -o sqlite
/tmp/cccHlOCK.o: In function `main':
opensqlite.c:(.text+0x21): undefined reference to `sqlite3_open'
opensqlite.c:(.text+0x38): undefined reference to `sqlite3_errmsg'
opensqlite.c:(.text+0x5f): undefined reference to `sqlite3_close'
opensqlite.c:(.text+0x83): undefined reference to `sqlite3_close'
collect2: ld 返回 1

问题解决:

出现上述问题是因为没有找到库文件的问题。
由于用到了用户自己的库文件,所以应该指明所用到的库,我们可以这样编译:

[zoulei@CentOS sqlite]$ gcc sqlite.c -o sqlite -l sqlite3

通过find命令找出sqlite3依赖的库:

[zoulei@CentOS sqlite-3.6.16]$ find -name "libsqlite3.so"
./.libs/libsqlite3.so
[zoulei@CentOS sqlite-3.6.16]$ cd ./.libs
[zoulei@CentOS .libs]$ ls


所以用 -l sqlite3 选项就可以了(由于编译生成的库文件是 libsqlite3.so.0.8.6 等,去掉前面的lib和后面的版本标志,就剩下 sqlite3 了所以是 -l sqlite3 )




声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/173244
推荐阅读
相关标签
  

闽ICP备14008679号