65.9K
CodeProject 正在变化。 阅读更多。
Home

将 SQLite 移植到 BREW

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.29/5 (4投票s)

2010年9月13日

CPOL

10分钟阅读

viewsIcon

30600

downloadIcon

452

- 将SQLite 3.2.8版本作为BREW 3.1.2版本的扩展提供

版权所有 © 2010 Tata Consultancy Services Ltd. 保留所有权利

需求和介绍

典型的手机应用程序基于请求-响应模式。每当应用程序需要数据时,它会向服务器发送一个Web请求。服务器在服务器上保存的数据库中处理请求,并将响应发送给应用程序。然而,这种方法往往与无线网络带宽应得到最佳利用的基本要求相悖。“断开连接的数据库模型”方法提供了一个解决方案来克服这个问题。在这种方法中,数据库和数据库引擎都位于手机本身上,每当应用程序需要数据时,它不是向服务器发送Web请求,而是向驻留在手机上的数据库发送数据库查询。这减少了对服务器的Web调用次数,并通过缩短响应时间来提高性能。这种方法的缺点是手机上可能存在过时的数据。但如果数据不经常更改,这是可以接受的。手机上的数据库可以定期与服务器上的数据库同步,以消除这种缺点。参见图1和图2。

图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版本中的某个版本来升级我们自己。由于我们的需求很简单,我们只是希望能够在手机上成功执行selectupdatedeleteinsert命令,所以我们选择了3.2.8版本。我们没有将SQLite源代码与我们的应用程序集成,而是决定将这个版本的SQLite作为BREW扩展。本文描述了从SQLite源代码创建此扩展所涉及的步骤。

SQLite是世界上部署最广泛的SQL数据库引擎。SQLite的源代码是公共领域的。点击此处了解更多关于SQLite的信息。

要求

创建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.hparse.ckeywordhash.hopcodes.hopcodes.csqlite3.h

  • gcc -o lemon lemon.c(此命令编译root\tool文件夹中的lemon.c文件并生成可执行文件lemon)
  • ./lemon parse.y(此命令使用可执行文件lemon从parse.y生成parse.cparse.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.awkparse.hvdbe.c生成opcodes.h
  • cat opcodes.h | awk -f mkcodec.awk>opcodes.c (此命令使用文件mkcodec.awkopcodes.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库函数的调用可能会导致应用程序在手机上崩溃。

修改以下文件

  1. 文件:root\src\os.hroot\src\os.c

    os.hos.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.hos.c文件。

  2. 文件:root\src\util.croot\src\table

    util.ctable.c调用了malloc()realloc()free()等函数。将对malloc()realloc()free()的调用分别替换为MALLOC()REALLOC()FREE()。这些函数是BREW API提供的malloc()realloc()free()的BREW特定实现。

  3. 文件: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
  4. 文件:root\src\parse.c

    在某些文件(如parse.cupdate.cinsert.cvdbe.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)中的相应文件。

  5. 文件:root\src\random.c

    此文件中定义的函数sqliteRandomByte()。此定义可在SQLite 2.2.0版本的源代码中找到。此函数正从os.c文件中调用。

    int sqliteRandomByte(){
      int r;
      sqlite3OsEnterMutex();
      r = randomByte();
      sqlite3OsLeaveMutex();
      return r;
    }
  6. 文件:root\src\prepare.c

    替换了一个if语句

    if( meta[1]>3 ){

    if( meta[1]>4 ){

步骤4:添加isqlite.c和isqlite.h文件

在工作区中包含文件isqlite.hisqlite.c。名为ISQLiteClass的SQLite 3.2.8版本接口在isqlite.h中定义。此接口的函数在isqlite.c中定义。有关详细信息,请参见(iSQLite.zip)中的文件。

步骤5:在RVDS中编译和链接

要为扩展生成BREW可执行(.mod)文件,请将所有源文件包含到工作区中。不要在工作区中添加AEEAppgen.cAEEModGen.c文件,而是添加iSQLite.zip中提供的名为AppgenModGen.a的文件。此文件是AEEAppgen.cAEEModGen.c文件的预编译库。

使用如下屏幕截图所示的设置

目标设置:后链接器被禁用,因为我们使用brew elf2mod工具从.elf生成.mod文件。

访问路径:在项目的“访问路径”选项卡中指定所有必需的路径,以消除所有链接错误。

编译器设置

链接器设置:我们将输出文件名设置为isqlite.elf

最后一步:生成.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日:初始版本
© . All rights reserved.