2017-10-13 5 views
4

DBIパッケージのdbListTablesを使用して関数を記述しましたが、わかりませんが警告がスローされます。関数の外で同じコードを実行すると、警告メッセージが表示されません。dbListTablesは、関数を介して呼び出されたときに警告メッセージを表示するのはなぜですか? (R DBI)

情報として、使用されるデータベースはMicrosoft SQL Serverです。

再現例

library(odbc) 
library(DBI) 

# dbListTables in a function: gives a warning message 

dbListTablesTest <- function(dsn, userName, password){ 

    con <- dbConnect(
    odbc::odbc(), 
    dsn  = dsn, 
    UID  = userName, 
    PWD  = password, 
    Port  = 1433, 
    encoding = "latin1" 
) 

    availableTables <- dbListTables(con) 
} 

availableTables <- 
    dbListTablesTest(
    dsn = "myDsn" 
    ,userName = myLogin 
    ,password = myPassword 
) 

# dbListTables not within a function works fine (no warnings) 

con2 <- dbConnect(
    odbc::odbc(), 
    dsn  = "myDsn", 
    UID  = myLogin, 
    PWD  = myPassword, 
    Port  = 1433, 
    encoding = "latin1" 
) 

availableTables <- dbListTables(con2) 

(ちなみに、私はそれで作業した後、接続を閉じるにはdbDisconnectを使用する必要があり実現しています。しかし、それは同様の警告を投げているようだ。だから、簡単のために私がしましたdbDisconnectを省略。)

警告メッセージ

上記のコードを実行する場合、私は次の警告MESSAを得ます(関数を介して)最初のオプションを使用しているときにGeが、私は2番目のオプション(関数なし)を使用して取得しません。

warning messages from top-level task callback '1' 
Warning message: 
Could not notify connection observer. trying to get slot "info" from an object of a basic class ("character") with no slots 

警告は、上記の機能からその行を省略すると消えてしまうので、明らかにdbListTablesによって引き起こされます。

私の質問

  • なぜ私はこの警告メッセージを取得していますか?
  • もっと具体的には、私は関数を介してdbListTablesを呼び出すときにそれを取得するだけですか?
  • 私は間違っている/私はそれを避けるべきですか?任意の助けを事前に

私のセッション情報

R version 3.4.2 (2017-09-28) 
Platform: x86_64-w64-mingw32/x64 (64-bit) 
Running under: Windows 7 x64 (build 7601) Service Pack 1 

Matrix products: default 

locale: 
[1] LC_COLLATE=Dutch_Belgium.1252 LC_CTYPE=Dutch_Belgium.1252 LC_MONETARY=Dutch_Belgium.1252 LC_NUMERIC=C     LC_TIME=Dutch_Belgium.1252  

attached base packages: 
[1] stats  graphics grDevices utils  datasets tools  methods base  

other attached packages: 
[1] DBI_0.7 odbc_1.1.3 

loaded via a namespace (and not attached): 
[1] bit_1.1-12  compiler_3.4.2 hms_0.3  tibble_1.3.4 Rcpp_0.12.13 bit64_0.9-7 blob_1.1.0  rlang_0.1.2 

ありがとう!

+0

「dbGetQuery」を使用して同じ警告が表示されるため、これはより広い問題と思われます。 – JAD

答えて

4

TL:DRコールodbc::dbConnect他の機能の中でこの警告が発生します。

odbc githubで掘り起こした後、私は警告の原因を発見しました。 dbConnectを呼び出すと、db接続が作成されます。この関数内で、次のコードです:

# perform the connection notification at the top level, to ensure that it's had 
# a chance to get its external pointer connected, and so we can capture the 
# expression that created it 
if (!is.null(getOption("connectionObserver"))) { # nocov start 
    addTaskCallback(function(expr, ...) { 
    tryCatch({ 
     if (is.call(expr) && identical(expr[[1]], as.symbol("<-"))) { 
     # notify if this is an assignment we can replay 
     on_connection_opened(eval(expr[[2]]), paste(
      c("library(odbc)", deparse(expr)), collapse = "\n")) 
     } 
    }, error = function(e) { 
     warning("Could not notify connection observer. ", e$message, call. = FALSE) 
    }) 

    # always return false so the task callback is run at most once 
    FALSE 
    }) 
} # nocov end 

このwarning呼び出しはおなじみのはずです。これが警告を生成するものです。それでなぜそれができますか?

上記のスニペットは、すべてがうまくいったかどうかを確認するために、接続オブジェクトのチェックをいくつか試みようとしています。

これを行うには、これを「TaskCallBack」にチェックする機能を追加します。これは、top-level taskが完了した後に実行される関数のリストです。私はこれを100%確信しているわけではありませんが、私が知る限り、これはコールスタックの最高機能が終了した後でこれらの関数が実行されることを意味します。

通常、これはスクリプト内の行です。だから、たとえば、次の2行目の割り当てが終了した後

library(odbc) 
con <- odbc::dbConnect(odbc::odbc(), ...) 

、以下の機能が実行される:

function(expr, ...) { 
    tryCatch({ 
     if (is.call(expr) && identical(expr[[1]], as.symbol("<-"))) { 
     # notify if this is an assignment we can replay 
     on_connection_opened(eval(expr[[2]]), paste(
      c("library(odbc)", deparse(expr)), collapse = "\n")) 
     } 
    }, error = function(e) { 
     warning("Could not notify connection observer. ", e$message, call. = FALSE) 
    } 
} 

トップレベルの発現が、関数に渡されているかどうかを確認するために使用されます接続が動作します。別のodbcというファンクションは、on_connection_openedと呼ばれ、いくつかのチェックを行います。これにより、どこでもエラーがスローされた場合は、tryCatchのため警告が出されます。

なぜ、on_connection_opened機能がクラッシュするのですか?

機能は、次の引数を取ります。

on_connection_opened <- function(connection, code) 

とそれがない最初のものの一つは、次のとおりです。

をしよう:警告メッセージを一致させるように思わ

display_name <- [email protected]$dbname 

スロットなしの基本クラス( "文字")のオブジェクトからスロット "情報"を取得する

引数の名前から、関数on_connection_openedは、最初の引数にデータベース接続オブジェクトが必要であることが明らかです。その呼び出し元からは何が得られますか? eval(expr[[2]])

これは、元のコールの左側です:con

この場合、これは、接続オブジェクトであり、すべてがいいです。

今、私たちは、あなたの質問に答えるために十分な情報を持っている:

なぜ私はこの警告メッセージを取得していますか?

この関数は接続を作成します。接続により、チェック接続機能がキューに入れられます。次に、テーブルのリストをチェックし、それを返します。チェック接続機能は、テーブルのリストを接続のように解釈し、チェックしようとしますが、悲惨に失敗します。これにより警告がスローされます。

もっと具体的には、私は関数を介してdbListTablesを呼び出すときにそれを取得するだけですか?

dbListTablesは原因ではなく、dbConnectです。関数内から呼び出しているため、戻り値を確認しようとしている接続オブジェクトが取得されず失敗します。

私は間違っている/私はそれを避けるべきですか?

回避策は、接続を別々に開いて、その機能に渡すことです。このようにして、接続は独自の呼び出しで開かれるため、チェックは正常に動作します。

また、あなたは再びTaskCallbackを削除することができます

before <- getTaskCallbackNames() 
    con <- odbc::dbConnect(odbc::odbc(), ...) 
    after <- getTaskCallbackNames() 
    removeTaskCallback(which(!after %in% before)) 

が実行されているon_connection_opened不可欠ですか?それは何を正確にしていますか?

パッケージの作成者がthis comment on Githubで説明したように、この関数はRStudioの[接続]タブで接続の表示を処理します。同じ機能で接続をもう一度閉じると、これは面白いことではありません。したがって、これはあなたの機能にとって不可欠ではありません。

+0

これを理解してくれてありがとう!私が正しく理解していれば、これは本当に私のところでは誤りではない、それは正しい? 'addTaskCallBack'関数は何とか' on_connection_opened'に間違った式を使用していますか?これが本当に正しい場合は、これが近い将来修正されるかどうか考えていますか? – Willem

+0

@Willem Correct。私は、その機能への呼び出しが不可欠であるかどうかを判断するために、パッケージの内部動作について十分に知りません。私はバグレポートを提出するかもしれません。しかし、しばらくの間、接続を開いて関数に渡すと、すべてが正しく処理されます。 – JAD

+1

@Willem https://github.com/rstats-db/odbc/issues/122 – JAD

関連する問題