Python SQL*Plus subprocess Error: sgslunUDPNew: Unable to create communication endpoint

Python SQL*Plus subprocess Error: sgslunUDPNew: Unable to create communication endpoint

所以我们使用 python 和 sqlplus 将所有表导出到 csv 文件。由于我们的 oracle 数据库中有一些 unicode 数据,我们需要将 NLS_LANG 环境变量设置为 .AL32UTF8,以便 sqlplus 在假脱机到 csv 文件时实际使用 utf-8 编码。

手动执行此操作并在 cmd 中设置 NLS_LANG 变量工作正常。

但是下面的 python 片段:

...

print("Connecting to database ...")
with subprocess.Popen(["C.\My\Path\To\sqlplus.exe", "MyUser/MyPassword@whocares.com:1522/MyDataBase"], stdin=subprocess.PIPE, encoding='utf-8', env={"NLS_LANG": ".AL32UTF8"}) as p:
    p.stdin.write("set echo off newpage 0 pagesize 0 linesize 3000 feed off head off trimspool on \n")
    p.stdin.flush()

...

导致 sqlplus 失败并出现此错误:

SQL*Plus: Release 19.0.0.0.0 - Production on Fri Oct 16 15:24:37 2020
Version 19.8.0.0.0

Copyright (c) 1982, 2020, Oracle.  All rights reserved.

sgslunUDPNew: Unable to create communication endpoint
ERROR:
ORA-12154: TNS:could not resolve the connect identifier specified

打开子进程时省略环境变量但效果很好:

...


print("Connecting to database ...")
with subprocess.Popen(["C.\My\Path\To\sqlplus.exe", "MyUser/MyPassword@whocares.com:1522/MyDataBase"], stdin=subprocess.PIPE, encoding='utf-8') as p:
    p.stdin.write("set echo off newpage 0 pagesize 0 linesize 3000 feed off head off trimspool on \n")
    p.stdin.flush()

...

更有趣的是,我们设置哪个环境变量并不重要。但是,一旦我们将 any 环境变量传递给 python 中的 sqlplus 子进程,它就会崩溃。

我们不确定这是否与 python 或 sqlplus 或两者的组合有关,我们将不胜感激任何帮助。

就版本而言,我们使用 Windows 10SQL*Plus: Release 19.0.0.0.0 - Production Version 19.8.0.0.0Python 3.8.5

sgslunUDPNew:无法创建通信端点 错误: ORA-12154: 意味着 Oracle 网络层 (TNS) 尝试打开无效或禁止的端口使用 OS 网络库 - 这可能是包含端口的格式错误或错误编码字符串的结果 - 最后 TNS 报告错误传递给 SQL*Plus

所以 - 由于 SQLPLUS 可以启动,这为测试提供了机会

with subprocess.Popen(["C.\My\Path\To\sqlplus.exe << EOF connect MyUser/MyPassword@whocares.com:1522/MyDataBase EOF ",["" ], stdin=subprocess.PIPE, encoding='utf-8', env={"NLS_LANG": ".AL32UTF8"}) 作为 p:

请查看您使用 Unicode 时遇到的“不错”结果 - 那是我一周前发现的。最后我相信 SQL*Plus 可能无法在内部正确解码 unicode。将测试这些东西。

How to connect to database using QOCI or QODBC with correct encoding?

无论如何 - 为了获得通用性,考虑将 pyODBC 与 Oracle ODBC 驱动程序一起使用,它得到了官方支持 - 或者其他数据库的其他 ODBC

好的 - 稍微测试一下并让它工作

import subprocess, os

line = "SCOTT/tiger@xxx.xxx.xxx.xxx:yyyyy/sssss"    

# fails
# subprocess.run(["sqlplus.exe", line], env={"NLS_LANG": ".AL32UTF8"})

my_env = os.environ.copy()
my_env["NLS_LANG"] = ".AL32UTF8"

# works
# subprocess.run(["sqlplus.exe", line], env=my_env)

#adopting solution
print("Connecting to database ...")
with subprocess.Popen(["C:\ORACLE\IC\12201\instantclient_12_2\sqlplus.exe", "SCOTT/tiger@xxx.xxx.xxx.xxx:yyyyy/sssss"], stdin=subprocess.PIPE, encoding='utf-8', env=my_env) as p:
    p.stdin.write("set echo off newpage 0 pagesize 0 linesize 3000 feed off head off trimspool on \n")
    p.stdin.flush()

输出

Connecting to database ...

SQL*Plus: Release 12.2.0.1.0 Production on Sun Oct 18 00:07:22 2020

Copyright (c) 1982, 2016, Oracle.  All rights reserved.

Last Successful login time: Sun Oct 18 2020 00:04:57 +02:00

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Oracle Label Security, OLAP, Advanced Analytics
and Real Application Testing options

SQL> SQL> Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Oracle Label Security, OLAP, Advanced Analytics
and Real Application Testing options

最终使用 NLS_LANG 没有问题,因为即使是

subprocess.run(["sqlplus.exe", line], env={"A": "1"})

失败 - 你只需要创建一个像

这样的有效环境
my_env = os.environ.copy()
my_env["NLS_LANG"] = ".AL32UTF8"

并将其分配给喜欢的“env”

with subprocess.Popen( ..... , env=my_env)

弗兰克