ParseException在Ubuntu上使用Python ODBC与Cloudera Impala ODBC驱动程序



我们有一个运行在AWS EC2实例(Amazon Linux)上的Python 3.7应用程序,它使用pyodbc(4.0.27)和ClouderaImpalaODBC驱动程序(使用ClouderaImpalaODBC-2.6.5.rpm安装)对ClouderaImpala服务执行SQL查询。此应用程序已成功运行多年。

我目前正试图让应用程序在运行Ubuntu 18.04.4 LTS的Docker容器中运行,但在运行最基本的查询(例如SELECT 'HELLO')时出现以下错误:

Error: ('HY000', '[HY000] [Cloudera][ImpalaODBC] (110) Error while executing a query in Impala: [HY000] : ParseException: Syntax error in line 1:\nufffdufffdufffdufffdufffdufffdufffd\n^\nEncountered: Unexpected character\nExpected: ALTER, COMMENT, COMPUTE, COPY, CREATE, DELETE, DESCRIBE, DROP, EXPLAIN, GRANT, INSERT, INVALIDATE, LOAD, REFRESH, REVOKE, SELECT, SET, SHOW, TRUNCATE, UPDATE, UPSERT, USE, VALUES, WITH\n\nCAUSED BY: Exception: Syntax error\n\x00u6572u3a64u5520u656eu7078u6365u6574\u2064u6863u7261u6361u6574u0a72 (110) (SQLExecDirectW)')"}

不用说,这看起来像一个字符串编码问题。

一些上下文管理:

  • 两个系统(Amazon Linux/Ubuntu)上的python代码是相同的
  • 两个系统上安装的Impala ODBC驱动程序具有相同的版本(2.6.5);Ubuntu的Impala ODBC驱动程序直接从Cloudera网站(https://www.cloudera.com/downloads/connectors/impala/odbc/2-6-5.html)下载
  • Impala ODBC连接参数是相同的,除了操作系统特定的项目:
    • "HOST"(主机),
    • "PORT" 21050
    • "Database"(数据库)
    • "UID"【用户名】">
    • "PWD"【密码】">
    • "Driver"{/opt/cloudera/impalaodbc/lib/64/libclouderaimpalaodbc64.so}">
    • "UseSASL" 1
    • "AuthMech" 3
    • "SSL" 1
    • "CAIssuedCertNamesMismatch" 1
    • "TrustedCerts"[path_to_certs_file]">
    • "TSaslTransportBufSize" 1000
    • "RowsFetchedPerBlock" 10000
    • "SocketTimeout" 0
    • "StringColumnLength" 32767
    • "UseNativeQuery" 0
  • 应用程序似乎成功连接到Impala,因为调用pyodbc.connect(**config, autocommit=True)或从连接中获取光标没有错误(已尝试使用无效的信用来确保,并在信用错误时获得通常的连接错误)。错误消息的详细信息表明正在使用正确的ODBC驱动程序

我试过用不同的值为Impala ODBC驱动程序参数&;drivermanagerencoding&;如"UTF-16";UTF-32"或者根本没有(这是Amazon Linux设置的情况),但总是得到相同的错误。

我还尝试在两个系统上使用odbclinux工具isql来尝试以这种方式进行故障排除;在Amazon Linux系统上可以成功连接,但是在Ubuntu系统上无法连接-始终得到以下提示(不确定这是相关的还是其他问题):

iusql -v [DSN]
[unixODBC][
[ISQL]ERROR: Could not SQLDriverConnect

找到了罪魁祸首——/opt/cloudera/impalaodbc/lib/64/cloudera.impalaodbc.iniDriverManagerEncoding的设置:

[Driver]
## - Note that this default DriverManagerEncoding of UTF-32 is for iODBC.
## - unixODBC uses UTF-16 by default.
## - If unixODBC was compiled with -DSQL_WCHART_CONVERT, then UTF-32 is the correct value.
##   Execute 'odbc_config --cflags' to determine if you need UTF-32 or UTF-16 on unixODBC
## - SimbaDM can be used with UTF-8 or UTF-16.
##   The DriverUnicodeEncoding setting will cause SimbaDM to run in UTF-8 when set to 2 or UTF-16 when set to 1.
DriverManagerEncoding=UTF-32
ErrorMessagesPath=/opt/cloudera/impalaodbc/ErrorMessages/
LogLevel=0
LogPath=
SwapFilePath=/tmp

## - Uncomment the ODBCInstLib corresponding to the Driver Manager being used.
## - Note that the path to your ODBC Driver Manager must be specified in LD_LIBRARY_PATH (LIBPATH for AIX).
## - Note that AIX has a different format for specifying its shared libraries.
# Generic ODBCInstLib
#   iODBC
# ODBCInstLib=libiodbcinst.so
#   SimbaDM / unixODBC
#ODBCInstLib=libodbcinst.so
# AIX specific ODBCInstLib
#   iODBC
#ODBCInstLib=libiodbcinst.a(libiodbcinst.so.2)
#   SimbaDM
#ODBCInstLib=libodbcinst.a(odbcinst.so)
#   unixODBC
ODBCInstLib=libodbcinst.a(libodbcinst.so.1)

该文件是作为驱动程序安装的一部分自动生成的。注意关于iODBC和unixODBC的注释——我们只安装了后者。

一旦我注释掉这个配置,我们的python应用就可以工作了。它还修复了iusql的问题(它是unixODBC安装的一部分)。

附加内容:

我也遇到了iqsl(不是iusql)的问题-isql -v [DSN]命令的错误/输出:

[S1000][unixODBC][Cloudera][ODBC] (11560) Unable to locate SQLGetPrivateProfileString function.
[ISQL]ERROR: Could not SQLConnect

错误与同一个ini文件中的配置参数ODBCInstLib有关。一旦我将它从默认的libodbcinst.a(libodbcinst.so.1)更改为/usr/lib/x86_64-linux-gnu/libodbcinst.so,它就工作了。在这篇文章中找到了答案,它实际上帮助解决了我最初的问题:

Can't connect to snowflake通过unixODBC错误:[S1000][unixODBC][Snowflake][ODBC] (11560) Unable to locate SQLGetPrivateProfileString function

最新更新