纵贯线,老男人的春天

4.25 晚上8点,杭州黄龙体育中心,纵贯线,四个老男人,三万六千名老男人的拥趸。罗大佑,李宗盛,周华健,张震岳,多少年前已经听惯的声音,于这一晚亲耳聆听。

回想大学时代,忽而已是十年。当年寝室里的老三迷恋着张学友,老九模仿着周华健,回想起来,犹如昨日,甚至恍惚间觉得他们跟他们已经面孔模糊在一起,就像你的样子。

三个小时,十年,逝去的时光,无论长短,在记忆中都将是永恒。有些东西,言语不足形容;有些记忆,岁月不能带走。

使用zlib输出gzip格式的文件

zlib是一个比较通用的压缩库,通过在程序中引入zlib,可以方便的对数据进行压缩。今天花了点时间研究了一下,在tbuldr中实现了直接将数据库中的数据导出为gzip文件的功能。

下载zlib源代码,对于Linux,可以编译成静态库,然后将zlib.h,libz.a(如有必要,再加上zonf.h)和程序代码放置到同一个目录,编译的时候包含libz.a即可。

#./configure
#make
#make install

如果要编译成动态库,则只需要第一步改成./configure -s即可。

废话少说,下面是一段演示代码,非常简单:

#include <stdio.h>
#include "zlib.h"

int main()
{
  char *data = "this is a gzip test from NinGoo.net";
  gzFile *fp=NULL;
  fp=gzopen("test_out.gz","wb");
  gzwrite(fp,data,strlen(data));
  gzclose(fp);
}

编译:

gcc -o test test.c libz.a

执行:

$./test
$gzip -d test_out.gz
$more test_out
this is a gzip test from NinGoo.net

tbuldr中,只需要在file参数指定的文件名后面加上.gz,就会自动输出为gzip格式的文件。至此,tbuldr已基本实现了sqluldr2的全部功能,性能测试结果也不相上下了。

另外,zlib也可以在内存中对数据进行压缩和解压缩,参考:
http://hispider.googlecode.com/svn/trunk/devel/hispider/src/utils/zstream.c

学习oci编程,从ociuldr开始

Update:发现原来在linux上写的代码,到windows上编译会有些错误,主要是编译器对变量声明的位置容忍度不一样,已经修正了代码。另外对输出的日志做了一点增强,打印了导出的总时间,省得人工计算了。并将源代码,windows32位版本,linux32位版,及linux64版本一并打包提供下载测试。

一直想学学oci编程,无奈基础不好,几次都是看了几页文档就放下了。所以比较佩服老楼,写了很多优秀的工具,例如广泛使用的ociuldr,以及为很多人解决了难题的AUL等。最近老楼焕发第二春,对ociuldr做了大量改进,并且升级成了sqluldr2,刚刚获得的最新消息是,sqluldr2开始支持gzip压缩格式了,牛人就是牛。

上周六一大早跑到公司,处理完一点小事后,想想反正来了,就多呆会儿吧。干什么呢?溜达到老楼的blog上,看到一对sqluldr的信息,就花了一上午的时间研究了下老版的ociuldr的源代码,再参考hrb_qiuyb写的oci8版的ociuldr2,这次终于能看明白了,还是oci8的函数比较容易懂,于是就开始自己动手编译。hrb_qiuyb版的bug比较多,动不动就segment fault,想了想不如多花点时间,好好的重新改写一下,虽然老楼已经出了sqludr2,珠玉在前,不过最近流行山寨,他做企业版,我来做山寨版,哈哈。山寨版的名字,就叫tbuldr(ToolBox*UnLoader),因为是基于老楼开放出来的源代码弄的,那就继续开源吧,希望不要抢了sqluldr2的生意哈。

到今天为止,代码终于差不多稳定了,修复了几个主要的bug,同时把sqluldr2最新的一些特性也用山寨的方法实现了,可能效率不如老楼的,不过至少外观上看是差不多了,如输出到stdout新版本的sqlldr控制文件固定长度导出指定表名导出按列输出等功能一一实现了。

另外还实现了一些小的功能:

  • feedback参数,指定输出多少行以后打印一条日志,可以更好的观察进度,默认还是50w条。
  • enclose参数,为每列加入包含字符。当选择的field字符在列值中有出现的时候,enclose就有作用了。
  • fixlen参数,表示固定长度输出。而不是像sqluldr2一样当field指定为0×20(空格)的时候采用固定长度。这个主要是考虑到某些非常特殊的情况下,可能会有人希望用空格做分隔符而又不希望是固定长度的。
  • 还有个隐含的debug参数,打开后会输出一些debug信息,主要array fetch时为各列分配的内存等数据。这个主要是dw用了老楼很早以前的一个debug版本,觉得log里输出了列名还挺有用,就保留了,不过默认是不显示的,也没有写在help里,这里偷偷的透露一下了,哈哈
$tbuldr

----------------------------------------------------------------------------
- tbuldr: Release 2.21 (ociuldr)
- First issued by Lou Fangxin (@) Copyright 2004/2008, all rights reserved.
- Modified by Ning Haiyuan (http://www.NinGoo.net).
----------------------------------------------------------------------------
 Usage: TBULDR keyword=value [,keyword=value,...]
 Valid Keywords:
       user     = username/password@tnsname
       query    = select statement, can simply speicify a table name
       sql      = SQL file name
       field    = seperator string between fields
       record   = seperator string between records
       enclose  = fields enclose string
       file     = output file name, default: uldrdata.txt
       head     = print row header(Yes|No,ON|OFF,1|0)
       read     = set DB_FILE_MULTIBLOCK_READ_COUNT at session level
       sort     = set SORT_AREA_SIZE at session level (UNIT:MB)
       hash     = set HASH_AREA_SIZE at session level (UNIT:MB)
       serial   = set _serial_direct_read to TRUE if 1 at session level
       trace    = set event 10046 to given level at session level
       table    = table name in the sqlldr control file
       mode     = sqlldr option, INSERT or APPEND or REPLACE or TRUNCATE
       log      = log file name, prefix with + to append mode
       long     = maximum long field size, default 8192 max 65534
       array    = array fetch size, default 50
       buffer   = sqlldr READSIZE and BINDSIZE, default 16 (MB)
       feedback = display progress every x rows, default 500000
       form     = display rows as form (Yes|No)
       fixlen   = fix length format (Yes|No)

  for field, record and enclose, use '0x' to specify hex character code
  r=0x0d n=0x0a |=0x7c ,=0x2c t=0x09  (more: man ascii)
$tbuldr user=test/test query=t
       0 rows exported at 2009-04-16 20:43:53
    400 rows exported at 2009-04-16 20:43:54
         output file uldrdata.txt closed at 4 rows. Elapsed time: 0 min 1 sec.
         control file is t_sqlldr.ctl.

当然,山寨版就是山寨版,以下sqluldr2的新功能暂未实现:

  • parfile,这个是比较有用功能,可以防止命令行中显式输入密码导致密码泄漏等。因为涉及到文件内容解析,对我来说,难度有点高,以后再说。
  • gzip压缩,这是下午老楼刚刚加入的新特性,还有待研究。不过这是利用了zlib实现的,网上有不少现成的代码,集成进来应当是能搞定的。另外也可以输出到stdout后通过管道调用gzip实现压缩,这个已经支持了。
  • BLOB/BFILE等不提供支持,虽然BLOB可以按照LONG RAW的方式导出成16进制字符,不过不保证没问题,如果BLOB里存储的是字符应当问题不大。CLOB/LONG最大只支持到65534字节,对于大部分情况应当是足够了。

第一次用c和oci正儿八经的写东西,bug肯定一大堆。山寨有风险,慎用,如果是生产环境有需求的,建议还是找老楼的企业版,支持山寨版的同学,可以自行编译帮忙做测试,有bug和建议欢迎提交^_^

如何在AIX上安装gcc

默认情况下AIX是不带编译器,如果需要编译一些源代码,则可以安装linux上常用的gcc。AIX上支持安装linux的RPM包。首先要安装RPM包支持,下载地址为:
ftp://ftp.software.ibm.com/aix/freeSoftware/aixtoolbox/INSTALLP/ppc/rpm.rte

使用installp安装即可,如下表示已经安装

lslpp -l rpm.rte
  Fileset                      Level  State      Description
  ----------------------------------------------------------------------------
Path: /usr/lib/objrepos
  rpm.rte                   3.0.5.40  COMMITTED  RPM Package Manager

Path: /etc/objrepos
  rpm.rte                   3.0.5.40  COMMITTED  RPM Package Manager

然后去下载gcc的安装包,进入下面的链接即可下载IBM提供的AIX Toolbox for Linux Applications,包括gcc:
http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/download.html
AIX5.3上的gcc下载地址为:
ftp://ftp.software.ibm.com/aix/freeSoftware/aixtoolbox/RPMS/ppc/gcc/gcc-4.2.0-3.aix5.3.ppc.rpm

root>#rpm -i gcc-4.2.0-3.aix5.3.ppc.rpm
root>#gcc -v
Using built-in specs.
Target: powerpc-ibm-aix5.3.0.0
Configured with: ../configure --with-as=/usr/bin/as --with-ld=/usr/bin/ld
--enable-languages=c,c++,java --prefix=/opt/freeware
--enable-threads --enable-version-specific-runtime-libs
--host=powerpc-ibm-aix5.3.0.0 --target=powerpc-ibm-aix5.3.0.0
--build=powerpc-ibm-aix5.3.0.0 --disable-libjava-multilib
Thread model: aix
gcc version 4.2.0