Skip to content

Commit

Permalink
Merge pull request #422 from r-dbi/unquote
Browse files Browse the repository at this point in the history
  • Loading branch information
krlmlr committed Dec 20, 2023
2 parents 62056e2 + 3e74e02 commit 69f3ae3
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 68 deletions.
10 changes: 3 additions & 7 deletions R/dbUnquoteIdentifier.R
Expand Up @@ -26,21 +26,17 @@
#'
#' # The returned object is always a list,
#' # also for Id objects
#' dbUnquoteIdentifier(
#' ANSI(),
#' Id(catalog = "Catalog", schema = "Schema", table = "Table")
#' )
#' dbUnquoteIdentifier(ANSI(), Id("Catalog", "Schema", "Table"))
#'
#' # Quoting is the inverse operation to unquoting the elements
#' # of the returned list
#' # Quoting and unquoting are inverses
#' dbQuoteIdentifier(
#' ANSI(),
#' dbUnquoteIdentifier(ANSI(), SQL("UnqualifiedTable"))[[1]]
#' )
#'
#' dbQuoteIdentifier(
#' ANSI(),
#' dbUnquoteIdentifier(ANSI(), Id(schema = "Schema", table = "Table"))[[1]]
#' dbUnquoteIdentifier(ANSI(), Id("Schema", "Table"))[[1]]
#' )
setGeneric("dbUnquoteIdentifier",
def = function(conn, x, ...) standardGeneric("dbUnquoteIdentifier")
Expand Down
60 changes: 26 additions & 34 deletions R/dbUnquoteIdentifier_DBIConnection.R
@@ -1,45 +1,37 @@
#' @rdname hidden_aliases
#' @usage NULL
dbUnquoteIdentifier_DBIConnection <- function(conn, x, ...) {
if (is(x, "SQL")) {
id_rx <- '(?:"((?:[^"]|"")+)"|([^". ]+))'
# Determine quoting character
quote_char <- substr(dbQuoteIdentifier(conn, ""), 1, 1)

rx <- paste0(
"^",
"(?:|(?:|", id_rx, "[.])",
id_rx, "[.])",
"(?:|", id_rx, ")",
"$"
)
if (is(x, "SQL") || is.character(x)) {
x <- lapply(x, unquote, quote_char = quote_char)
lapply(x, Id)
} else if (is(x, "Id")) {
list(x)
} else {
stop("x must be SQL, Id, or character", call. = FALSE)
}
}

bad <- grep(rx, x, invert = TRUE)
if (length(bad) > 0) {
stop("Can't unquote ", x[bad[[1]]], call. = FALSE)
}
catalog <- gsub(rx, "\\1\\2", x)
catalog <- gsub('""', '"', catalog)
schema <- gsub(rx, "\\3\\4", x)
schema <- gsub('""', '"', schema)
table <- gsub(rx, "\\5\\6", x)
table <- gsub('""', '"', table)
unquote <- function(x, quote_char) {
# replace doubled quotes with escaped quote
gsub <- gsub(
pattern = paste0(quote_char, quote_char),
replacement = paste0("\\", quote_char),
x
)

ret <- Map(catalog, schema, table, f = as_table)
names(ret) <- names(x)
return(ret)
}
if (is(x, "Id")) {
return(list(x))
}
stop("x must be SQL or Id", call. = FALSE)
scan(
text = x,
what = character(),
quote = quote_char,
quiet = TRUE,
na.strings = character(),
sep = "."
)
}

#' @rdname hidden_aliases
#' @export
setMethod("dbUnquoteIdentifier", signature("DBIConnection"), dbUnquoteIdentifier_DBIConnection)

as_table <- function(catalog, schema, table) {
args <- c(catalog = catalog, schema = schema, table = table)
# Also omits NA args
args <- args[!is.na(args) & args != ""]
do.call(Id, as.list(args))
}
10 changes: 3 additions & 7 deletions man/dbUnquoteIdentifier.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions tests/testthat/test-dbUnquoteIdentifier_DBIConnection.R
@@ -0,0 +1,20 @@
test_that("can unquote any number of components", {
expect_equal(dbUnquoteIdentifier(ANSI(), "a"), list(Id("a")))
expect_equal(dbUnquoteIdentifier(ANSI(), "a.b"), list(Id("a", "b")))
expect_equal(dbUnquoteIdentifier(ANSI(), "a.b.c"), list(Id("a", "b", "c")))
expect_equal(dbUnquoteIdentifier(ANSI(), "a.b.c.d"), list(Id("a", "b", "c", "d")))
})

test_that("can unquote any quoted components", {
expect_equal(dbUnquoteIdentifier(ANSI(), '"a.b"'), list(Id("a.b")))

expect_equal(dbUnquoteIdentifier(ANSI(), 'a."b"'), list(Id("a", "b")))
expect_equal(dbUnquoteIdentifier(ANSI(), '"a".b'), list(Id("a", "b")))
expect_equal(dbUnquoteIdentifier(ANSI(), '"a"."b"'), list(Id("a", "b")))

expect_equal(dbUnquoteIdentifier(ANSI(), '"a"""."b"""'), list(Id('a"', 'b"')))
})

test_that("Id is unchanged and wrapped in list", {
expect_equal(dbUnquoteIdentifier(ANSI(), Id("foo")), list(Id("foo")))
})
20 changes: 0 additions & 20 deletions tests/testthat/test-quote.R
Expand Up @@ -28,23 +28,3 @@ test_that("unquote Id", {
expect_equal(dbUnquoteIdentifier(ANSI(), Id(table = "a", schema = "b", catalog = "c")),
list(Id(table = "a", schema = "b", catalog = "c")))
})

test_that("unquote SQL", {
expect_equal(dbUnquoteIdentifier(ANSI(), SQL('"a"')), list(Id(table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL("a")), list(Id(table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL('"b"."a"')), list(Id(schema = "b", table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL("b.a")), list(Id(schema = "b", table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL('"c"."b"."a"')),
list(Id(catalog = "c", schema = "b", table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL('"c"."b"."a"')),
list(Id(catalog = "c", schema = "b", table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL("c.b.a")),
list(Id(catalog = "c", schema = "b", table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL('"c"."b.d"."a"')),
list(Id(catalog = "c", schema = "b.d", table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL('c."b""d".a')),
list(Id(catalog = "c", schema = 'b"d', table = "a")))
expect_equal(dbUnquoteIdentifier(ANSI(), SQL(c('"Catalog"."Schema"."Table"', '"UnqualifiedTable"'))),
list(Id(catalog = "Catalog", schema = "Schema", table = "Table"),
Id(table = "UnqualifiedTable")))
})

0 comments on commit 69f3ae3

Please sign in to comment.