在Oracle i中往往会出现要在存储过程中运行操作系统命令的情况一般来说利用Oracle Enterprise Manager设定作业时可以达到这个目的但是由于OEM在设定作业缺乏灵活性设定的作业的参数是固定的在实际应用当中往往需要在SQL语句当中运行需要随时运行操作系统命令Oracle i没有直接运行OS命令的语句我们可以利用DBMS_PIPE程序包实现这一要求
DBMS_PIPE通过创建管道可以让至少两个进程进行通信Oracle的管道与操作系统的管道在概念上有相同的地方但是在实现机制不同
下面介绍实现具体步骤:
创建一个程序包姑且起名叫DAEMONSQL语句如下:
/*创建daemon程序包*/
CREATE OR REPLACE PACKAGE BODY daemon AS
/*execute_system是实现运行os命令的函数*/
FUNCTION execute_system(command VARCHAR
timeout NUMBER DEFAULT )
RETURN NUMBER IS
status NUMBER;
result VARCHAR();
command_code NUMBER;
pipe_name VARCHAR();
BEGIN
pipe_name := DBMS_PIPEUNIQUE_SESSION_NAME;
DBMS_PIPEPACK_MESSAGE(SYSTEM);
DBMS_PIPEPACK_MESSAGE(pipe_name);
DBMS_PIPEPACK_MESSAGE(command);
/*向daemon管道发送表示命令的字符*/
status := DBMS_PIPESEND_MESSAGE(daemon timeout);
IF status <> THEN
RAISE_APPLICATION_ERROR(
Execute_system: Error while sending Status = || status);
END IF;
status := DBMS_PIPERECEIVE_MESSAGE(pipe_name timeout);
IF status <> THEN
RAISE_APPLICATION_ERROR(
Execute_system: Error while receiving
Status = || status);
END IF;
/*获取返回结果*/
DBMS_PIPEUNPACK_MESSAGE(result);
IF result <> done THEN
RAISE_APPLICATION_ERROR(
Execute_system: Done not received);
END IF;
DBMS_PIPEUNPACK_MESSAGE(command_code);
DBMS_OUTPUTPUT_LINE(System command executed result = ||
command_code);
RETURN command_code;
END execute_system;
/*stop是让daemon停止*/
PROCEDURE stop(timeout NUMBER DEFAULT ) IS
status NUMBER;
BEGIN
DBMS_PIPEPACK_MESSAGE(STOP);
status := DBMS_PIPESEND_MESSAGE(daemon timeout);
IF status <> THEN
RAISE_APPLICATION_ERROR(
stop: error while sending status = || status);
END IF;
END stop;
END daemon;
通过Sql*Plus运行以上语句将为当前用户创建daemon程序包
创建在OS上运行的守护进程监听由上面的daemon程序包发来的要求执行os命令的语句以下Pro*C的代码必须由pro*c先进行预编译
#include
#include
EXEC SQL INCLUDE SQLCA;
EXEC SQL BEGIN DECLARE SECTION;
char *uid = scott/tiger;/*在这个地方改为你自己访问的用户密码服务名*/
int status;
VARCHAR command[];
VARCHAR value[];
VARCHAR return_name[];
EXEC SQL END DECLARE SECTION;
void
connect_error()
{
char msg_buffer[];
int msg_length;
int buffer_size = ;
EXEC SQL WHENEVER SQLERROR CONTINUE;
sqlglm(msg_buffer &buffer_size &msg_length);
printf(Daemon error while connecting:\n);
printf(%*s\n msg_length msg_buffer);
printf(Daemon quitting\n);
exit();
void
sql_error()
{
char msg_buffer[];
int msg_length;
int buffer_size = ;
EXEC SQL WHENEVER SQLERROR CONTINUE;
sqlglm(msg_buffer &buffer_size &msg_length);
printf(Daemon error while executing:\n);
printf(%*s\n msg_length msg_buffer);
printf(Daemon continuing\n);
}
main()
{
EXEC SQL WHENEVER SQLERROR DO connect_error();
EXEC SQL CONNECT :uid;
printf(Daemon connected\n);
EXEC SQL WHENEVER SQLERROR DO sql_error();
printf(Daemon waiting\n);
while () {
EXEC SQL EXECUTE
BEGIN
/*接收deamon发来的字符*/
:status := DBMS_PIPERECEIVE_MESSAGE(daemon);
IF :status = THEN
/*取出字符*/
DBMS_PIPEUNPACK_MESSAGE(:command);
END IF;
END;
ENDEXEC;
IF (status == )
{
commandarr[commandlen] = \;
/*如果是stop该进程就退出*/
IF (!strcmp((char *) commandarr STOP))
{
printf(Daemon exiting\n);
break;
}
ELSE IF (!strcmp((char *) commandarr SYSTEM))
{
EXEC SQL EXECUTE
BEGIN
DBMS_PIPEUNPACK_MESSAGE(:return_name);
DBMS_PIPEUNPACK_MESSAGE(:value);
END;
ENDEXEC;
valuearr[valuelen] = \;
printf(Will execute system command %s\n valuearr);
/*运行os命令*/
status = system(valuearr);
EXEC SQL EXECUTE
BEGIN
DBMS_PIPEPACK_MESSAGE(done);
DBMS_PIPEPACK_MESSAGE(:status);
:status := DBMS_PIPESEND_MESSAGE(:return_name);
END;
ENDEXEC;
IF (status)
{
printf
(Daemon error while responding to system command);
printf( status: %d\n status);
}
}
ELSE
{
printf
(Daemon error: invalid command %s received\n
commandarr);
}
}
ELSE
{
printf(Daemon error while waiting for signal);
printf( status = %d\n status);
}
}
EXEC SQL COMMIT WORK RELEASE;
exit();
}