Print sql statement craeted by DBI::dbBind

前端 未结 1 870
春和景丽
春和景丽 2021-01-22 08:15

I want to print the sql syntax created with DBI::dbBind while creating safe parametrized query:

conn <- #create connection 
stmt <- \"select * from dbo.myt         


        
相关标签:
1条回答
  • 2021-01-22 09:07

    I'll formalize my comment into an answer.

    "Binding" does not change the query, it merely "augments" a query with objects that are treated solely as data, vice intermingled with code.

    The latter intermingling can be problematic for a few reasons:

    1. Malevolent code deploying "SQL Injection" (https://xkcd.com/327/, and a wiki explanation). In short, it takes advantage of closing out a quoted string or literal and executing SQL code directly, perhaps to delete or modify data, perhaps to extract data.

    2. Innocently enough, if the "data" you add to the query contains quotes that are not escaped properly, you could inadvertently perform your own SQL injection, though perhaps less likely to do as "Bad Things" as #1 would do.

    3. Optimization of SQL code. Most DBMSes will analyze and optimize a SQL query so that it performs better, takes advantage of keys, etc. They often remember queries, so that a repeated query does not need to be re-analyzed, saving time. If you intermingle data/parameters in with the raw SQL query text, then when you change one thing about it (even just one digit in a parameter), the DBMS will likely need to re-analyze the query. Inefficient.

    There are functions that facilitate escaping or quoting literals and strings, and if you feel you must put literals in your SQL query, then I urge you to use them. These include (but are not limited to) DBI::dbQuoteString, DBI::dbQuoteLiteral, and DBI::dbQuoteIdentifier.

    Another such function is glue::glue_sql, which handles correct quoting/escaping of literals and identifiers, to "make[s] constructing SQL statements safe and easy" (quoted from the github repo). This is "just" string interpolation, so while it should protect you just fine against #1 and #2 above, it does not necessarily permit/encourage #3.

    (It only takes one mis-quoting to remind you which is used where for your particular DBMS.)

    For the record, binding is rather simple, as provided in its documentation:

    iris_result <- dbSendQuery(con, "SELECT * FROM iris WHERE [Petal.Width] > ?")
    dbBind(iris_result, list(2.3))
    results <- dbFetch(iris_result)
    

    If you want, you can re-use the same res (at least in some DBMSes, not tested on all), as in

    # same iris_result as above
    dbBind(iris_result, list(2.5))
    dbFetch(iris_result)
    dbBind(iris_result, list(3))
    dbFetch(iris_result)
    dbBind(iris_result, list(3.2))
    dbFetch(iris_result)
    

    As many times as you need, ultimately finishing with

    DBI::dbClearResult(iris_result)
    
    0 讨论(0)
提交回复
热议问题