Libsqlite3

From 탱이의 잡동사니
Jump to navigation Jump to search

Overview

Sqlite3 프로그래밍.

Sqlite3 프로그래밍 관련 함수 전체 레퍼런스는 이곳<ref>https://www.sqlite.org/c3ref/funclist.html</ref> 혹은 이곳<ref>https://www.sqlite.org/capi3ref.html</ref>에서 확인할 수 있다.

Open

<source lang=c> int sqlite3_open(

 const char *filename,   /* Database filename (UTF-8) */
 sqlite3 **ppDb          /* OUT: SQLite db handle */

); int sqlite3_open16(

 const void *filename,   /* Database filename (UTF-16) */
 sqlite3 **ppDb          /* OUT: SQLite db handle */

); int sqlite3_open_v2(

 const char *filename,   /* Database filename (UTF-8) */
 sqlite3 **ppDb,         /* OUT: SQLite db handle */
 int flags,              /* Flags */
 const char *zVfs        /* Name of VFS module to use */

); </source>

Open Flags <source lang=c>

  1. define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
  2. define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
  3. define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */
  4. define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */
  5. define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */
  6. define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */
  7. define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */
  8. define SQLITE_OPEN_MEMORY 0x00000080 /* Ok for sqlite3_open_v2() */
  9. define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */
  10. define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */
  11. define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */
  12. define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
  13. define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
  14. define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
  15. define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
  16. define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
  17. define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
  18. define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
  19. define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
  20. define SQLITE_OPEN_WAL 0x00080000 /* VFS only */

</source>

One-step query execution interface

<source lang=c> int sqlite3_exec(

 sqlite3*,                                  /* An open database */
 const char *sql,                           /* SQL to be evaluated */
 int (*callback)(void*,int,char**,char**),  /* Callback function */
 void *,                                    /* 1st argument to callback */
 char **errmsg                              /* Error msg written here */

); </source>

SQL statement

Prepare statement

실행된 SQL의 결과를 바로 리턴하는 것이 아닌, statement 형태의 구조로 가지고 있으면서 결과값을 하나씩 하나씩 row 단위로 사용할 수 있도록 하는 형태.

  • Interface

<source lang=c> typedef struct sqlite3_stmt sqlite3_stmt; </source>

"Prepared statement" 혹은 "Compiled SQL statement" 혹은 그냥 "statement"라고도 불린다. 보통은 다음의 패턴으로 사용된다.

- sqlite3_prepare_v2() 혹은 그와 비슷한 함수로 object를 생성한다.
- sqlite3_bind_*() 함수로 SQL 결과값을 host_parameter 로 바인딩한다.
- sqlite3_step() 함수로 SQL 문을 하나씩 실행시킨다.
- sqlite3_reset() 함수로 statement 를 리셋한다. 
- sqlite3_finalize() 함수로 object를 종료한다.
  • Interface

<source lang=c> int sqlite3_prepare(

 sqlite3 *db,            /* Database handle */
 const char *zSql,       /* SQL statement, UTF-8 encoded */
 int nByte,              /* Maximum length of zSql in bytes. */
 sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
 const char **pzTail     /* OUT: Pointer to unused portion of zSql */

); int sqlite3_prepare_v2(

 sqlite3 *db,            /* Database handle */
 const char *zSql,       /* SQL statement, UTF-8 encoded */
 int nByte,              /* Maximum length of zSql in bytes. */
 sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
 const char **pzTail     /* OUT: Pointer to unused portion of zSql */

); int sqlite3_prepare16(

 sqlite3 *db,            /* Database handle */
 const void *zSql,       /* SQL statement, UTF-16 encoded */
 int nByte,              /* Maximum length of zSql in bytes. */
 sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
 const void **pzTail     /* OUT: Pointer to unused portion of zSql */

); int sqlite3_prepare16_v2(

 sqlite3 *db,            /* Database handle */
 const void *zSql,       /* SQL statement, UTF-16 encoded */
 int nByte,              /* Maximum length of zSql in bytes. */
 sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
 const void **pzTail     /* OUT: Pointer to unused portion of zSql */

); </source> 인자값 "db"는 데이터 베이스 커넥션을 의미한다.

인자값 "zSql"은 실행될 SQL 쿼리를 의미한다.(UTF-8/UTF-16 으로 인코딩된다.) sqlite3_prepare() 와 sqlite3_prepare_v2() 는 UTF-8 를 사용하고, sqlite3_prepare16()과 sqlite3_prepare16_v2()는 UTF-16을 사용한다.

인자값 "nByte"는 SQL 쿼리 최대 길이를 의미한다. 문자열 종료 문자 '\000' 이나, '\u0000'이 올때까지 읽거나, 지정된 바이트 길이까지 읽어들인다. 음수 값으로 지정시, 문자열 종료문자가 올때까지 읽어들인다.

인자값 "pzTail"는 입려된 zSql 에서 nByte 설정으로 인해 실행되지 못한 다음번 문자열의 첫 번째 바이트를 가리키는 역할은 한다.

인자값 "ppStmt"는 prepared statement 가리킨다. 에러 발생시, NULL 로 입력된다.

성공시 SQLITE_OK, 실패시 에러코드를 리턴한다.

sqlite3_step

  • Interface

<source lang=c> int sqlite3_step(sqlite3_stmt*); </source>

Return 값으로 다음의 값들이 올 수 있다.

  • SQLITE_BUSY
현재 데이터베이스에 lock 이 걸려 있음을 뜻한다. 다시 재시도를 하거나 롤백 후, 다시 시도할 수 있다.
  • SQLITE_DONE
해당 쿼리 구문이 성공적으로 수행(종료)되었음을 의미한다. sqlite3_reset() 호출 후, sqlite3_step()를 수행하여야 한다.
  • SQLITE_ROW
수행 결과에 데이터가 있음을 나타낸다. select 구문과 같은 경우를 생각해볼 수 있는데, 이후 column_access 함수들을 사용할 수 있다.
  • SQLITE_ERROR
오류가 발생했음을 나타낸다.
  • SQLITE_MISUSE
잘못된 사용법 오류.

column name

  • Interface

<source lang=c> const char *sqlite3_column_name(sqlite3_stmt*, int N); const void *sqlite3_column_name16(sqlite3_stmt*, int N); </source>

column patch

<source lang=c> const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); int sqlite3_column_bytes(sqlite3_stmt*, int iCol); int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); double sqlite3_column_double(sqlite3_stmt*, int iCol); int sqlite3_column_int(sqlite3_stmt*, int iCol); sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); int sqlite3_column_type(sqlite3_stmt*, int iCol); sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); </source>

String

sqlite3 에서는 문자열, 숫자 등을 입력된 인자값에 맞게 손쉽게 sqlite3 에서 사용되는 query 문으로 변경해주는 함수들이 있다. 아래 함수로 생성된 문자열 메모리는 반드시 sqlite3_free() 함수로 해제해야만 한다.

<source lang=c> SQLITE_API char *sqlite3_mprintf(const char*,...); SQLITE_API char *sqlite3_vmprintf(const char*, va_list); SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);

SQLITE_API void *sqlite3_malloc(int); SQLITE_API void *sqlite3_realloc(void*, int); SQLITE_API void sqlite3_free(void*); </source>

기본적으로 printf() 에서 사용가능한 모든 포멧팅 형식을 지원하며, 추가적으로 "%q", "%Q", "%w", "%z" 옵션을 지원한다.

%q

"%q" 옵션은 "%s" 와 같이 동작한다. 하지만, 입력된 스트링에 작은 따옴표(')가 포함되어 있다면 앞부분에 자동적으로 (\')을 문장에 삽입하게 된다. 입력하고자 하는 스트링을 작은 따옴표(')로 감싸고자 할 때 유용하다.

예를 들어, 다음을 생각해보자. <source lang=c> char *zText = "It's a happy day!";

char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText); sqlite3_exec(db, zSQL, 0, 0, 0); sqlite3_free(zSQL); </source>

위의 예제에서 작성된 SQL 구문은 다음과 같이 된다.

INSERT INTO table1 VALUES('It''s a happy day!')

만약 "%s"를 사용했다면, 다음과 같은 SQL 구문이 작성되었을 것이다. 실행 시, SQL 구문에러를 리턴할 것이다.

INSERT INTO table1 VALUES('It's a happy day!');

%Q

"%Q" 옵션은 "%q"와 같이 입력된 문자열을 작은 따옴표(')로 감싸서 사용하고자 할 때 유용하다. "%q" 옵션과 다른점은, 만약 입력된 파라미터 중에서, NULL 포인터가 있다면, %Q는 자동으로 문자열 "NULL"(큰 따옴표 제외)을 입력한다는 것이다.

<source lang=c> char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText); sqlite3_exec(db, zSQL, 0, 0, 0); sqlite3_free(zSQL); </source> 위의 예제에서, 만약 zText 가 NULL 포인터라고 해도 정상적으로 Query 가 실행되게 된다.

%w

"%w" 옵션은 "%q"과 비슷하지만, 작은 따옴표(')로 둘러싸는 것이 아닌, 큰 따옴표(")로 둘러싸고자 할 때 유용하다. 즉, 입력된 문자열에서 큰 따옴표(") 발견시, 자동으로 (\")을 추가해준다. "%w" 옵션은 테이블 및 콜론 이름을 보다 안전하게 SQL 구문으로 작성하기 위해 고안되었다.

%z

"%z" 옵션은 "%s"과 비슷하지만, 버퍼 스트링 복사 후, 입력 파라미터에 대해 자동으로 sqlite3_free() 메소드를 실행한다는 것이 다르다.

Example

<source lang=c>

  1. include <stdio.h>
  2. include <sqlite3.h>
  3. include <string.h>
  4. include <stdlib.h>

int main(int argc, char **argv) {

   char* sql;
   
   sql = sqlite3_mprintf("INSERT INTO table VALUES('%q')", "'hello'");
   printf("mprintf result. sql[%s]\n", sql);
   sqlite3_free(sql);
   
   printf("Program end.\n");
   return 0;

} </source>

Locking

SQLite3 에서 Locking 은 가장 큰 특징이기도 하면서도 가장 큰 단점이기도 하다. 기본적으로 SQLite 에서의 DB 접근은 한번에 하나의 접근만 허용한다. 만약 높은 수준의 동시성을 지원해야 한다면, 다른 DB 를 찾아보는 것이 좋다.

Data change notification callbacks

sqlite3 는 데이터에 변동이 있을 때 이를 알려주는 콜백을 등록할 수 있는 기능을 제공한다<ref>https://www.sqlite.org/c3ref/update_hook.html</ref>.

<source lang=c> void *sqlite3_update_hook(

 sqlite3*, 
 void(*)(void *,int ,char const *,char const *,sqlite3_int64),
 void*

); </source> The sqlite3_update_hook() interface registers a callback function with the database connection identified by the first argument to be invoked whenever a row is updated, inserted or deleted in a rowid table. Any callback set by a previous call to this function for the same database connection is overridden.

The second argument is a pointer to the function to invoke when a row is updated, inserted or deleted in a rowid table. The first argument to the callback is a copy of the third argument to sqlite3_update_hook(). The second callback argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE depending on the operation that caused the callback to be invoked. The third and fourth arguments to the callback contain pointers to the database and table name containing the affected row. The final callback parameter is the rowid of the row. The final callback parameter is the rowid of the row. In the case of an update, this is the rowid after the update takes place.

The update hook is not invoked when internal system tables are modified(i.e. sqlite_master and sqlite_sequence). The update hook is not invoked when WITHOUT_ROWID tables are modified.

In the current implementation, the update hook is not invoked when duplication rows are deleted because of an ON_CONFLICT_REPLACE clause. Nor is the update hook invoked when rows are deleted using the truncate optimization. The exceptions defined in this paragraph might change in a future release of SQLite.

The update hook implementation must not do anything that will modify the database connection that invoked the update hook. Any actions to modify the database connection must be deferred until the completion of the sqlite3_step() call that triggered the update hook. Note that sqlite3_prepare_v2() and sqlite3_stop() both modify their database connections for the meaning of "modify" in this paragraph.

The sqlite3_update_hook(D, C, P) function returns the P argument from the previous call on the same database connection D, or NULL for the first call on D.

Samples

Connecting to database

데이터 베이스 생성 후 접속하기.

  • Code

<source lang=c>

  1. include <stdio.h>
  2. include <sqlite3.h>

int main(int argc, char* argv[]) {

   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   
   rc = sqlite3_open("test.db", &db);
   
   if(rc)
   {
       fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
       exit(0);
   }
   else
   {
       fprintf(stderr, "Opened database successfully\n");
   }
   sqlite3_close(db);

}

</source>

  • compile

<source lang=bash> $ gcc test.c -l sqlite3 $ ./a.out Opened database successfully </source>

Create a table

데이터 베이스 생성 후, 테이블 생성하기.

  • Code

<source lang=c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <sqlite3.h>

static int callback(void *NotUsed, int argc, char **argv, char **azColName) {

   int i;
   for(i = 0; i < argc; i++)
   {
       printf("%s = %s\n", azColName[i], argv[1] ? argv[i] : "NULL");
   }
   printf("\n");
   
   return 0;

}

int main(int argc, char* argv[]) {

   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;
   
   /* Open database */
   rc = sqlite3_open("test.db", &db);
   if(rc)
   {
       fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
       exit(0);
   }
   else
   {
       fprintf(stdout, "Opened database successfully\n");
   }
   
   /* Create SQL statement */
   sql = "CREATE TABLE COMPANY(" \
       "ID INT PRIMARY KEY     NOT NULL," \
       "NAME           TEXT    NOT NULL," \
       "AGE            INT     NOT NULL," \
       "ADDRESS        CHAR(50)," \
       "SALARY         REAL);";
   
   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
   if(rc != SQLITE_OK)
   {
       fprintf(stderr, "SQL error: %s\n", zErrMsg);
       sqlite3_free(zErrMsg);
   }
   else
   {
       fprintf(stdout, "Table created successfully\n");
   }
   sqlite3_close(db);
   return 0;

} </source>

Insert operation

  • Code

<source lang=c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <sqlite3.h>

static int callback(void *NotUsed, int argc, char **argv, char **azColName) {

   int i;
   for(i = 0; i < argc; i++)
   {
       printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;

}

int main(int argc, char* argv[]) {

   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;
   
   /* Open database */
   rc = sqlite3_open("test.db", &db);
   if(rc)
   {
       fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
       exit(0);
   }
   else
   {
       fprintf(stderr, "Opened database successfully\n");
   }
   
   /* Create SQL statement */
   sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) "  \
       "VALUES (1, 'Paul', 32, 'California', 20000.00 ); " \
       "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) "  \
       "VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); "     \
       "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
       "VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" \
       "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
       "VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );";
   
   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
   if(rc != SQLITE_OK)
   {
       fprintf(stderr, "SQL error: %s\n", zErrMsg);
       sqlite3_free(zErrMsg);
   }
   else
   {
       fprintf(stdout, "Records created successfully\n");
   }
   sqlite3_close(db);
   return 0;

} </source>

  • Result

<source lang=bash> $ ./main Opened database successfully Records created successfully </source>

Select operation

  • Callback prototype

<source lang=c> typedef int (*sqlite3_callback)(

   void*,    /* Data provided in the 4th argument of sqlite3_exec() */
   int,      /* The number of columns in row */
   char**,   /* An array of strings representing fields in the row */
   char**    /* An array of strings representing column names */

); </source>

  • code

<source lang=c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <sqlite3.h>

static int callback(void *data, int argc, char **argv, char **azColName) {

   int i;
   
   fprintf(stderr, "%s: ", (const char*)data);
   
   for(i = 0; i < argc; i++)
   {
       printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;

}

int main(int argc, char* argv[]) {

   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;
   const char* data = "Callback function called";
   
   /* Open database */
   rc = sqlite3_open("test.db", &db);
   if(rc)
   {
       fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
       exit(0);
   }
   else
   {
       fprintf(stderr, "Opened database successfully\n");
   }
   
   /* Create SQL statement */
   sql = "SELECT * from COMPANY";
   
   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
   if(rc != SQLITE_OK)
   {
       fprintf(stderr, "SQL error: %s\n", zErrMsg);
       sqlite3_free(zErrMsg);
   }
   else
   {
       fprintf(stdout, "Operation done successfully\n");
   }
   sqlite3_close(db);
   return 0;

} </source>

  • Result
Opened database successfully
Callback function called: ID = 1
NAME = Paul
AGE = 32
ADDRESS = California
SALARY = 20000.0

Callback function called: ID = 2
NAME = Allen
AGE = 25
ADDRESS = Texas
SALARY = 15000.0

Callback function called: ID = 3
NAME = Teddy
AGE = 23
ADDRESS = Norway
SALARY = 20000.0

Callback function called: ID = 4
NAME = Mark
AGE = 25
ADDRESS = Rich-Mond
SALARY = 65000.0

Operation done successfully

Update operation

  • Code

<source lang=c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <sqlite3.h>

static int callback(void *data, int argc, char **argv, char **azColName) {

   int i;
   fprintf(stderr, "%s: ", (const char*)data);
   for(i = 0; i < argc; i++)
   {
       printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   return 0;

}

int main(int argc, char* argv[]) {

   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;
   const char* data = "Callback function called";
   
   /* Open database */
   rc = sqlite3_open("test.db", &db);
   if(rc)
   {
       fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
       exit(0);
   }
   else
   {
       fprintf(stderr, "Opened database successfully\n");
   }
   
   /* Create merged SQL statement */
   sql = "UPDATE COMPANY set SALARY = 25000.00 where ID=1; " \
       "SELECT * from COMPANY";
   
   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
   if(rc != SQLITE_OK)
   {
       fprintf(stderr, "SQL error: %s\n", zErrMsg);
       sqlite3_free(zErrMsg);
   }
   else
   {
       fprintf(stdout, "Operation done successfully\n");
   }
   sqlite3_close(db);
   return 0;

} </source>

  • Result

<source lang=bash> Opened database successfully Callback function called: ID = 1 NAME = Paul AGE = 32 ADDRESS = California SALARY = 25000.0

Callback function called: ID = 2 NAME = Allen AGE = 25 ADDRESS = Texas SALARY = 15000.0

Callback function called: ID = 3 NAME = Teddy AGE = 23 ADDRESS = Norway SALARY = 20000.0

Callback function called: ID = 4 NAME = Mark AGE = 25 ADDRESS = Rich-Mond SALARY = 65000.0

Operation done successfully </source>

Delete operation

  • Code

<source lang=c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <sqlite3.h>

static int callback(void *data, int argc, char **argv, char **azColName) {

   int i;
   fprintf(stderr, "%s: ", (const char*)data);
   
   for(i = 0; i < argc; i++)
   {
       printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
   }
   printf("\n");
   
   return 0;

}

int main(int argc, char* argv[]) {

   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;
   const char* data = "Callback function called";
   
   /* Open database */
   rc = sqlite3_open("test.db", &db);
   if(rc)
   {
       fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
       exit(0);
   }
   else
   {
       fprintf(stderr, "Opened database successfully\n");
   }
   
   /* Create merged SQL statement */
   sql = "DELETE from COMPANY where ID = 2; " \
       "SELECT * from COMPANY";
   
   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
   if(rc != SQLITE_OK)
   {
       fprintf(stderr, "SQL error: %s\n", zErrMsg);
       sqlite3_free(zErrMsg);
   }
   else
   {
       fprintf(stdout, "Operation done successfully\n");
   }
   sqlite3_close(db);
   return 0;

} </source>

  • Result

<source lang=bash> Opened database successfully Callback function called: ID = 1 NAME = Paul AGE = 32 ADDRESS = California SALARY = 25000.0

Callback function called: ID = 3 NAME = Teddy AGE = 23 ADDRESS = Norway SALARY = 20000.0

Callback function called: ID = 4 NAME = Mark AGE = 25 ADDRESS = Rich-Mond SALARY = 65000.0

Operation done successfully </source>

External links

  • http://www.tutorialspoint.com/sqlite/sqlite_c_cpp.htm

References

<references />