【发布时间】:2018-04-18 21:34:20
【问题描述】:
我正在构建一个函数来连接到一个特定的受密码保护的 ODBC 数据源,该数据源将被团队中的许多成员使用 - 它可以在多个环境中使用。如果连接被拒绝,我想显示警告消息但屏蔽显示的密码。如果我使用suppressWarnings(),据我所知,没有任何内容被捕获,如果我不使用,则该消息将显示在标准输出中并带有密码。到目前为止的功能如下:
connectToData <- function(uid, pswd, dsn='myDSN') {
# Function to connect to myDSN data
#
# Args:
# uid: The user's ID for connecting to the database
# pswd: The user's password for connecting to the database.
# dsn: The DSN for the (already existing) ODBC connection to the 5G
# data. It must be set up on an individual Windows user's machine,
# and they could use any name for it. The default is 'myDSN'
#
# Returns:
# The 'RODBC' class object returned by the RODBC:odbcConnect() function.
#
# TODO: 1) See if you can specify the connection using odbcDriverConnect()
# so as to not rely on user's ODBC connections
# 2) Capture warnings from odbcConnect() and print them while
# disguising password using gsub, as I've attempted to do below.
library('RODBC')
db.conn <- odbcConnect(dsn,
uid=uid,
pwd=pswd)
if(class(db.conn) != 'RODBC') { # Error handling for connections that don't make it
print(gsub(pswd,'******',warnings())) # This doesn't work like I want it to
stop("ODBC connection could not be opened. See warnings()")
} else {
return(db.conn)
}
}
当我使用正确的用户名/密码运行它时,我会得到正确的结果,但是当我使用错误的密码运行它时,我会得到:
> db.conn <- connectTo5G(uid='myID',pswd='badpassword', dsn='myDSN')
[1] "RODBC::odbcDriverConnect(\"DSN=myDSN;UID=myID;PWD=******\")"
[2] "RODBC::odbcDriverConnect(\"DSN=myDSN;UID=myID;PWD=******\")"
Error in connectTo5G(uid = "myID", pswd = "badpassword", dsn = "myDSN") :
ODBC connection could not be opened. See warnings()
In addition: Warning messages:
1: In RODBC::odbcDriverConnect("DSN=myDSN;UID=myID;PWD=badpassword") :
[RODBC] ERROR: state 28000, code 1017, message [Oracle][ODBC][Ora]ORA-01017: invalid username/password; logon denied
2: In RODBC::odbcDriverConnect("DSN=myDSN;UID=myID;PWD=badpassword") :
ODBC connection failed
print(gsub(...)) 似乎可以处理调用函数之前的最新警告,并且它也只打印产生警告的函数调用,而不是警告的文本。
我想做的是在“另外:警告消息:”之后捕获所有内容,以便我可以在上面使用gsub(),但避免在gsub() 有机会处理它之前打印它。我想我需要使用withCallingHandlers(),但我查看了文档和示例,但我无法弄清楚。
一些额外的背景:这是一个 Oracle 数据库,它会在用户尝试连接三次后锁定用户,所以我想使用 stop(),以防有人编写多次调用此函数的代码。我小组中的不同用户同时在 Windows 和 Linux 中工作(有时来回切换),因此任何解决方案都需要灵活。
【问题讨论】:
-
也许更传统的错误处理工具在这里会更好用,比如
tryCatch? (小点,inherits()通常是检查对象 S3 类向量的首选习惯用法,而不是==或!=) -
this 是否有助于弄清楚如何使用
withCallingHandlers来捕获错误和警告? -
谢谢,@joran。我最终使用了
inherits(),但使用了TryCatch(),如下面@JonGrub 的回答。