暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 从数据库内部执行命令scp

askTom 2018-09-03
707

问题描述

美好的一天
汤姆
-
我写信给你,因为我在开发中遇到问题,我需要访问linux服务器来动态提取文件,并使用java库中支持的scp命令将它们放置在我的windows服务器上。但它失败了,因为它告诉我该命令 “既不外部也不内部” 未被识别。

这可能会发生吗?

我附加了我的代码。

非常感谢您的帮助

CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "Host" AS
import java.io.*;

public class Host {
  public static void executeCommand(String command) {
    try {
      String[] finalCommand;
      if (isWindows()) {
        finalCommand = new String[4];
        // Use the appropriate path for your windows version.
        //finalCommand[0] = "C:\\winnt\\system32\\cmd.exe";    // Windows NT/2000
        finalCommand[0] = "C:\\windows\\system32\\cmd.exe";    // Windows XP/2003
        //finalCommand[0] = "C:\\windows\\syswow64\\cmd.exe";  // Windows 64-bit
        finalCommand[1] = "/y";
        finalCommand[2] = "/c";
        finalCommand[3] = command;
      }
      else {
        finalCommand = new String[3];
        finalCommand[0] = "/bin/sh";
        finalCommand[1] = "-c";
        finalCommand[2] = command;
      }
  
      final Process pr = Runtime.getRuntime().exec(finalCommand);
      pr.waitFor();

      new Thread(new Runnable(){
        public void run() {
          BufferedReader br_in = null;
          try {
            br_in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
            String buff = null;
            while ((buff = br_in.readLine()) != null) {
              System.out.println("Process out :" + buff);
              try {Thread.sleep(100); } catch(Exception e) {}
            }
            br_in.close();
          }
          catch (IOException ioe) {
            System.out.println("Exception caught printing process output.");
            ioe.printStackTrace();
          }
          finally {
            try {
              br_in.close();
            } catch (Exception ex) {}
          }
        }
      }).start();
  
      new Thread(new Runnable(){
        public void run() {
          BufferedReader br_err = null;
          try {
            br_err = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
            String buff = null;
            while ((buff = br_err.readLine()) != null) {
              System.out.println("Process err :" + buff);
              try {Thread.sleep(100); } catch(Exception e) {}
            }
            br_err.close();
          }
          catch (IOException ioe) {
            System.out.println("Exception caught printing process error.");
            ioe.printStackTrace();
          }
          finally {
            try {
              br_err.close();
            } catch (Exception ex) {}
          }
        }
      }).start();
    }
    catch (Exception ex) {
      System.out.println(ex.getLocalizedMessage());
    }
  }
  
  public static boolean isWindows() {
    if (System.getProperty("os.name").toLowerCase().indexOf("windows") != -1)
      return true;
    else
      return false;
  }

};
/


 create or replace procedure runOn ( p_cmd in varchar2)
 as
 -- Created : 03/09/2018 10:40:00
 -- Purpose : Ejecutar comando cmd out scope pl/sql
 language java
   name 'Host.executeCommand (java.lang.String)';
/
--

DECLARE
  l_schema VARCHAR2(30) := 'VENTAS'; -- Adjust as required.
BEGIN
  DBMS_JAVA.grant_permission(l_schema, 'java.io.FilePermission', '<>', 'read ,write, execute, delete');
  DBMS_JAVA.grant_permission(l_schema, 'SYS:java.lang.RuntimePermission', 'writeFileDescriptor', '');
  DBMS_JAVA.grant_permission(l_schema, 'SYS:java.lang.RuntimePermission', 'readFileDescriptor', '');
END;
/

SET SERVEROUTPUT ON SIZE 1000000
CALL DBMS_JAVA.SET_OUTPUT(1000000);
begin
  runOn ('cd c:\com\interfases\entrada');
  runOn ('C:\Users\ecorona\Documents\MobaXterm\slash\bin\scp.exe root@999.99.99.999:/root/2018/img/154819-2.jpeg .');
end;
/
复制


打电话给终端。

进程错误: 系统找不到指定的路径。

Procedimiento PL/SQL终端更正。

专家解答

好的,我将建议一种不同的方法,因为我认为您会发现它更简单。

首先,我们将创建一个具有预处理器的外部表

SQL> create or replace directory TEMP as 'c:\temp';

Directory created.

SQL> create or replace directory BIN as 'c:\bin';

Directory created.

SQL>
SQL> create table host_command_external
  2  ( text  varchar2(4000)  )
  3  organization external
  4  (
  5    type oracle_loader
  6    default directory temp
  7    access parameters
  8   (
  9      records delimited by newline nologfile
 10      preprocessor bin: 'run_command.cmd'
 11      fields terminated by whitespace
 12      ( text position(1:4000) )
 13   )
 14   location ('dummy.txt')
 15  )
 16  reject limit unlimited;

Table created.
复制


现在,文件 'dummy.txt '* 必须 * 存在,但我们不在乎内容-因此,我们只是创建一个空文件

SQL> host touch c:\temp\dummy.txt
复制


我们真正感兴趣的是 'run_command.cmd' 的内容。因此,我将首先添加作为测试:

c:\bin\run_command.cmd
===============
@echo off
echo This is a test
复制


然后查询我的表

SQL> select * from host_command_external;

TEXT
------------------------------------------
This is a test
复制


好的... 您可以看到这是怎么回事-* 查询 * 我的表将 * 运行 * run_command.cmd脚本。

所以现在我将用UTL_FILE来增强它

SQL> declare
  2    f utl_file.file_type;
  3  begin
  4    f := utl_file.fopen('BIN','run_command.cmd','w');
  5    utl_file.put_line(f,'C:\bin\usr\local\wbin\ls -l c:\temp');
  6    utl_file.fclose(f);
  7  end;
  8  /

PL/SQL procedure successfully completed.

SQL> select * from host_command_external;

TEXT
------------------------------------------------------------------------------------------------------
c:\oracle\product\12.2\DATABASE>C:\bin\usr\local\wbin\ls -l c:\temp
total 1971276
-rw-rw-rw-   1 user     group      105791 Jun  2  2017 122_download_now.jpg
-rw-rw-rw-   1 user     group      134220 Sep 12  2017 12c.png
-rw-rw-rw-   1 user     group      248032 Aug 23 11:08 18c_pic1.jpg
-rw-rw-rw-   1 user     group      414154 Aug 23 11:08 18c_pic2.jpg
复制


所以动态改变脚本的内容也有效。因此,我们可以将其包装在一个函数中,以使其易于使用

SQL> create or replace
  2  function host_command(p_command varchar2) return sys.odcivarchar2list pipelined is
  3    f utl_file.file_type;
  4  begin
  5    f := utl_file.fopen('BIN','run_command.cmd','w');
  6    utl_file.put_line(f,p_command);
  7    utl_file.fclose(f);
  8
  9    for i in ( select * from host_command_external )
 10    loop
 11      pipe row ( i.text );
 12    end loop;
 13    return;
 14  end;
 15  /

Function created.

SQL>
SQL> select * from host_command('C:\bin\usr\local\wbin\ls -l c:\temp');

COLUMN_VALUE
-------------------------------------------------------------------------------------------
c:\oracle\product\12.2\DATABASE>C:\bin\usr\local\wbin\ls -l c:\temp
total 1971276
-rw-rw-rw-   1 user     group      105791 Jun  2  2017 122_download_now.jpg
-rw-rw-rw-   1 user     group      134220 Sep 12  2017 12c.png
-rw-rw-rw-   1 user     group      248032 Aug 23 11:08 18c_pic1.jpg
-rw-rw-rw-   1 user     group      414154 Aug 23 11:08 18c_pic2.jpg
复制


就这样。运行带有select语句的主机命令。

现在 * 显然 * 你不会有一个只需要 * 任何 * 参数并盲目运行的函数-这是一个巨大的风险。但是在您的情况下,该函数可能仅采用文件名,然后在utl_file.put_line调用中编写适当的scp命令。

但是您可以看到这是如何工作的-并且比java存储的proc更容易调试/维护。
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论