[转帖]如何快速导出SYBASE的存储过程
<table width="100%"><tbody><tr><td class="a14"><b>问题的提出</b></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">在一个应用系统中,如果编写了大量的Sybase存储过程,对存储过程进行系统、有效地备份是必须的。而我们通常用的办法是使用Sybase提供的Sybase Central工具先选定存储过程,然后通过鼠标右键选择Generate DDL的方式把存储过程备份下来。使用这种方式,不仅备份时间特别长(备份文件为6M左右时,达几个小时之久),更要命的是使用该方式备份下来的存储过程文本往往无法直接使用,因为在每个存储过程体后自动加的关键字go,有时就直接放在过程体最后一行尾部,没有空格,这样要使用该文本重新建过程时,需要花大量的时间进行修正。因此,找一种备份速度既快备份后内容又规整的方法来替代该工具是完全有必要的。</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">笔者在实际工作中,交叉使用以下两种方法,对存储过程进行备份。方法一:通过编写嵌入sql的C程序,实现整库存储过程的快速导出。方法二:通过defncopy快速导出指定的存储过程。现分别详细介绍如下:</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"><b>方法一:通过cpre实现快速导出</b></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">以下程序通过sybase的cpre预编译处理生成可执行文件后,可以实现存储过程的快速导出,在数据库空闲时,可以在一分钟之内导出所有的存储过程(生成的文件有6M左右,而Sybase Central需要以小时计)。</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">该程序运行时格式如下(设可执行文件为exportproc):</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">sybase> exprotproc 文件名 </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">执行完后,所有的存储过程体就存放在该文件中,文件的内容也保存了存储过程的书写格式,并在每个存储过程后面加一个单独的行go。为了使程序灵活,在正式导之前根据提示需要输入用户名、口令、联机串、数据库名。</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">#include <stdio.h></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">#include <unistd.h></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL INCLUDE SQLCA;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">void Sql_Error();</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">main( argc, argv)</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">int argc;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">char **argv;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">{</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">FILE *fp;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">char useName, usePasswd, dbString;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">char *fpass;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">long oldId;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL BEGIN DECLARE SECTION;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">char textLine;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">long id;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">char dbName;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL END DECLARE SECTION;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*输入参数不够,给出使用提示*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">if (argc!=2){</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Usage As %s <fileName>\n", argv);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">exit(0);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">if( (fp=fopen(argv,"w+"))==NULL){</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Open file %s error\n",argv);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">exit(0);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*输入联库用户名*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Please Input user name:");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">gets(useName); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*输入用户口令,在输入时屏幕不显示输入内容*/ </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">fpass=getpass("Please Input Passwd:");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">strcpy(usePasswd,fpass);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*输入联库字符串*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Please Input Database string:");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">gets(dbString); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*输入要导出其中存储过程的库名*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Please Input Database Name:");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">gets(dbName); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL WHENEVER SQLERROR CALL Sql_Error(); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">if( ConnectDB(useName, usePasswd, dbString) !=0){ /*连接数据库*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Can't connect database\n");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">exit(0);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">else</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Connect database ok!\n");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Begin to export PROCEDURE Please wait...\n");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL use :dbName;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL commit;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*声明游标,找出该库中所有的存储过程对应的内容*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL declare pro_cur cursor for</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">SELECT id, text from syscomments</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">where id in (select id from sysobjects </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">where type = 'P') </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">and texttype=0</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">and text is not null</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">order by id, number,colid2,colid;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL OPEN pro_cur;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL FETCH pro_cur into :id, :textLine;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">oldId=-9999L;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">while(!sqlca.sqlcode){</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">if( id!=oldId && oldId!=-9999L){</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*当一个存储过程结束后,在其过程体后加入新行GO*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">fprintf(fp,"\nGO\n\n"); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">oldId=id;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">fprintf(fp,"%s",textLine);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL FETCH pro_cur INTO :id, :textLine;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL CLOSE pro_cur;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">fprintf(fp,"\nGO\n\n"); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">fclose(fp);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("End export PROCEDURE !\n");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*断开于数据库的连接*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">DisConnectDB();</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Disconnect DataBase success!\n"); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">void Sql_Error()</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">{</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL WHENEVER SQLERROR CONTINUE; </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("Error.\n");</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">printf("%s\n",sqlca.sqlerrm.sqlerrmc);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">exit(0); </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*连接数据库函数*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">int ConnectDB( username, password, dbstring)</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL BEGIN DECLARE SECTION;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">CS_CHAR *username,*password,*dbstring;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL END DECLARE SECTION;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">{ </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL SET CHAINED OFF;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL CONNECT :username IDENTIFIED BY :password USING :dbstring;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">return(sqlca.sqlcode);</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">} </td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">/*断开数据库函数*/</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">int DisConnectDB()</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">{</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">EXEC SQL DISCONNECT ALL;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">return 0;</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">}</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">该程序在IBM AIX4.3、hp-unix 11.0、tru64 unix5.0平台上测试通过。</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14"><b>方法二:通过defncopy实现快速导出</b></td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">在需要对一些存储过程单独进行备份时,往往使用defncopy通过拼串的方式进行。具体步骤如下:</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">1.根据需要备份的存储过程,先编写此crtprocout.sql文件,假设导出所有以PR_JF开头的存储过程,内容如下:</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">select "defncopy -U用户名 -P口令 -S联机串名 out "+name+".sql 库名 "+name from sysobjects where type='P' and name like "PR_JF%"</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">2.利用上述文件,生成导过程脚本</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">isql -U用户名 -P口令 -S联机串名 –I crtprocout.sql –o procout</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">3.改变文件procout的权限</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">chmod +x procout</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">4.执行脚本导出过程,每个过程脚本名为:过程名+后缀”.sql”</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">./procout</td></tr></tbody></table><table width="100%"><tbody><tr><td class="a14">小结:以上两种办法通过修改sql语句里的where条件相互之间是可以代替的。但笔者认为,前者适合对整库的过程进行备份,而后者适合对指定的几个过程进行备份。因为前者会对所有的过程脚本生成到一个文件里,适合面向多个过程的管理和备份;而后者一个过程脚本生成一个文件,适合面向单个过程的管理和备份。以上两种方法通过简单修改也可进行触发器等的导出。</td></tr></tbody></table><a href="http://www.ccw.com.cn/htm/center/skill/02_7_25_2.asp">http://www.ccw.com.cn/htm/center/skill/02_7_25_2.asp</a>
页:
[1]