LV07-06-SQLite-C语言API

本文主要是SQLite数据库的C语言接口相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
参考方向 参考原文
SQLite官网SQLite Home Page
SQLite中文网SQLite 中文网
SQLite 基础教程SQLite参考手册 - 在线原生手册
菜鸟教程SQLite 教程
易百教程SQLite 教程
点击查看相关文件下载
--- ---

这一部分就主要是C语言的API函数介绍了,这些函数在SQLite官网首页上都有:List Of SQLite Functions (或者功能列表:_SQlite中文网 ),需要注意的是,一定要提前装好sqlite3和相关库,这样编译链接程序的时候才不会报错。

1
2
sudo apt install sqlite3            # 安装sqlite3
sudo apt-get install libsqlite3-dev # 安装函数库

编译链接程序的时候要记得加上-lsqlite3

一、sqlite3_open()函数

1. 函数说明

我们可以在这里看到函数原型:Opening A New Database Connection (sqlite.org) (或者打开一个新的数据库连接_SQlite中文网 )。

1
2
3
4
5
6
7
8
/* 需包含的头文件 */
#include <sqlite3.h>

/* 函数声明 */
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);

【函数说明】该函数用于打开一个 SQLite 数据库文件。

【函数参数】

  • filenamechar类型指针变量,指向要打开的数据库文件。
  • ppDbsqlite3类型二级指针变量,表示数据库句柄,一般我们会定义一个一级指针变量sqlite3 *db,所以这里在进行传参的时候要传入一个地址,所以就需要传入&db

【返回值】int类型,如果成功打开(或创建)数据库,则返回SQLITE_OK,失败返回出错码。

【使用格式】一般情况下基本使用格式如下:

1
2
3
4
5
6
7
8
9
10
/* 需要包含的头文件 */
#include <sqlite3.h>

/* 至少应该有的语句 */
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
if(sqlite3_open("database_name.db", &db) != SQLITE_OK)
{
printf("Open error!\n",);
return -1;
}

【注意事项】

(1)如果 filename参数是 NULL:memory:,那么 sqlite3_open() 将会在 RAM中创建一个内存数据库,这只会在会话session 的有效时间内持续。

(2)如果文件名 filename 不为 NULL,那么 sqlite3_open() 将使用这个参数值尝试打开数据库文件。如果该名称的文件不存在,sqlite3_open() 将创建一个新的命名为该名称的数据库文件并打开。

2. 使用实例

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <sqlite3.h>

#define DATABASE "user.db" /* 数据库名称 */

int main(int argc, char *argv[])
{
sqlite3 * db; /* 数据库指针,代表数据库操作句柄 */
/* 1.打开数据库 */
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("Open [%s] error!\n", DATABASE);
return -1;
}
else
{
printf("Open [%s] success!\n", DATABASE);
}
return 0;
}

在终端执行以下命令编译程序:

1
2
gcc test.c -Wall -lsqlite3 # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

1
Open [user.db] success!

二、sqlite3_close()函数

1. 函数说明

我们可以在这里看到函数原型:Closing A Database Connection (sqlite.org) (或者关闭数据库连接_SQlite中文网 )。

1
2
3
4
5
/* 需包含的头文件 */
#include <sqlite3.h>

/* 函数声明 */
int sqlite3_close(sqlite3 *);

【函数说明】该函数用于关闭一个打开的 SQLite 数据库文件。

【函数参数】

  • arg1sqlite3类型指针变量,指向要关闭的数据库文件,函数声明只需要数据类型即可,所以这里没有写形参名,注意这里是一个一级指针。

【返回值】int类型,如果成功关闭数据库,则返回SQLITE_OK,如果还有操作没有完成,将返回 SQLITE_BUSY 禁止关闭的错误消息。

【使用格式】一般情况下基本使用格式如下:

1
2
3
4
5
6
/* 需要包含的头文件 */
#include <sqlite3.h>

/* 至少应该有的语句 */
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
sqlite3_close(db);

【注意事项】none

2. 使用实例

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <sqlite3.h>

#define DATABASE "user.db" /* 数据库名称 */

int main(int argc, char *argv[])
{
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
/* 1.打开数据库 */
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("Open [%s] error!\n", DATABASE);
return -1;
}
else
{
printf("Open [%s] success!\n", DATABASE);
}
if(sqlite3_close(db) != SQLITE_OK)
{
printf("Close [%s] error!\n", DATABASE);
return -1;
}
else
{
printf("Close [%s] success!\n", DATABASE);
}
return 0;
}

在终端执行以下命令编译程序:

1
2
gcc test.c -Wall -lsqlite3 # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

1
2
Open [user.db] success!
Close [user.db] success!

三、sqlite3_errmsg()函数

1. 函数说明

我们可以在这里看到函数原型:Error Codes And Messages (sqlite.org) (或者错误代码和消息_SQlite中文网 )。

1
2
3
4
5
/* 需包含的头文件 */
#include <sqlite3.h>

/* 函数声明 */
const char * sqlite3_errmsg(sqlite3 *);

【函数说明】该函数用于得到错误信息的描述。

【函数参数】

  • arg1sqlite3类型指针变量,指向要获取错误信息的数据库句柄,函数声明只需要数据类型即可,所以这里没有写形参名,注意这里是一个一级指针。

【返回值】char类型指针变量,返回一个指向描述错误信息的字符串的指针变量。

【使用格式】一般情况下基本使用格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 需要包含的头文件 */
#include <sqlite3.h>

/* 至少应该有的语句 */
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("Open error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Open success:[%s]!\n", sqlite3_errmsg(db));
}

【注意事项】none

2. 使用实例

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <sqlite3.h>

#define DATABASE "user.db" /* 数据库名称 */

int main(int argc, char *argv[])
{
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
/* 1.打开数据库 */
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("Open error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Open success:[%s]!\n", sqlite3_errmsg(db));
}
if(sqlite3_close(db) != SQLITE_OK)
{
printf("Close error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Close success:[%s]!\n", sqlite3_errmsg(db));
}
return 0;
}

在终端执行以下命令编译程序:

1
2
gcc test.c -Wall -lsqlite3 # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

1
2
Open success:[not an error]!
Close success:[library routine called out of sequence]!

四、sqlite3_exec()函数

1. 函数说明

我们可以在这里看到函数原型:One-Step Query Execution Interface (sqlite.org) (或者一站式查询执行界面_SQlite中文网 )。

1
2
3
4
5
6
7
8
9
10
11
/* 需包含的头文件 */
#include <sqlite3.h>

/* 函数声明 */
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 */
);

【函数说明】该函数用于执行一条执SQLite语句。

【函数参数】

  • arg1sqlite3类型指针变量,指向一个已经打开的数据库,其实就是要操作数据库的句柄,函数声明只需要数据类型即可,所以这里没有写形参名,注意这里是一个一级指针。
  • sqlchar类型指针变量,要执行的SQLite语句(是一个指向SQLite语句字符串首地址的指针变量)。
  • callbackint (*)(void*,int,char**,char**)类型的一个函数指针,指向一个回调函数,一般只有在查询时(也就是执行SELECT语句)才用得上,若设置为NULL,则不会调用任何回调函数,并且将忽略结果行。
点击查看数据类型分析

(1)callback前边有一个*并且由()括起来,说明这首先是一个指针变量;

(2)后边的()表示这个指针变量指向一个函数,这个函数带有四个形参;

(3)前边的int表示函数返回值为int类型。

总的来说,指针变量callback可以指向一个带有void*,int,char**,char**等四个类型形参且返回值为int类型的函数。

  • arg4void类型指针变量,一般要进行强制类型转换,用于为回调函数传递参数;
  • errmsgchar类型的二级指针变量,指向错误消息。

【返回值】int类型,如果成功执行语句,则返回SQLITE_OK,失败返回出错码。

【使用格式】一般情况下基本使用格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 需要包含的头文件 */
#include <sqlite3.h>

/* 至少应该有的语句 */
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
char *errmsg; /* 存放错误信息 */
if(sqlite3_exec(db, "create table if not exists fruit(id int, name char , price REAL);",
NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("Create or open table error:%s\n", errmsg);
}
else
{
printf("Create or open table success!\n");
}

【注意事项】none

2. 回调函数

这里再来详细说明一下回调函数,前边我们学习函数指针的时候有说过,通过typedef定义一个函数指针的类型的话,可以简化书写方式,于是这个函数就可以写成这个样子:

1
2
3
4
5
6
7
typedef int(*sqlite3_callback)(void *, int, char **, char **);
int sqlite3_exec(
sqlite3 *db,
const char *sql,
sqlite3_callback callback,
void *, char **errmsg
);

但是这个函数是存在于库中的,我们是无法修改的,所以我们其实不用管这个,需要使用到回调函数的时候,直接传入一个函数名就可以了,回调函数可以定义成下边的形式:

1
int callBack(void *arg, int f_num, char ** f_value, char ** f_name)

【参数说明】

  • parasqlite3_exec传递给回调函数的参数,传入的其实是sqlite3_exec函数的第四个void *的那个参数。
  • f_num:记录中包含的字段数目。
  • f_value:包含每个字段值的指针数组。
  • f_name:包含每个字段名称的指针数组。

【返回值】int类型,成功返回0(这个其实可以自己定义,一般这个返回值我们并不进行判断)。

【注意事项】

(1)只有在查询语句中,回调函数才会被调用。

(2)有多少条符合条件的查询记录,就会调用多少次回调函数。

3. 使用实例

3.1 不使用回调函数

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>

#define DATABASE "user.db" /* 数据库名称 */

int main(int argc, char *argv[])
{
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
char *errmsg; /* 存放错误信息 */
char sql[128];/* 用于暂存SQLite语句 */
int i = 0;
char temp[6][128] = {
"create table if not exists fruit(id int, name char , price REAL);",
"insert into fruit(id,name,price) values(1,'apple',5);",
"insert into fruit(id,name,price) values(2,'banana',3);",
"insert into fruit(id,name,price) values(3,'pears',3.5);",
"insert into fruit(id,name,price) values(4,'orange',2.5);",
"insert into fruit(id,name,price) values(5,'grape',8);"
};
/* 1.打开数据库 */
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("Open error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Open success:[%s]!\n", sqlite3_errmsg(db));
}
/* 2.创建数据表并输入数据 */
for(i = 0; i < 6; i++)
{
bzero(sql, sizeof(sql)/sizeof(char));
printf("%s\n", temp[i]);
strcpy(sql, temp[i]);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
printf("sqlite3_exec error:%s\n", errmsg);
else
printf("sqlite3_exec success!\n");
}
/* 3.关闭数据库 */
if(sqlite3_close(db) != SQLITE_OK)
{
printf("Close error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Close success:[%s]!\n", sqlite3_errmsg(db));
}

return 0;
}

在终端执行以下命令编译程序:

1
2
gcc test.c -Wall -lsqlite3 # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Open success:[not an error]!
create table if not exists fruit(id int, name char , price REAL);
sqlite3_exec success!
insert into fruit(id,name,price) values(1,'apple',5);
sqlite3_exec success!
insert into fruit(id,name,price) values(2,'banana',3);
sqlite3_exec success!
insert into fruit(id,name,price) values(3,'pears',3.5);
sqlite3_exec success!
insert into fruit(id,name,price) values(4,'orange',2.5);
sqlite3_exec success!
insert into fruit(id,name,price) values(5,'grape',8);
sqlite3_exec success!
Close success:[library routine called out of sequence]!

这说明所有语句都正常执行了,接下来我们打开SQLite来看一下里边的数据:

  • 打开数据库
1
sqlite3 user.db
  • 设置输出格式
1
2
sqlite> .head on
sqlite> .mode column
  • 查询数据
1
2
3
4
5
6
7
8
sqlite> select * from fruit;
id name price
---------- ---------- ----------
1 apple 5.0
2 banana 3.0
3 pears 3.5
4 orange 2.5
5 grape 8.0

可以看到数据都已经写入到数据库中了。

3.2 使用回调函数

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>

#define DATABASE "user.db" /* 数据库名称 */

int callBack(void *arg, int f_num, char ** f_value, char ** f_name)
{
int i = 0;

for(i = 0; i < f_num; i++)
{
if(i > f_num - 3)
printf("%s:%-19s", f_name[i], f_value[i]);
else
printf("%s:%-8s", f_name[i], f_value[i]);
}
puts(""); /* 换行 */

return 0;
}

int main(int argc, char *argv[])
{
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
char *errmsg; /* 存放错误信息 */
char sql[128];/* 用于暂存SQLite语句 */
int i = 0;
char temp[7][128] = {
"create table if not exists fruit(id int, name char , price REAL);",
"insert into fruit(id,name,price) values(1,'apple',5);",
"insert into fruit(id,name,price) values(2,'banana',3);",
"insert into fruit(id,name,price) values(3,'pears',3.5);",
"insert into fruit(id,name,price) values(4,'orange',2.5);",
"insert into fruit(id,name,price) values(5,'grape',8);"
"select * from fruit;"
};
/* 1.打开数据库 */
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("Open error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Open success:[%s]!\n", sqlite3_errmsg(db));
}
/* 2.创建数据表并输入数据 */
for(i = 0; i < 7; i++)
{
bzero(sql, sizeof(sql)/sizeof(char));
printf("%s\n", temp[i]);
strcpy(sql, temp[i]);
if(sqlite3_exec(db, sql, callBack, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s\n", errmsg);
return -1;
}

}

/* 3.关闭数据库 */
if(sqlite3_close(db) != SQLITE_OK)
{
printf("Close error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Close success:[%s]!\n", sqlite3_errmsg(db));
}

return 0;
}

在终端执行以下命令编译程序:

1
2
gcc test.c -Wall -lsqlite3 # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Open success:[not an error]!
create table if not exists fruit(id int, name char , price REAL);
insert into fruit(id,name,price) values(1,'apple',5);
insert into fruit(id,name,price) values(2,'banana',3);
insert into fruit(id,name,price) values(3,'pears',3.5);
insert into fruit(id,name,price) values(4,'orange',2.5);
insert into fruit(id,name,price) values(5,'grape',8);select * from fruit;
id:1 name:apple price:5.0
id:2 name:banana price:3.0
id:3 name:pears price:3.5
id:4 name:orange price:2.5
id:5 name:grape price:8.0

Close success:[library routine called out of sequence]!

这说明所有语句都正常执行了,接下来我们打开SQLite来看一下里边的数据:

  • 打开数据库
1
sqlite3 user.db
  • 设置输出格式
1
2
sqlite> .head on
sqlite> .mode column
  • 查询数据
1
2
3
4
5
6
7
8
sqlite> select * from fruit;
id name price
---------- ---------- ----------
1 apple 5.0
2 banana 3.0
3 pears 3.5
4 orange 2.5
5 grape 8.0

可以看到数据都已经写入到数据库中了。

五、sqlite3_get_table()函数

1. 函数说明

我们可以在这里看到函数原型:Convenience Routines For Running Queries (sqlite.org) (或者方便的运行查询例程_SQlite中文网 )。

1
2
3
4
5
6
7
8
9
10
11
12
/* 需包含的头文件 */
#include <sqlite3.h>

/* 函数声明 */
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 */
);

【函数说明】该函数用于可以不使用回调函数就执行SQLite语句,一般用于执行SELECT查询语句。这是一个旧接口,保留该接口是为了向后兼容,不建议使用此接口。

【函数参数】

  • dbsqlite3类型指针变量,指向已打开的数据库句柄。
  • zSqlchar类型指针变量,指向要执行的SQLite语句首地址。
  • pazResultchar类型三级指针变量,用来指向sql语句执行结果的指针。
  • pnRowint类型指针变量,表示满足条件的记录的数目。
  • pnColumnint类型指针变量,每条记录包含的字段数目。
  • pzErrmsgchar类型二级指针变量,指向错误信息指针的地址。

【返回值】int类型,成功返回SQLITE_OK,失败返回错误码。

【使用格式】一般情况下基本使用格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 需要包含的头文件 */
#include <sqlite3.h>

/* 至少应该有的语句 */
char *errmsg;
char ** resultp;
int nrow;
int ncolumn;
if(sqlite3_get_table(db, "select * from tab_name", &resultp, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
{
printf("%s\n", errmsg);
return -1;
}

【注意事项】none

2. 使用实例

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>

#define DATABASE "user.db" /* 数据库名称 */

int main(int argc, char *argv[])
{
sqlite3 *db; /* 数据库指针,代表数据库操作句柄 */
char *errmsg; /* 存放错误信息 */
char sql[128];/* 用于暂存SQLite语句 */
int i = 0;
char temp[6][128] = {
"create table if not exists fruit(id int, name char , price REAL);",
"insert into fruit(id,name,price) values(1,'apple',5);",
"insert into fruit(id,name,price) values(2,'banana',3);",
"insert into fruit(id,name,price) values(3,'pears',3.5);",
"insert into fruit(id,name,price) values(4,'orange',2.5);",
"insert into fruit(id,name,price) values(5,'grape',8);"
};
/* 1.打开数据库 */
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("Open error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Open success:[%s]!\n", sqlite3_errmsg(db));
}
/* 2.创建数据表并输入数据 */
for(i = 0; i < 6; i++)
{
bzero(sql, sizeof(sql)/sizeof(char));
printf("%s\n", temp[i]);
strcpy(sql, temp[i]);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s\n", errmsg);
return -1;
}

}
/* 3.打印所有数据 */
char ** resultp;
int nrow;
int ncolumn;

if(sqlite3_get_table(db, "select * from fruit", &resultp, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
{
printf("%s\n", errmsg);
return -1;
}
else
{
printf("nrow = %d, ncolumn=%d\n", nrow, ncolumn);
}

int j = 0;
int index = ncolumn;
for(j = 0; j < ncolumn; j++)
{
printf("%-10s ", resultp[j]);
}
puts("");

for(i = 0; i < nrow; i++)
{
for(j = 0; j < ncolumn; j++)
{
printf("%-10s ", resultp[index++]);
}
puts("");
}
/* 4.关闭数据库 */
if(sqlite3_close(db) != SQLITE_OK)
{
printf("Close error:[%s]!\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("Close success:[%s]!\n", sqlite3_errmsg(db));
}

return 0;
}

在终端执行以下命令编译程序:

1
2
gcc test.c -Wall -lsqlite3 # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Open success:[not an error]!
create table if not exists fruit(id int, name char , price REAL);
insert into fruit(id,name,price) values(1,'apple',5);
insert into fruit(id,name,price) values(2,'banana',3);
insert into fruit(id,name,price) values(3,'pears',3.5);
insert into fruit(id,name,price) values(4,'orange',2.5);
insert into fruit(id,name,price) values(5,'grape',8);
nrow = 5, ncolumn=3
id name price
1 apple 5.0
2 banana 3.0
3 pears 3.5
4 orange 2.5
5 grape 8.0
Close success:[library routine called out of sequence]!