将 SQLite 移植到 BREW






4.29/5 (4投票s)
- 将SQLite 3.2.8版本作为BREW 3.1.2版本的扩展提供
版权所有 © 2010 Tata Consultancy Services Ltd. 保留所有权利
需求和介绍
典型的手机应用程序基于请求-响应模式。每当应用程序需要数据时,它会向服务器发送一个Web请求。服务器在服务器上保存的数据库中处理请求,并将响应发送给应用程序。然而,这种方法往往与无线网络带宽应得到最佳利用的基本要求相悖。“断开连接的数据库模型”方法提供了一个解决方案来克服这个问题。在这种方法中,数据库和数据库引擎都位于手机本身上,每当应用程序需要数据时,它不是向服务器发送Web请求,而是向驻留在手机上的数据库发送数据库查询。这减少了对服务器的Web调用次数,并通过缩短响应时间来提高性能。这种方法的缺点是手机上可能存在过时的数据。但如果数据不经常更改,这是可以接受的。手机上的数据库可以定期与服务器上的数据库同步,以消除这种缺点。参见图1和图2。
Sun Microsystems 为 j2me 应用程序倡导了这种方法。它在 BREW 和 Android 等其他移动平台上也很受欢迎。然而,这种解决方案的传统方法,即 JAVA2 ME SDK 提供的 RMS 存储或 BREW IDatabase,未能充分满足实际需求。这种信念促使嵌入式数据库系统被移植到移动平台,例如,Qualcomm 已将 SQLite 移植为 BREW 新版本上的一个名为 ISQL 的扩展。此扩展仅适用于 BREW SDK v3.1.4 及以上版本。我们无法将其用于开发适用于 SDK 3.1.2 版本的手机应用程序。因此,我们决定为 SDK 3.1.2 版本移植 SQLite。
作为第一步,我们从较低版本的SQLite开始,将SQLite 2.2.0版本移植到BREW 3.1.2版本。我们在此次实践中的经验和学习在[2]中有所描述。
目前SQLite已经发展到3.x版本,它比旧的2.x版本提供了更多的功能。因此,我们决定通过在BREW上移植3.x版本中的某个版本来升级我们自己。由于我们的需求很简单,我们只是希望能够在手机上成功执行select
、update
、delete
和insert
命令,所以我们选择了3.2.8版本。我们没有将SQLite源代码与我们的应用程序集成,而是决定将这个版本的SQLite作为BREW扩展。本文描述了从SQLite源代码创建此扩展所涉及的步骤。
SQLite是世界上部署最广泛的SQL数据库引擎。SQLite的源代码是公共领域的。点击此处了解更多关于SQLite的信息。
要求
- BREW SDK 3.1.2(或更高版本)
- RVDS 3.0
- Elf2mod 工具:https://brewx.qualcomm.com/brew/sdk/authdownload.jsp?page=dx/elf2mod
- Visual Studio 2005(或更高版本)
- SQLite 3.2.8 版本源代码:http://www.sqlite.org/src/zip/SQLite-e61382aed45a83ad.zip?uuid=e61382aed45a83ad688a0461948f9cd052a527fa
创建SQLite扩展的步骤
先决条件
- 安装BREW SDK 3.1.2(或更高版本)和RVDS 3.0
- 下载elf2mod工具
- 下载SQLite 3.2.8版本源代码
步骤 1:生成源代码文件
版本3.2.8的源代码文件位于名为SQLite-e61382aed45a83ad的文件夹中。此后,我们将把此文件夹称为根目录。并非所有源文件都直接在root\src文件夹中。我们需要使用根目录中提供的其他文件来创建一些文件。请参阅此链接以了解实现方式:http://www.sqlite.org/cvstrac/wiki?p=SqliteBuildProcess。
我们需要使用以下 Unix 命令生成文件 parse.h、parse.c、keywordhash.h、opcodes.h、opcodes.c、sqlite3.h。
gcc -o lemon lemon.c
(此命令编译root\tool文件夹中的lemon.c文件并生成可执行文件lemon)./lemon parse.y
(此命令使用可执行文件lemon从parse.y生成parse.c和parse.h文件)gcc -o mkkeywordhash mkkeywordhash.c
(此命令编译位于root\tool文件夹中的mkkeywordhash.c文件)./mkkeywordhash>keywordhash.h
(此命令生成keywordhash.h文件)cat parse.h vdbe.c | awk -f mkcodeh.awk>opcodes.h
(此命令使用文件mkcodeh.awk、parse.h、vdbe.c生成opcodes.h)cat opcodes.h | awk -f mkcodec.awk>opcodes.c
(此命令使用文件mkcodec.awk、opcodes.h生成文件opcodes.c)
使用sed命令,利用root/src中提供的文件sqlite.h.in和根目录中提供的文件VERSION生成文件sqlite3.h。
将所有生成的.h和.c文件放入root\src文件夹。
步骤2:设置Visual Studio工作区和链接
创建一个新的 BREW 工作区,并从 root/src 文件夹中包含以下文件
- analyze.c
- attach.c
- auth.c
- btree.c
- btree.h
- build.c
- callback.c
- complete.c
- delete.c
- expr.c
- func.c
- hash.c
- hash.h
- insert.c
- keywordhash.h
- legacy.c
- main.c
- opcodes.c
- opcodes.h
- os_common.h
- os.h
- os.c
- pager.c
- pager.h
- parse.c
- parse.h
- prepare.c
- printf.c
- random.c
- select.c
- sqlite3.h
- sqliteInt.h
- table.c
- tokenize.c
- update.c
- utf.c
- util.c
- vacuum.c
- vdbe.h
- vdbeapi.c
- vdbeapi.h
- vdbeaux.c
- vdbefifo.c
- vdbeInt.h
- vdbemem.c
- where.c
在项目属性中指定所有必需的路径,以消除所有链接错误。
步骤3:文件修改
在源代码中,#include
文件Locale.h,并在应用程序源代码的开头添加以下行
setlocale(LC_ALL,"")
SQLite源代码大量使用了各种C库函数。如果我们在程序执行开始时没有调用setlocale()
函数,对某些C库函数的调用可能会导致应用程序在手机上崩溃。
修改以下文件
- 文件:root\src\os.h和root\src\os.c
在os.h和os.c中定义的函数具有操作系统特定的实现。我们需要提供这些函数的BREW特定实现。为此,我们可以重新定义结构
OsFile
。我们还需要添加BREW API的AEEFile.h。我们可能需要定义一些宏。所有这些都包含在以下代码片段中。将以下定义粘贴到os.h文件的开头。
#define OS_BREW312 1 #include "AEEFile.h" struct OsFile { IFileMgr *m_pIFileMgr; //!< pointer to IFileMgr. IFile *m_pIFile; //!< Pointer to IFile. }; typedef struct OsFile OsFile; # define SQLITE_TEMPNAME_SIZE 100//(MAX_PATH+50)
宏
OS_BREW312
在为os.c文件中的函数提供BREW特定实现时使用。在os.c文件的开头添加该行。
#include "AEEStdlib.h"
为该文件中定义的函数提供BREW特定实现。有关详细信息,请参见(iSQLite.zip)中提供的os.h和os.c文件。
- 文件:root\src\util.c和root\src\table
从util.c和table.c调用了
malloc()
、realloc()
和free()
等函数。将对malloc()
、realloc()
、free()
的调用分别替换为MALLOC()
、REALLOC()
和FREE()
。这些函数是BREW API提供的malloc()
、realloc()
和free()
的BREW特定实现。 - 文件:root\src\sqlite3.h
在文件开头添加以下行
#include "AEEStdlib.h"
我们可能不需要所有提供的功能。我们可以
#define
一些宏来禁用这些功能。我们定义了以下宏,以避免包含我们不需要的功能。
#define SQLITE_OMIT_AUTHORIZATION 1 #define SQLITE_OMIT_UTF16 1 #define SQLITE_OMIT_ALTERTABLE 1 #define SQLITE_OMIT_TRIGGER 1 #define SQLITE_OMIT_VIEW 1 #define SQLITE_OMIT_FOREIGN_KEY 1 #define SQLITE_OMIT_AUTOVACUUM 1 #define SQLITE_OMIT_AUTOINCREMENT 1 #define OMIT_DATE_RELATED_FUNCTIONS 1 #define SQLITE_OMIT_TRACE 1 #define SQLITE_OMIT_ANALYZE 1 #define SQLITE_OMIT_PRAGMA 1 #define SQLITE_OMIT_TCL_VARIABLE 1 #define SQLITE_OMIT_EXPLAIN 1 #define SQLITE_OMIT_PAGER_PRAGMAS 1 #define SQLITE_OMIT_INTEGRITY_CHECK 1 #define SQLITE_OMIT_GLOBALRECOVER 1 #define SQLITE_OMIT_TEMPDB 1 #define SQLITE_OMIT_REINDEX 1 #define SQLITE_OMIT_CAST 1 #define SQLITE_OMIT_SUBQUERY 1 #define SQLITE_OMIT_BLOB_LITERAL 1 #define SQLITE_OMIT_PROGRESS_CALLBACK 1 #define SQLITE_OMIT_MEMORYDB 1 #define SQLITE_OMIT_VACUUM 1 #define SQLITE_OMIT_COMPOUND_SELECT 1
- 文件:root\src\parse.c
在某些文件(如parse.c、update.c、insert.c、vdbe.c)中,调用了一些用于处理触发器、修改表、索引等功能相关的函数。如上所述,我们的应用程序不需要所有这些功能。我们利用SQLite3.h中定义的宏,通过条件编译将相应的代码段注释掉。
例如,以下代码片段展示了在parse.c文件中使用条件编译。
#ifndef SQLITE_OMIT_TRIGGER case 236: case 241: #line 969 "parse.y" {sqlite3DeleteTriggerStep((yypminor->yy360));} #line 1387 "parse.c" break; #endif #ifndef SQLITE_OMIT_VIEW case 99: #line 354 "parse.y" { sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy198, \ &yymsp[-2].minor.yy198, yymsp[0].minor.yy375, yymsp[-5].minor.yy280); } #line 2280 "parse.c" break; #endif #ifndef SQLITE_OMIT_AUTOVACUUM case 253: case 254: #line 906 "parse.y" {sqlite3Vacuum(pParse,0);} #line 2977 "parse.c" break; #endif
有关详细信息,请参阅(iSQLite.zip)中的相应文件。
- 文件:root\src\random.c
此文件中定义的函数
sqliteRandomByte()
。此定义可在SQLite 2.2.0版本的源代码中找到。此函数正从os.c文件中调用。int sqliteRandomByte(){ int r; sqlite3OsEnterMutex(); r = randomByte(); sqlite3OsLeaveMutex(); return r; }
- 文件:root\src\prepare.c
替换了一个
if
语句if( meta[1]>3 ){
用
if( meta[1]>4 ){
步骤4:添加isqlite.c和isqlite.h文件
在工作区中包含文件isqlite.h和isqlite.c。名为ISQLiteClass
的SQLite 3.2.8版本接口在isqlite.h中定义。此接口的函数在isqlite.c中定义。有关详细信息,请参见(iSQLite.zip)中的文件。
步骤5:在RVDS中编译和链接
要为扩展生成BREW可执行(.mod)文件,请将所有源文件包含到工作区中。不要在工作区中添加AEEAppgen.c和AEEModGen.c文件,而是添加iSQLite.zip中提供的名为AppgenModGen.a的文件。此文件是AEEAppgen.c和AEEModGen.c文件的预编译库。
使用如下屏幕截图所示的设置
访问路径:在项目的“访问路径”选项卡中指定所有必需的路径,以消除所有链接错误。
最后一步:生成.mod文件
使用elf2mod
工具将elf转换为BREW可执行(.mod)文件,如下所示
elf2mod isqlite.elf
这将在同一文件夹中创建isqlite.mod文件。此文件是BREW扩展的mod文件。使用BREW Apploader将isqlite.mod添加到手机中。
如何在应用程序中使用此扩展
如果应用程序想要使用此接口的函数,则应在其源代码中包含以下文件。
- isqlite.h - 此文件包含
ISQLite
接口函数的声明。 - isqlite.bid - 此文件包含此扩展的类ID。在通过
ISHELL_CreateInstance
创建ISQLiteClass
实例时需要此类ID。
以下文件需要包含在应用程序的工作文件夹中。 - isqlite.h
- isqlite.bid
- sqlite3.h
应用程序必须在其MIF的依赖项部分添加扩展的类ID(在isqlite.bid中定义)。
以下示例代码演示了ISQLite
接口的使用。
//sample program
ISQLiteClass *pISQLiteClass = NULL;
AEEApplet *pApplet = (AEEApplet *)GETAPPINSTANCE();
sqlite3 *psqlite3 = NULL;
//create an instance of ISQLiteClass interface
if(SUCCESS!= ISHELL_CreateInstance(pApplet->m_pIShell,
AEECLSID_ISQLITE,(void **)&pISQLiteClass))
{
DBGPRINTF("failed to create ISQLiteClass instance");
}
else
{
char *pszSQLQueryInsert = "create table SAMPLE
(C1 varchar(10), C2 varchar(10), C3 varchar(10),\
C4 varchar(10), C5 varchar(10), C6 varchar(10));
INSERT INTO SAMPLE \
(C1, C2, C3, C4) values ('123','Govind', 'Afade', '25');
INSERT INTO \
SAMPLE (C1, C2, C3, C4) values
('123','Govind', 'Adle', '26');";
char *pszSQLQuerySelect = "SELECT * from SAMPLE";
//Open a database file database.db
if(SQLITE_OK!= ISQLiteClass_sqlite3_open
(a_pApplet->m_pISQLiteClass, "database.db", &psqlite3))
{
DBGPRINTF("db file could not open");
}
else
{
char **ppszResult = NULL;
int nRow = -1;
int nCol = -1;
char *pszErrorString = NULL;
int nReturnValue = -1;
//execute SQL to create table and insert 2 records
nReturnValue = ISQLiteClass_sqlite3_get_table
(a_pApplet->m_pISQLiteClass,psqlite3,\
pszSQLQueryInsert,&ppszResult,&nRow,&nCol,&pszErrorString);
ISQLiteClass_sqlite3_free_table(a_pApplet->m_pISQLiteClass, ppszResult);
//execute SQL select query
nReturnValue = ISQLiteClass_sqlite3_get_table
(a_pApplet->m_pISQLiteClass,\
psqlite3,pszSQLQuerySelect,&ppszResult,
&nRow,&nCol,&pszErrorString);
ISQLiteClass_sqlite3_free_table(a_pApplet->m_pISQLiteClass, ppszResult);
}
//Release instance of SQLite class
ISQLiteClass_Release(pISQLiteClass);
}
参考文献
[1] SQLite 主页 ( http://www.sqlite.org/)
[2] “移动数据库——将 SQLite 移植到 BREW”,Kushal Gore、Priyanka Kabra、Sanjay Kimbahune、Pankaj Doke(一篇发表于2010年3月5日至6日在孟买 Vile Parle 的 JVPD Scheme 的 SVKM's NMIMS(被视为大学)举办的 ICTM -2010“ICT 和技术管理创新”全国亚太区域会议的论文。网址:http://www.ncict-mumbai.org/index.html)
[3] RVDS 3.0 文档 ( http://infocenter.arm.com/help/index.jsp)
作者
库沙尔·戈尔
Kushal Gore 拥有印度理工学院古瓦哈提分校的数学与计算理学硕士学位。他是 Tata Consultancy Services Limited 孟买创新实验室的研究团队成员。他的研究兴趣是移动计算。
联系方式:kushal.gore@tcs.com
潘卡吉·多克
Pankaj Doke 拥有孟买大学的计算机工程学士学位。他是 Tata Consultancy Services Limited 孟买创新实验室的研究团队负责人。他的研究兴趣是移动计算、计算机安全、模式识别、机器学习和大规模系统。
联系方式:pankaj.doke@tcs.com
桑杰·金巴胡内
Sanjay Kimbahune 拥有 Amravati 大学电子工程学士学位。他是 Tata Consultancy Services Limited 孟买创新实验室的研究科学家。他的研究兴趣是移动计算和电信系统。
联系方式:sanjay.kimbahune@tcs.com
历史
- 2010年9月13日:初始版本