首页 | 资讯动态 | linux基础 | 系统管理 | 网络管理 | 编程开发 | linux数据库 | 服务器技术 | linux相关 | linux认证 | 嵌入式 | 下载中心 | 专题 | linux招聘 | 镜像站
OKLinux中文技术站
·设为首页
·加入收藏
·联系我们
系统管理: 中文环境 系统管理 桌面应用 内核技术 | Linux基础: 基础入门 安装配置 常用命令 经验技巧 软件应用 | Linux数据库: Mysql Postgre Oracle DB2 Sybase other
网络管理: 网络安全 网络应用 Linux服务器 环境配置 黑客安全 | 编程开发: PHP CC++ Python Perl Shell 嵌入式开发 java jsp | PHP技术: PHP基础 PHP技巧 PHP应用 PHP文摘
Linux资讯 Linux招聘 Linux专题 Apache | Linux相关: 硬件相关 Linux解决方案 Linux认证 企业应用 其它Unix | 相关下载: 资料下载 参考手册 开发工具 服务器类 软路由 其它
 技术搜索:
会员中心 注册会员 高级搜索  
  → 当前位置:首页>linux数据库>postgre>正文

Sqlite中文排序研究

http://www.oklinux.cn  2006-11-27  来源: blog.csdn.net absurd  会员收藏  游客收藏  【 】 

Sqlite是一个用C语言实现的小型SQL数据库引擎。它体积小巧但功能强大,对硬件资源要求很低而且性能表现卓越,非常适合于嵌入式应用环境。最近发现sqlite并不支持中文(拼音/笔画)排序,而这个功能又是我们必需的,所以花了些时间去研究。我对Sqlite的了解只能算是业余级,在研究的过程或许走了些弯路,或许已经有现存的算法可利用,不管怎么样,在研究过程中还是有不少收获,写出来和大家探讨一下。

 

我们知道,计算机中的每一个字符都有一个内码。在默认情况下,计算机排序时,比较两个字符的大小就是比较字符内码的大小,这对于英文来说没有问题,因为英文字母的内码是按字母顺序递增的。对于中文来说,就比较麻烦了:首先,中文的排序方式有多种,比如按内码排序、按拼音排序和按笔画排序,要通过参数指定排序的方式,否则计算机就按内码排序了。其次,汉字的内码顺序即不同于拼音顺序,也不同于按笔画顺序。在GB2312编码中,汉字基本上按拼音排序(据说有例外,不太清楚)。在GBK中,它在GB2312基础上进行了扩充,兼容GB2312中的所有字符,所以不是按拼音排序了。在Unicode中,汉字的排列似乎更没有什么规律可言了。

 

为了解决内码顺序与用户习惯顺序(如拼音顺序)的冲突,在glibclocale数据里,要求提供排序方式(collate)的描述。我看了一下glibc-2.3.5提供的locale数据,在简体中文(zh_CN)locale数据描述里,关于排序方式的描述如下:

% ISO 14651 collation sequence

LC_COLLATE

copy "iso14651_t1"

END LC_COLLATE

 

也就是说,照抄iso14651_t1的排序方式。打开iso14651_t1文件看了一下,也没有发现关于中文的特殊处理,可以推断glibc默认的排序方式就是按unicode排序。

 

所以不能指望glibc提供中文排序功能,如果SQLite支持了中文排序只能是做了特殊处理。浏览了一下SQLite的代码,这种希望似乎也不大。在网上也没有查到相关的资料和补丁,看来只能靠自己了。

 

不过,在浏览SQLite代码时还是有些收获,至少知道了它比较数据记录的过程:

1.         sqlite3VdbeExec调用sqlite3BtreeInsert把记录插入到适当的位置。

2.         sqlite3BtreeInsert调用sqlite3BtreeMoveto找到要插入的位置。

3.         sqlite3BtreeMoveto调用sqlite3VdbeRecordCompare比较两条记录的大小。

4.         sqlite3VdbeRecordCompare调用sqlite3MemCompare比较字段的大小。

5.         sqlite3MemCompare调用binCollFunc去做真正的比较。

6.         binCollFunc是一个回调函数,由外层设置的。

 

进一步研究,知道了binCollFunc的来源:

1.         struct CollSeq是一个用来比较的对象,它带有一个比较函数和相关上下文。

2.         通过multiSelectCollSeq找到合适的CollSeq对象。

3.         multiSelectCollSeq调用sqlite3ExprCollSeq查找。

4.         multiSelectCollSeq调用sqlite3CheckCollSeq查找。

5.         查找标准是SELECTCREATE TABLE所带的COLLATE子句。

6.         也就是说可以通过SELECTCREATE TABLE的参数来决定选择哪个比较函数。

 

基于上面这些认识,我们知道比较函数是可以指定的了。接下来的问题是,我们能否自定义比较函数,如何自定义,以及如何安装到SQLite里。很快发现SQLite已经提供了安装比较函数的接口:

int sqlite3_create_collation16(

  sqlite3* db,

  const char *zName,

  int enc,

  void* pCtx,

  int(*xCompare)(void*,int,const void*,int,const void*)

)

 

int sqlite3_create_collation(

  sqlite3* db,

  const char *zName,

  int enc,

  void* pCtx,

  int(*xCompare)(void*,int,const void*,int,const void*)

)

 

 

前者用来安装UTF-16的比较函数,后者用来安装UTF-8的比较函数。我们发现,在main.c里已经安装了一些内置的比较函数:

sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc);

sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc);

sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);

 

好了,原理清楚了,我们要做的只是提供一个比较函数,并且安装进去就OK了。为了测试,我写一个按拼音排序的比较函数(按笔画排序类似):

int pinyin_cmp(

    void *NotUsed,

    int nKey1, const void *pKey1,

    int nKey2, const void *pKey2)

{

    int n = nKey1 < nKey1 ? nKey1 : nKey2;

 

    return pinyin_strncmp(pKey1, pKey2, n + 1);

}

 

 

安装比较函数时要注意,因为我们实现的比较函数是针对UTF-16的,所以名字要用UTF-16编码。但是由于linux下默认的wchar_t32位的,不能直接用L”pinyin”的方式把ANSI字符串转换成UTF-16字符串,只能按下列方式。

unsigned short zName[] = {'p', 'i', 'n', 'y', 'i', 'n', 0};

sqlite3_create_collation16(db, zName, SQLITE_UTF16, 16, pinyin_cmp);

 

测试结果正常(红色部分为按拼音排序,蓝色部分为默认排序):

sqlite> create table person(name text, age int);

sqlite> insert into person values("张三", 23);

sqlite> insert into person values("张三丰", 23);

sqlite> insert into person values("李四", 24);

sqlite> insert into person values("李四叔", 24);

sqlite> insert into person values("王五", 25);

sqlite> insert into person values("王五妹", 25);

sqlite> insert into person values("赵七", 26);

sqlite> insert into person values("赵七姑", 26);

sqlite>

sqlite> select * from person order by name collate pinyin;

李四|24

李四叔|24

王五|25

王五妹|25

张三|23

张三丰|23

赵七|26

赵七姑|26

sqlite> select * from person order by name;              

张三|23

张三丰|23

李四|24

李四叔|24

王五|25

王五妹|25

赵七|26

赵七姑|26

 

总结:SQLite的架构设计非常优秀,接口定义得也比较合理,支持中文排序变得非常简单。

原文链接:http://blog.csdn.net/absurd


上一篇:MySQL的一些安全注意点   下一篇:通过Putty远程安全管理MySQL


收藏于收藏夹】 【评论】 【推荐】 【打印】 【关闭
相关文档
·初识开源面向对象数据库 db4o
·BI相关的开源工具
·在SUSE Linux Server上配置DB2
·通过Perl 编程访问DB2数据库
·Sqlite 数据库在Media NAS 系统中的应用
·数据库的开源之旅
·OpenBSD4.0 PostgreSQL8.1.5数据库的安装
·PostgreSQL 最新8.2版发布
·将你的网站从MySQL改为PostgreSQL
·ucLinux下sqlite数据库移植全攻略
·PostgreSQL介绍及安装指南
·Linux下免费数据库PostgreSQL开发入门
·PostgreSql服务器的配置
·源码安装Postgresql8.1.3+PostGIS1.1.2
·PostgreSQL 的热备和恢复
·Linux实时内存数据库eXtremeDB性能
发表评论
密码: 匿名评论
评论内容:

(不超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规)
 
  最新文档
·在Ubuntu和Debian系统下安装PostgreSQL
·如何从网络上登录其它计算机的PostgreS
·Ubuntu系统下安装和配置PostgreSQL 8.1
·在RedHat7.0上安装和配置PostgreSQL
·PostgreSQL7.2教程(2)
·PostgreSQL7.2教程(1)
·Python入门第十章 进一步学习
·Python入门第九章 类
·Python入门第八章 错误与例外
·Python入门第七章 输入输出
·Python入门第六章 模块
·Python入门第五章 Python数据结构
  阅读排行
·Python入门第七章 输入输出
·PostgreSQL 最新8.2版发布
·PostgreSQL介绍及安装指南
·PostgreSQL 的热备和恢复
·PostgreSQL 7.2 教程 (1)
·在Linux上安装postgresql的全过程
·源码安装Postgresql8.1.3+PostGIS1.1.2
·PostgreSQL入门,V0.9.3+++
·ucLinux下sqlite数据库移植全攻略
·Linux下mySQL数据库开发技术
·Linux实时内存数据库eXtremeDB性能
·将你的网站从MySQL改为PostgreSQL
·postgresql访问认证设置
·PostgreSQL7.2教程(1)
·BI相关的开源工具
网摘收藏: