(sqlite3學習1)linux下C語言編程操作sqlite數據庫(含交叉編譯)

交叉編譯sqlite3:

#./configure CC=aarch64-linux-gnu-gcc
#make

加-host=arm-linux會生成靜態庫和動態庫,不加只生成靜態庫。

動態庫拷貝到執行環境,還需要:

# ldconfig   #使動態庫在系統中更新生效

 將庫拷貝到代碼執行環境:

====================================================

以下是轉載:

linux下C語言編程操作數據庫(sqlite3)

置頂 zouleideboke 2017-06-23 17:25:15   16699   收藏 32
展開
前言: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

/*********************************************************************************
 *      Copyright:  (C) 2017 zoulei
 *                  All rights reserved.
 *
 *       Filename:  insert.c
 *    Description:  This file i
 *
 *        Version:  1.0.0(2017年06月22日)
 *         Author:  zoulei <[email protected]>
 *      ChangeLog:  1, Release initial version on "2017年06月22日 19時31分12秒"
 *
 ********************************************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
#define _DEBUG_
int main(int argc, char**argv)
{
     sqlite3 *db=NULL;
     int len;
     int i=0;
     int nrow=0;
     int ncolumn = 0;
     char *zErrMsg =NULL;
     char **azResult=NULL; //二維數組存放結果
     /* 打開數據庫 */
     len = sqlite3_open("user",&db);
     if( len )
     {
        /*  fprintf函數格式化輸出錯誤信息到指定的stderr文件流中  */
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));//sqlite3_errmsg(db)用以獲得數據庫打開錯誤碼的英文描述。
        sqlite3_close(db);
        exit(1);
     }
     else printf("You have opened a sqlite3 database named user successfully!\n");
 
     /* 創建表 */
     char *sql = " CREATE TABLE SensorData(\
         ID INTEDER PRIMARY KEY,\
         SensorID INTEGER,\
         siteNum INTEGER,\
         Time VARCHAR(12),\
         SensorParameter REAL\
         );" ;
 
      sqlite3_exec(db,sql,NULL,NULL,&zErrMsg);
#ifdef _DEBUG_
      printf("%s\n",zErrMsg);
      sqlite3_free(zErrMsg);
#endif
      /*插入數據  */
      char*sql1 ="INSERT INTO 'SensorData'VALUES(NULL,1,2,201430506201,13.5);";
      sqlite3_exec(db,sql1,NULL,NULL,&zErrMsg);
      char*sql2 ="INSERT INTO 'SensorData'VALUES(NULL,3,4,201530506302,14.5);";
      sqlite3_exec(db,sql2,NULL,NULL,&zErrMsg);
      char*sql3 ="INSERT INTO 'SensorData'VALUES(NULL,5,6,201630506413,18.6);";
      sqlite3_exec(db,sql3,NULL,NULL,&zErrMsg);
 
      /* 查詢數據 */
      sql="select *from SensorData";
      sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
      printf("nrow=%d ncolumn=%d\n",nrow,ncolumn);
      printf("the result is:\n");
      for(i=0;i<(nrow+1)*ncolumn;i++)
        {
          printf("azResult[%d]=%s\n",i,azResult[i]);
        }
 
     /* 刪除某個特定的數據 */
      sql="delete from SensorData where SensorID = 1 ;";
      sqlite3_exec( db , sql , NULL , NULL , &zErrMsg );
#ifdef _DEBUG_
      printf("zErrMsg = %s \n", zErrMsg);
      sqlite3_free(zErrMsg);
#endif
 
      /* 查詢刪除後的數據 */
      sql = "SELECT * FROM SensorData ";
      sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
      printf( "row:%d column=%d\n " , nrow , ncolumn );
      printf( "After deleting , the result is : \n" );
      for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )
      {
            printf( "azResult[%d] = %s\n", i , azResult[i] );
      }
      sqlite3_free_table(azResult);
#ifdef _DEBUG_
   printf("zErrMsg = %s \n", zErrMsg);
   sqlite3_free(zErrMsg);
#endif
 
      sqlite3_close(db);
      return 0;
 
}
 代碼分析:

其實操作數據庫無非就是如何調用sqlite3提供的API,以及如何使用相應的語句操作sqlite3數據庫進行增,刪,改,查等。那麼下面我們着重分析

一下sqlite3提供的函數接口。

1.打開數據庫函數接口

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

int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
用這個函數開始數據庫操作。需要傳入兩個參數,一是數據庫文件名,比如:我的虛擬機~/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);


int sqlite3_exec(
  sqlite3*,                     /* An open database */
  const char *sql,              /* SQL to be executed */
  sqlite_callback,              /* Callback function */
  void *,                       /* 1st argument to callback function */
  char **errmsg                 /* Error msg written here */
);
這就是執行一條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);


int sqlite3_get_table(
  sqlite3 *db,          /* An open database */
  const char *zSql,     /* SQL to be evaluated */
  char ***pazResult,    /* Results of the query */
  int *pnRow,           /* Number of result rows written here */
  int *pnColumn,        /* Number of result columns written here */
  char **pzErrmsg       /* Error msg written here */
);
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 )


————————————————
版權聲明:本文爲CSDN博主「zouleideboke」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zouleideboke/article/details/73649886

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章