From bf52b737e2303f3871e57daca6a868767e114c1f Mon Sep 17 00:00:00 2001 From: Alexander Bessonov Date: Thu, 20 Mar 2014 10:56:51 +0400 Subject: [PATCH 01/28] Link to prebuilt package --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8669b92..5c2dea9 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,5 @@ teradataR R package to perform in-database analytics using Teradata database. Compatible with both R version 2 and 3. + +Prebuilt package could be found [here](https://github.com/Teradata/teradataR/raw/master/build/teradataR_1.1.0.tar.gz). From 116ede57695a797a34e37d95cf1a882a4ba2fce9 Mon Sep 17 00:00:00 2001 From: Alexander Bessonov Date: Thu, 20 Mar 2014 12:11:56 +0400 Subject: [PATCH 02/28] Installation howto --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 5c2dea9..2f56fa2 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,16 @@ R package to perform in-database analytics using Teradata database. Compatible with both R version 2 and 3. Prebuilt package could be found [here](https://github.com/Teradata/teradataR/raw/master/build/teradataR_1.1.0.tar.gz). + +## Dependencies + ++ RJDBC + + rJava ++ RODBC + +## Installation + +To install the package, issue the following command from R REPL: + install.packages("C:\\Documents and Settings\\User\\My Documents\\Downloads\\teradataR_1.1.0.tar.gz", repos=NULL,type="source"); +Where first argument is the path to the package file. + From 600c6971dbb69531c4b197c1c6a3ebea11f75545 Mon Sep 17 00:00:00 2001 From: Alexander Bessonov Date: Thu, 20 Mar 2014 12:15:04 +0400 Subject: [PATCH 03/28] Readme fix --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2f56fa2..e0be237 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Prebuilt package could be found [here](https://github.com/Teradata/teradataR/raw ## Installation To install the package, issue the following command from R REPL: + install.packages("C:\\Documents and Settings\\User\\My Documents\\Downloads\\teradataR_1.1.0.tar.gz", repos=NULL,type="source"); + Where first argument is the path to the package file. From 2d285e4df67eaa28f4d2932f1e797bbd4d686ec9 Mon Sep 17 00:00:00 2001 From: Alexander Bessonov Date: Mon, 16 Jun 2014 13:39:22 +0400 Subject: [PATCH 04/28] Added DISTINCT to have "sparced" sample --- R/td.kmeans.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/td.kmeans.R b/R/td.kmeans.R index 345f630..d49ab3f 100755 --- a/R/td.kmeans.R +++ b/R/td.kmeans.R @@ -16,7 +16,7 @@ td.kmeans <- function(x, centers, iter.max = 10, nstart = 1) { nms <- paste(gettextf("\"%s\"", names(x)), collapse = ",") maxD <- 0 for (i in 1:nstart) { - testClusters <- tdQuery(gettextf("SELECT %s FROM %s %s SAMPLE %d", nms, obj, wc, centers)) + testClusters <- tdQuery(gettextf("SELECT DISTINCT %s FROM %s %s SAMPLE %d", nms, obj, wc, centers)) curD <- 0 for (j in 1:centers - 1) { for (k in (j + 1):centers) curD <- curD + sum(dist(testClusters[c(j, k), ])) From aafda0666acd8b0700e73af852e86b7b29ca277a Mon Sep 17 00:00:00 2001 From: Alexander Bessonov Date: Mon, 30 Jun 2014 01:11:23 +0400 Subject: [PATCH 05/28] Removed Dependency from DESCRIPTION --- DESCRIPTION | 8 +++++--- build/teradataR_1.1.0.tar.gz | Bin 213429 -> 321459 bytes 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index acf84c1..c422b9e 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,11 +2,13 @@ Package: teradataR Type: Package Title: Teradata R Package Version: 1.1.0 -Date: 2013-08-01 +Date: 2014-06-29 Author: Todd Brye Maintainer: Alexander Bessonov -Depends: R (>= 2.11.0), RJDBC, RODBC +Depends: R (>= 2.11.0) +Suggests: RODBC (>= 1.3-9), RJDBC (>= 0.2-1) Description: This package allows you you access a Teradata database using the R language. It allows programmers familiar with R to analyze Teradata objects a lot like they would access a data frame object. License: GPL (>= 2) LazyLoad: yes -Packaged: 2013-08-01 15:36:00 UTC; nonsleepr +Packaged: 2014-06-29 00:33:50 MSK; nonsleepr + diff --git a/build/teradataR_1.1.0.tar.gz b/build/teradataR_1.1.0.tar.gz index 6fea732df69db6ece640efddda7790dcb6593114..3296158256672032aff59a3c34792a22e530ef52 100644 GIT binary patch delta 125457 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 delta 16573 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 From e64947df38b18f0ab64a7543718cd60570e931b8 Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 13:38:01 -0700 Subject: [PATCH 06/28] testing push --- R/RPAD.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/RPAD.R b/R/RPAD.R index e63d32a..3fc2fd6 100755 --- a/R/RPAD.R +++ b/R/RPAD.R @@ -4,7 +4,7 @@ RPAD <- function(x, ilength, fill_string = " ") { return(x) } - rfmt <- "RPAD(%s,%d,%s)" + rfmt <- "RPAD(\"%s\",%d,\'%s\')" if (inherits(x, "td.data.frame")) { if (length(x) == 1) { if (!is.null(attr(x, "expressions"))) @@ -20,6 +20,6 @@ RPAD <- function(x, ilength, fill_string = " ") { } if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("RPAD(", x, ",", ilength, ",", fill_string, ")", sep = ""))) + return(asTdExpr(paste("RPAD(\"", x, "\",", ilength, ",", fill_string, ")", sep = ""))) } } From b340555ae1c00ec3515331638865a8e0c39aac7b Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 14:37:58 -0700 Subject: [PATCH 07/28] committing all changes made to teradataR package --- R/CEIL.R | 2 +- R/CHR.R | 7 ---- R/DECODE.R | 48 +++++++++++++++++--------- R/INITCAP.R | 17 ++++++++++ R/INSTR.R | 12 ++----- R/INTCAP.R | 21 ------------ R/LPAD.R | 8 +++-- R/LTRIM.R | 17 +++------- R/NGRAM.R | 38 ++++++++++++--------- R/OREPLACE.R | 32 ++++++++++++------ R/OTRANSLATE.R | 38 +++++++++++++-------- R/RTRIM.R | 15 +++------ R/as.td.data.frame.R | 3 +- R/on.R | 41 ++++++++++++++++++++++ R/td.CalcMatrix.R | 10 ++++++ R/td.ExecR.R | 10 ++++++ R/td.data.frame.R | 2 +- R/tdQuery.R | 2 +- R/teradataR-internal.R | 43 +++++++++++++++++++++++ man/INITCAP.Rd | 46 +++++++++++++++++++++++++ man/LPAD.Rd | 51 ++++++++++++++++++++++++++++ man/LTRIM.Rd | 47 ++++++++++++++++++++++++++ man/RPAD.Rd | 52 ++++++++++++++++++++++++++++ man/RTRIM.Rd | 46 +++++++++++++++++++++++++ man/on.Rd | 73 +++++++++++++++++++++++++++++++++++++++ man/td.CalcMatrix.Rd | 70 ++++++++++++++++++++++++++++++++++++++ man/td.ExecR.Rd | 64 +++++++++++++++++++++++++++++++++++ test/.DS_Store | Bin 0 -> 6148 bytes test/basicContract.txt | 1 + test/basicOperator.txt | 1 + test/testCHR.R | 22 ++++++++++++ test/testCalcMatrix.R | 66 ++++++++++++++++++++++++++++++++++++ test/testDECODE.R | 3 ++ test/testExecR.R | 75 +++++++++++++++++++++++++++++++++++++++++ test/testINITCAP.R | 20 +++++++++++ test/testINSTR.R | 24 +++++++++++++ test/testLPAD.R | 20 +++++++++++ test/testLTRIM.R | 19 +++++++++++ test/testNGRAM.R | 19 +++++++++++ test/testOREPLACE.R | 24 +++++++++++++ test/testOTRANSLATE.R | 20 +++++++++++ test/testOn.R | 31 +++++++++++++++++ test/testRPAD.R | 20 +++++++++++ test/testRTRIM.R | 17 ++++++++++ test/testUtil.R | 25 ++++++++++++++ test/testtoQuery.R | 1 + 46 files changed, 1102 insertions(+), 121 deletions(-) create mode 100755 R/INITCAP.R delete mode 100755 R/INTCAP.R create mode 100755 R/on.R create mode 100755 R/td.CalcMatrix.R create mode 100755 R/td.ExecR.R create mode 100644 man/INITCAP.Rd create mode 100644 man/LPAD.Rd create mode 100644 man/LTRIM.Rd create mode 100644 man/RPAD.Rd create mode 100644 man/RTRIM.Rd create mode 100644 man/on.Rd create mode 100644 man/td.CalcMatrix.Rd create mode 100644 man/td.ExecR.Rd create mode 100644 test/.DS_Store create mode 100755 test/basicContract.txt create mode 100755 test/basicOperator.txt create mode 100644 test/testCHR.R create mode 100755 test/testCalcMatrix.R create mode 100644 test/testDECODE.R create mode 100755 test/testExecR.R create mode 100644 test/testINITCAP.R create mode 100644 test/testINSTR.R create mode 100644 test/testLPAD.R create mode 100644 test/testLTRIM.R create mode 100644 test/testNGRAM.R create mode 100644 test/testOREPLACE.R create mode 100644 test/testOTRANSLATE.R create mode 100644 test/testOn.R create mode 100644 test/testRPAD.R create mode 100644 test/testRTRIM.R create mode 100755 test/testUtil.R create mode 100644 test/testtoQuery.R diff --git a/R/CEIL.R b/R/CEIL.R index bd534aa..04aeceb 100755 --- a/R/CEIL.R +++ b/R/CEIL.R @@ -7,7 +7,7 @@ CEIL <- function(x) { } else if (inherits(x, "td.expression") || inherits(x, "numeric")) val <- paste("CEIL(", x, ")", sep = "") else if (inherits(x, "character")) val <- paste("CEIL('", x, "')", sep = "") else stop("Invalid data type for 'x' in CEIL function") - + class(val) <- "td.expression" return(val) } diff --git a/R/CHR.R b/R/CHR.R index d436992..acb15e8 100755 --- a/R/CHR.R +++ b/R/CHR.R @@ -11,10 +11,3 @@ CHR <- function(x) { class(val) <- "td.expression" return(val) } - -# CHR <- function(x) { if(inherits(x, 'td.data.frame')) { if(length(x) == 1) if(!is.null(attr(x, 'expressions'))) { val -# <- paste('CHR(', attr(x, 'expressions')[[names(x)]], ')', sep='') class(val) <- 'td.expression' return(val) } else { -# val <- paste('CHR(\'', names(x), '\')', sep='') class(val) <- 'td.expression' return(val) } else { message('CHR -# warning: td.data.frame 'x' has length > 1 using first element') val <- paste('CHR(\'', names(x)[1], '\')', sep='') -# class(val) <- 'td.expression' return(val) } } if(inherits(x, 'numeric') || inherits(x, 'character') || -# inherits(x,'td.expression')) { val <- paste('CHR(', x, ')', sep='') class(val) <- 'td.expression' return(val) } } diff --git a/R/DECODE.R b/R/DECODE.R index e52c539..506e255 100755 --- a/R/DECODE.R +++ b/R/DECODE.R @@ -1,22 +1,40 @@ -DECODE <- function(x, ...) { - parms <- list(...) - for (i in 1:length(parms)) { - if (is.character(parms[[i]])) - parms[[i]] <- paste("'", parms[[i]], "'", sep = "") +DECODE <- function(x, default=NULL, ...) { + simplePaste <- function(i) { + if(inherits(i, "numeric")) { + res <- as.numeric(paste(i)) + } + else { + res <- paste("'",i,"'", collapse=none) + print(nchar(res, type="chars")) + } + return(res) } - plist <- paste(parms, collapse = ",") - + params <- list(...) + #print(parms[[2]]) + #plist <- unlist(parms) + #return("DECODE(c1, 1, \'A\', 2,\'B\')" ) + res <- lapply(params, simplePaste) + res <- paste(res, collapse=",") + print(res) if (inherits(x, "td.data.frame")) { - if (length(x) > 1) + if (length(x) > 1) { message("DECODE warning: td.data.frame 'x' has length > 1 using first element") + } - val <- paste("DECODE(", .td.gencolumnexpr(x[1]), ",", plist, ")", sep = "") - } else if (inherits(x, "td.expression") || inherits(x, "numeric")) - val <- paste("DECODE(", x, ",", plist, ")", sep = "") else if (inherits(x, "character")) - val <- paste("DECODE('", x, "'", ",", plist, ")", sep = "") else stop("Invalid data type for 'x' in DECODE function") - - class(val) <- "td.expression" - return(val) + + #print(res) + val <- paste("DECODE(", .td.gencolumnexpr(x[1]), ",", res, ")", sep = "") + } + else if (inherits(x, "td.expression") || inherits(x, "numeric")) { + val <- paste("DECODE(", x, ",", res, ")", sep = "") + } + else if (inherits(x, "character")) { + val <- paste("DECODE('", x, "'", ",", lapply(params, simplePaste), ")", sep = "") + } + else stop("Invalid data type for 'x' in DECODE function") + + class(val) <- "td.expression" + return(val) } # DECODE <- function(x, ...) { parms <- list(...) for(i in 1:length(parms)) { if(is.character(parms[[i]])) parms[[i]] diff --git a/R/INITCAP.R b/R/INITCAP.R new file mode 100755 index 0000000..4d4cb6a --- /dev/null +++ b/R/INITCAP.R @@ -0,0 +1,17 @@ +INITCAP <- function(x) { + #handles condition in which x is a td data frame + if (inherits(x, "td.data.frame")) { + if (length(x) > 1) + message("INITCAP warning: td.data.frame 'x' has length > 1 using first element") + + #sets up query expression + val <- paste("INITCAP(", .td.gencolumnexpr(x[1]), ")", sep = "") + #handles condition in which x is a td expression or numeric + } + else if (inherits(x, "td.expression") || inherits(x, "numeric") || inherits(x, "character")) + val <- paste("INITCAP(", x, ")", sep = "") + else stop("Invalid data type for 'x' in INITCAP function") + + class(val) <- "td.expression" + return(val) +} \ No newline at end of file diff --git a/R/INSTR.R b/R/INSTR.R index 1e61ca6..8ad03fe 100755 --- a/R/INSTR.R +++ b/R/INSTR.R @@ -1,4 +1,5 @@ INSTR <- function(x, y) { + # check type of x if (inherits(x, "td.data.frame")) { if (length(x) > 1) message("INSTR warning: td.data.frame 'x' has length > 1 using first element") @@ -8,6 +9,7 @@ INSTR <- function(x, y) { xval <- x else if (inherits(x, "character")) xval <- paste("'", x, "'", sep = "") else stop("Invalid data type for 'x' in INSTR function") + # check type of y if (inherits(y, "td.data.frame")) { if (length(y) > 1) message("INSTR warning: td.data.frame 'y' has length > 1 using first element") @@ -22,12 +24,4 @@ INSTR <- function(x, y) { class(val) <- "td.expression" return(val) -} - - -# INSTR <- function(x, search_string=' ') { asTdExpr <- function(x) {class(x) <- 'td.expression'; return(x)} ifmt <- -# 'INSTR(%s,%s)' if(inherits(x, 'td.data.frame')) { if(length(x) == 1) { if(!is.null(attr(x, 'expressions'))) val <- -# attr(x, 'expressions')[[names(x)]] else val <- names(x) } else { message('INSTR warning: td.data.frame 'x' has length -# > 1 using first element') val <- names(x)[1] } return(asTdExpr(gettextf(ifmt, val, search_string))) } if(inherits(x, -# 'character') || inherits(x,'td.expression')) { return(asTdExpr(paste('INSTR(', x, ',', search_string, ')', sep=''))) -# } } +} \ No newline at end of file diff --git a/R/INTCAP.R b/R/INTCAP.R deleted file mode 100755 index 2139d7d..0000000 --- a/R/INTCAP.R +++ /dev/null @@ -1,21 +0,0 @@ -INTCAP <- function(x) { - if (inherits(x, "td.data.frame")) { - if (length(x) > 1) - message("INTCAP warning: td.data.frame 'x' has length > 1 using first element") - - val <- paste("INTCAP(", .td.gencolumnexpr(x[1]), ")", sep = "") - } else if (inherits(x, "td.expression") || inherits(x, "numeric")) - val <- paste("INTCAP(", x, ")", sep = "") else if (inherits(x, "character")) - val <- paste("INTCAP('", x, "')", sep = "") else stop("Invalid data type for 'x' in INTCAP function") - - class(val) <- "td.expression" - return(val) -} - - -# INTCAP <- function(x) { asTdExpr <- function(x) {class(x) <- 'td.expression'; return(x)} if(inherits(x, -# 'td.data.frame')) { if(length(x) == 1) if(!is.null(attr(x, 'expressions'))) return(asTdExpr(paste('INTCAP(', attr(x, -# 'expressions')[[names(x)]], ')', sep=''))) else return(asTdExpr(paste('INTCAP(\'', names(x), '\')', sep=''))) else -# { message('INTCAP warning: td.data.frame 'x' has length > 1 using first element') return(asTdExpr(paste('INTCAP(\'', -# names(x)[1], '\')', sep=''))) } } if(inherits(x, 'character') || inherits(x,'td.expression')) { -# return(asTdExpr(paste('INTCAP(', x, ')', sep=''))) } } diff --git a/R/LPAD.R b/R/LPAD.R index 9079c0f..f8827b1 100755 --- a/R/LPAD.R +++ b/R/LPAD.R @@ -1,10 +1,12 @@ LPAD <- function(x, ilength, fill_string = " ") { + #helper function to make sure input value is of correct type asTdExpr <- function(x) { class(x) <- "td.expression" return(x) } - lfmt <- "LPAD(%s,%d,%s)" + lfmt <- "LPAD(\"%s\",%d,\'%s\')" + #handles conditions in which x is a td data frame if (inherits(x, "td.data.frame")) { if (length(x) == 1) { if (!is.null(attr(x, "expressions"))) @@ -18,8 +20,8 @@ LPAD <- function(x, ilength, fill_string = " ") { return(asTdExpr(gettextf(lfmt, val, ilength, fill_string))) } - + #handles conditions in which x is a character or td expression if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("LPAD(", x, ",", ilength, ",", fill_string, ")", sep = ""))) + return(asTdExpr(paste("LPAD(\"", x, "\",", ilength, ",", fill_string, ")", sep = " "))) } } diff --git a/R/LTRIM.R b/R/LTRIM.R index c10d169..8b60d73 100755 --- a/R/LTRIM.R +++ b/R/LTRIM.R @@ -1,11 +1,11 @@ -LTRIM <- function(x, rstring = " ") { +LTRIM <- function(x) { asTdExpr <- function(x) { class(x) <- "td.expression" return(x) } - lfmt <- "LTRIM(%s,%s)" - if (inherits(x, "td.data.frame")) { + lfmt <- "LTRIM(%s)" + if (length(x) == 1) { if (!is.null(attr(x, "expressions"))) val <- attr(x, "expressions")[[names(x)]] else val <- names(x) @@ -14,12 +14,5 @@ LTRIM <- function(x, rstring = " ") { message("LTRIM warning: td.data.frame 'x' has length > 1 using first element") val <- names(x)[1] } - - return(asTdExpr(gettextf(lfmt, val, rstring))) - - } - - if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("LTRIM(", x, ",", fill_string, ")", sep = ""))) - } -} + return(asTdExpr(gettextf(lfmt, val))) +} diff --git a/R/NGRAM.R b/R/NGRAM.R index 06c4e30..c474ada 100755 --- a/R/NGRAM.R +++ b/R/NGRAM.R @@ -1,25 +1,33 @@ -NGRAM <- function(x, second_string, gram_length) { +NGRAM <- function(x, y, gram_length) { + #helper function acts as a setter for class td.expression asTdExpr <- function(x) { class(x) <- "td.expression" return(x) } - + #set up base text ofmt <- "NGRAM(%s,%s,%d)" - if (inherits(x, "td.data.frame")) { - if (length(x) == 1) { - if (!is.null(attr(x, "expressions"))) - val <- attr(x, "expressions")[[names(x)]] else val <- names(x) - - } else { - message("NGRAM warning: td.data.frame 'x' has length > 1 using first element") - val <- names(x)[1] + #determine datatype of parameters + if (inherits(x, "td.data.frame") || inherits(y, "td.data.frame")) { + if (length(x) == 1 && length(y) == 1) { + if (!is.null(attr(x, "expressions")) && (!is.null(attr(y, "expressions")))) { + val1 <- attr(x, "expressions")[[names(x)]] + val2 <- attr(y, "expressions")[[names(y)]] + } + else { + val1 <- names(x) + val2 <- names(y) + } } - - return(asTdExpr(gettextf(ofmt, val, second_string, gram_length))) + else { + message("NGRAM warning: td.data.frame 'x' or 'y' has length > 1 using first element") + val1 <- names(x)[1] + val2 <- names(y)[1] + } + return(asTdExpr(gettextf(ofmt, val1, val2, gram_length))) } - - if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("NGRAM(", x, ",", second_string, ",", gram_length, ")", sep = ""))) + #check for other datatypes + if (inherits(x, "character") || inherits(x, "td.expression") || inherits(y, "character") || inherits(y, "td.expression")) { + return(asTdExpr(paste("NGRAM(", x, ",",y, ",", gram_length, ")", sep = ""))) } } diff --git a/R/OREPLACE.R b/R/OREPLACE.R index 5c40b79..3715c67 100755 --- a/R/OREPLACE.R +++ b/R/OREPLACE.R @@ -1,25 +1,35 @@ -OREPLACE <- function(x, search_string, replace_string = " ") { +OREPLACE <- function(x, search_char, replace_char) { asTdExpr <- function(x) { class(x) <- "td.expression" return(x) } - rfmt <- "OREPLACE(%s,%s,%s)" + rfmt <- "OREPLACE(%s, %s, %s)" if (inherits(x, "td.data.frame")) { - if (length(x) == 1) { - if (!is.null(attr(x, "expressions"))) - val <- attr(x, "expressions")[[names(x)]] else val <- names(x) - - } else { - message("OREPLACE warning: td.data.frame 'x' has length > 1 using first element") - val <- names(x)[1] + if (length(x) == 1 || length(y) == 1) { + if (!is.null(attr(x, "expressions")) || !is.null(attr(search_char, "expressions")) || !is.null(attr(replace_char, "expressions"))) { + val1 <- attr(x, "expressions")[[names(x)]] + val2 <- attr(search_char, "expressions")[[names(search_char)]] + val3 <- attr(replace_char, "expressions")[[names(replace_char)]] + } + else { + val1 <- names(x) + val2 <- names(search_char) + val3 <- names(replace_char) + } + } + else { + message("OREPLACE warning: td.data.frame 'x' or 'search_string' or 'replace_string' has length > 1 using first element") + val1 <- names(x)[1] + val2 <- names(search_char)[1] + val3 <- names(replace_char)[1] } - return(asTdExpr(gettextf(rfmt, val, search_string, replace_string))) + return(asTdExpr(gettextf(rfmt, val1, val2, val3))) } if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("OREPLACE(", x, ",", search_string, ",", replace_string, ")", sep = ""))) + return(asTdExpr(paste("OREPLACE(", val1, ", ", val2, ", ", val3, ")", sep = ""))) } } diff --git a/R/OTRANSLATE.R b/R/OTRANSLATE.R index fa5b372..1210b42 100755 --- a/R/OTRANSLATE.R +++ b/R/OTRANSLATE.R @@ -1,25 +1,35 @@ -OTRANSLATE <- function(x, from_string, to_string = " ") { +OTRANSLATE <- function(x, search_char, replace_char) { asTdExpr <- function(x) { class(x) <- "td.expression" return(x) } ofmt <- "OTRANSLATE(%s,%s,%s)" - if (inherits(x, "td.data.frame")) { - if (length(x) == 1) { - if (!is.null(attr(x, "expressions"))) - val <- attr(x, "expressions")[[names(x)]] else val <- names(x) - - } else { - message("OTRANSLATE warning: td.data.frame 'x' has length > 1 using first element") - val <- names(x)[1] + if (inherits(x, "td.data.frame") && inherits(search_char, "td.data.frame") && inherits(replace_char, "td.data.frame")) { + if (length(x) == 1 && length(search_char) == 1 && length(replace_char) == 1) { + if (!is.null(attr(x, "expressions")) || !is.null(attr(search_char, "expressions")) || !is.null(attr(replace_char, "expressions"))) { + val1 <- attr(x, "expressions")[[names(x)]] + val2 <- attr(search_char, "expressions")[[names(search_char)]] + val3 <- attr(replace_char, "expressions")[[names(replace_char)]] + } + else { + val1 <- names(x) + val2 <- names(search_char) + val3 <- names(replace_char) + } } - - return(asTdExpr(gettextf(ofmt, val, from_string, to_string))) - } + else { + message("OTRANSLATE warning: td.data.frame 'x' or 'search_char' or 'replace_char' has length > 1 using first element") + val1 <- names(x)[1] + val2 <- names(search_char)[1] + val3 <- names(replace_char)[1] + } + + return(asTdExpr(gettextf(ofmt, val1, val2, val3))) - if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("OTRANSLATE(", x, ",", from_string, ",", to_string, ")", sep = ""))) + if (inherits(x, "character") || inherits(x, "td.expression") || inherits(search_char, "character") || + inherits(search_char,"td.expression") || inherits(replace_char, "character") || inherits(replace_char, "td.expression")) { + return(asTdExpr(paste("OTRANSLATE(", x, ",", search_char, ",", replace_char, ")", sep = ""))) } } diff --git a/R/RTRIM.R b/R/RTRIM.R index 5181c67..fe96314 100755 --- a/R/RTRIM.R +++ b/R/RTRIM.R @@ -1,10 +1,10 @@ -RTRIM <- function(x, rstring = " ") { +RTRIM <- function(x) { asTdExpr <- function(x) { class(x) <- "td.expression" return(x) } - rfmt <- "RTRIM(%s,%s)" + rfmt <- "RTRIM(%s)" if (inherits(x, "td.data.frame")) { if (length(x) == 1) { if (!is.null(attr(x, "expressions"))) @@ -15,11 +15,6 @@ RTRIM <- function(x, rstring = " ") { val <- names(x)[1] } - return(asTdExpr(gettextf(rfmt, val, rstring))) - - } - - if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("RTRIM(", x, ",", fill_string, ")", sep = ""))) - } -} + return(asTdExpr(gettextf(rfmt, val))) + } +} \ No newline at end of file diff --git a/R/as.td.data.frame.R b/R/as.td.data.frame.R index 8d18d24..ef78b80 100755 --- a/R/as.td.data.frame.R +++ b/R/as.td.data.frame.R @@ -1,5 +1,5 @@ as.td.data.frame <- function(x, ...) { - if (inherits(x, "td.data.frame")) { + if (inherits(x, "td.data.frame")) { args <- list(...) if (is.null(args[["tableName"]])) tbl <- deparse(substitute(x)) else tbl <- args[["tableName"]] @@ -13,6 +13,7 @@ as.td.data.frame <- function(x, ...) { query <- gettextf("CREATE TABLE %s AS (%s) WITH DATA", oObj, selectText) df <- try(tdQueryUpdate(query)) if (length(df) == 1L && df == "No Data") + return(td.data.frame(tbl, oDatabase)) else stop(gettextf("Error: %s", paste(df, collapse = ""))) } if (inherits(x, "data.frame")) { diff --git a/R/on.R b/R/on.R new file mode 100755 index 0000000..79e2a28 --- /dev/null +++ b/R/on.R @@ -0,0 +1,41 @@ +on <- function(target=NULL, from=NULL, subQuery=NULL, partition=NULL, hash=NULL, order=NULL, local_order=NULL, null_order=NULL, dimension=NULL, as=NULL) { + if(!is.null(subQuery)) { + baseText <- paste("on %s%s%s%s", subQuery, "%s") + } + else { + baseText <- "on %s%s%s%s%s" + } + if (grepl("select", target)) { + if(!is.null(from)) { + returnString <- gettextf(baseText, "(", target," from ", from, ")") + } + else { + returnString <- gettextf(baseText, "(", target, ")", "", "") + } + } + else { + returnString <- gettextf(baseText, target, "", "", "", "","") + } + + if(!is.null(as)) { + returnString <- paste(returnString, .td.makeAs(as), sep="\n") + } + if (!is.null(partition)) { + returnString <- paste( returnString, .td.makePartition(partition), sep = "\n") + } + if (!is.null(hash)) { + returnString <- paste(returnString, .td.makeHash(hash), sep="\n") + } + if (!is.null(order)) { + returnString <- paste(returnString, .td.makeOrder(order), sep="\n") + } + + if (!is.null(local_order)) { + returnString <- paste(returnString, .td.makeLocalOrder(null_order, local_order), sep="\n") + } + if (!is.null(dimension)) { + returnString <- paste(returnString, .td.makeDimension(), sep="\n") + } + returnString <- gsub(";", "", returnString) + return(returnString) +} diff --git a/R/td.CalcMatrix.R b/R/td.CalcMatrix.R new file mode 100755 index 0000000..c242036 --- /dev/null +++ b/R/td.CalcMatrix.R @@ -0,0 +1,10 @@ +td.CalcMatrix <- function(selectPhrase=string, ons=string, phase=NULL, calctype=NULL, output=NULL, null_handling=NULL, optional_operators=NULL, as=NULL) { + + ons <- unlist(ons) + ons <- paste(ons, sep="", collapse="\n") + using <- .td.usingClause(phase=phase, calctype=calctype, output=output, null_handling=null_handling) + queryText <- paste(selectPhrase, "(\n", ons, using, ") ", optional_operators, " as ", as, ";") + + print(queryText) + return(queryText) +} diff --git a/R/td.ExecR.R b/R/td.ExecR.R new file mode 100755 index 0000000..3671ea7 --- /dev/null +++ b/R/td.ExecR.R @@ -0,0 +1,10 @@ +td.ExecR <- function(selectPhrase=string, ons=list(), returns=NULL, contract=NULL, operator=string, optional_operators=NULL) { + ons<- unlist(ons) + ons <- paste(ons, sep="", collapse="\n") + using <- .td.usingClause(returns=returns, contract=contract, operator=operator) + queryText <- paste(selectPhrase, "(\n", ons, using, ") ", optional_operators, ") as db;") + print(queryText) + + return(queryText) + +} \ No newline at end of file diff --git a/R/td.data.frame.R b/R/td.data.frame.R index 1e23908..19a7d1d 100755 --- a/R/td.data.frame.R +++ b/R/td.data.frame.R @@ -4,7 +4,7 @@ td.data.frame <- function(table, database = "") { query <- gettextf("SELECT * FROM %s SAMPLE 0", obj) res <- try(tdQuery(query)) if (is.null(attr(res, "class"))) { - res <- data.frame() + res <- data.frame(stringsAsFactors = FALSE) attr(res, "totalRows") <- 0 warning("Teradata table not found. Result is empty data frame.") } else { diff --git a/R/tdQuery.R b/R/tdQuery.R index 1f2d594..eba0a7b 100755 --- a/R/tdQuery.R +++ b/R/tdQuery.R @@ -1,6 +1,6 @@ tdQuery <- function(q, ...) { if (class(tdConnection) == "RODBC") - return(sqlQuery(tdConnection, q, ...)) + return(sqlQuery(tdConnection, q, stringsAsFactors=FALSE, ...)) if (class(tdConnection) == "JDBCConnection") return(dbGetQuery(tdConnection, q, ...)) } diff --git a/R/teradataR-internal.R b/R/teradataR-internal.R index 02e9e17..cdfd08a 100755 --- a/R/teradataR-internal.R +++ b/R/teradataR-internal.R @@ -884,3 +884,46 @@ return(query) } + +.td.makeHash <- function(...) { + baseText = "hash by %s" + dependents = paste(...) + return(gettextf(baseText, dependents)) +} + +.td.makePartition <- function(...) { + baseText = "partition by %s" + dependents = paste(...) + return(gettextf(baseText, dependents)) +} + +.td.makeOrder <- function(...) { + baseText = "order by %s" + dependents = paste(...) + return(gettextf(baseText, dependents)) +} + +.td.makeLocalOrder <- function(null_order=NULL, local_order=NULL, ...) { + baseText = "local order by %s" + if (!is.null(nullOrder)) { + specialValue = paste(nullOrder) + orderByList = paste(...) + dependents = paste(orderByList, specialValue) + return(gettextf(baseText, dependents)) + } + else { + dependents = paste(...) + return(gettextf(baseText, dependents)) + } +} + +.td.makeDimension <- function() { + baseText = "dimension" + return(baseText) +} + +.td.makeAs <- function(...) { + baseText = "as %s" + dependents = paste(...) + return(gettextf(baseText, dependents)) +} \ No newline at end of file diff --git a/man/INITCAP.Rd b/man/INITCAP.Rd new file mode 100644 index 0000000..1b4f258 --- /dev/null +++ b/man/INITCAP.Rd @@ -0,0 +1,46 @@ +\name{INITCAP} +\alias{INITCAP} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +Wrapper Function INITCAP +} +\description{ +Makes a wrapper around the fastpath function INITCAP +} +\usage{ +INITCAP(x) +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{x}{ +a teradata dataframe that contains columns of characters that will be capitalized +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +A teradata data frame of the columns that have their first letters capitalized +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Todd Brye, Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +%% ~~objects to See Also as \code{\link{help}}, ~~~ +} +\examples{ +tdf["col2"] <- INITCAP(tdf["col1"]) +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/man/LPAD.Rd b/man/LPAD.Rd new file mode 100644 index 0000000..b667f1d --- /dev/null +++ b/man/LPAD.Rd @@ -0,0 +1,51 @@ +\name{LPAD} +\alias{LPAD} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +Wrapper Function LPAD +} +Makes a wrapper around the fastpath function LPAD +} +\usage{ +LPAD(x, ilength, fill_string = " ") +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{x}{ +a teradata dataframe that contains column(s) of characters that will be padded +} + \item{ilength} { +the amount of padding to append to the beginning of the character +} + \item{fill_string} { +the character used to pad the the column(s) of characters that are passed into the function. Default character is the empty character +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +A teradata data frame of the columns that have been padded at the beginning +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Todd Brye, Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +%% ~~objects to See Also as \code{\link{help}}, ~~~ +} +\examples{ +tdf["col2"] <- LPAD(tdf["col1", 15, " "]) +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/man/LTRIM.Rd b/man/LTRIM.Rd new file mode 100644 index 0000000..745915a --- /dev/null +++ b/man/LTRIM.Rd @@ -0,0 +1,47 @@ +\name{LTRIM} +\alias{LTRIM} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +Wrapper Function LTRIM +} +\description{ +Makes a wrapper around the fastpath function LTRIM +} +\usage{ +LTRIM(x) +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{x}{ +a teradata dataframe that contains column(s) of characters whose padding to their left will be trimmed +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +A teradata data frame of the columns that will be trimmed at the beginning of each character +%% ... +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Todd Brye, Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +%% ~~objects to See Also as \code{\link{help}}, ~~~ +} +\examples{ +tdf["col2"] <- LTRIM(tdf["col1"]) +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/man/RPAD.Rd b/man/RPAD.Rd new file mode 100644 index 0000000..9d1e621 --- /dev/null +++ b/man/RPAD.Rd @@ -0,0 +1,52 @@ +\name{RPAD} +\alias{RPAD} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +Wrapper Function RPAD +} +\description{ +Makes a wrapper around the fastpath function RPAD +} +\usage{ +RPAD(x, ilength, fill_string = " ") +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{x}{ +a teradata dataframe that contains column(s) of characters that will be padded +} + \item{ilength} { +the amount of padding to append to the beginning of the character +} + \item{fill_string} { +the character used to pad the the column(s) of characters that are passed into the function. Default character is the empty character +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +A teradata data frame of the columns that will be padded at the beginning of each character +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Todd Brye, Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +%% ~~objects to See Also as \code{\link{help}}, ~~~ +} +\examples{ +tdf["col2"] <- RPAD(tdf["col1", 15, " "]) +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/man/RTRIM.Rd b/man/RTRIM.Rd new file mode 100644 index 0000000..9bffe06 --- /dev/null +++ b/man/RTRIM.Rd @@ -0,0 +1,46 @@ +\name{RTRIM} +\alias{RTRIM} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +Wrapper Function RTRIM +} +\description{ +Makes a wrapper around the fastpath function RTRIM +} +\usage{ +RTRIM(x) +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{x}{ +a teradata dataframe that contains column(s) of characters whose padding to their right will be trimmed +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +A teradata data frame of the columns that will be trimmed at the end of each character +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Todd Brye, Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +%% ~~objects to See Also as \code{\link{help}}, ~~~ +} +\examples{ +tdf["col2"] <- RTRIM(tdf["col1"]) +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/man/on.Rd b/man/on.Rd new file mode 100644 index 0000000..9169d12 --- /dev/null +++ b/man/on.Rd @@ -0,0 +1,73 @@ +\name{on} +\alias{on} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +On Function +} +\description{ +Creates A representation of an ON Clause in an ExecR Table Operator query. +} +\usage{ +on(target=NULL, from=NULL, subQuery=NULL, partition=NULL, hash=NULL, order=NULL, local_order=NULL, null_order=NULL, dimension=NULL, as=NULL) +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{target}{ +a character that represents a name of a table or a query expression +} + \item{from} { +a character that represents a name of the origin of a query expression +} + \item{subQuery}{ +a character that represents a nested ON Clause or nested query expression that is part of an ON Clause +} + \item{partition} { +the parallel option, partition by , or partition by +} + \item{hash} { +the parallel option, hash by +} + \item{order}{ +the parallel option, order by +} + \item{local_order}{ +the parallel option, local order by +} + \item{null_order}{ +specification for the parallel option local_order +} + \item{dimension} { +the parallel option, dimension +} + \item{as} { +creates and alias +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +a string representation of an ON Clause for a table operator +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +%% ~~objects to See Also as \code{\link{help}}, ~~~ +} +\examples{ +o <- on(target="select *" from="tab1", partition="any") +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/man/td.CalcMatrix.Rd b/man/td.CalcMatrix.Rd new file mode 100644 index 0000000..c576da5 --- /dev/null +++ b/man/td.CalcMatrix.Rd @@ -0,0 +1,70 @@ +\name{td.CalcMatrix} +\alias{td.CalcMatrix} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +Wrapper function for CalcMatrix +} +\description{ +Creates A wrapper around the CalcMatrix table operator, using R Code. +} +\usage{ +td.CalcMatrix(selectPhrase=string, ons=string, phase=NULL, calctype=NULL, output=NULL, null_handling=NULL, optional_operators=NULL, as=NULL) +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{selectPhrase}{ + a character that represents the select clause for a query expression +} + \item{ons} { +a character or list representation of the needed ON Clauses +} + \item{phase} { +the character representation of the input of the optional PHASE clause +} + \item{calctype} { +the character representation of the input of the optional CALCTYPE clause +} + \item{output} { +the character representation of the input of the optional OUTPUT clause +} + \item{null_handling} { +the character representation of the input of the optional specfication for null handling +} + \item{optional_operators} { +the character representation of the other operators that can be specified +} + \item{as} { +creates and alias +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +a character representation of a query that can be passed into TdQuery to use the CalcMatrix table operator. +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +%% ~~objects to See Also as \code{\link{help}}, ~~~ +} +\examples{ +on2 <- on(target= "select * from tab1") +query <- td.CalcMatrix(selectPhrase="select session as ampkey, D1.* from TD_SYSFNLIB.calcmatrix", ons=on1, phase="LOCAL", as="D1") +res <- tdQuery(query) +print(res) +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/man/td.ExecR.Rd b/man/td.ExecR.Rd new file mode 100644 index 0000000..eeecd93 --- /dev/null +++ b/man/td.ExecR.Rd @@ -0,0 +1,64 @@ +\name{td.ExecR} +\alias{td.ExecR} +%- Also NEED an '\alias' for EACH other topic documented here. +\title{ +ExecR Wrapper Function +} +\description{ +This function is a wrapper function around the table operator ExecR. It generates a string that can be passed into the function tdQuery to make a query that uses ExecR. +} +\usage{ +td.ExecR(selectPhrase=string, ons=list(), returns=NULL, contract=NULL, operator=string, optional_operators=NULL) +} +%- maybe also 'usage' for other objects documented here. +\arguments{ + \item{selectPhrase}{ +a character that represents a select phrase +} + \item{ons} { +a list or character representation of on clauses +} + \item{returns} { +a file or character representation of a returns clause +} + \item{contract} { +a file or character representation of a contract clause +} + \item{operator} { +a file or character representation of an operator clause +} + \item{optional_operators} { +a character representation of any other needed operators +} +} +\details{ +%% ~~ If necessary, more details than the description above ~~ +} +\value{ +A character representation of a query that will use the ExecR table operator when passed into the tdQuery function. +} +\references{ +%% ~put references to the literature/web site here ~ +} +\author{ +Erin Cole +} +\note{ +%% ~~further notes~~ +} + +%% ~Make other sections like Warning with \section{Warning }{....} ~ + +\seealso{ +\code{\link{on}} +} +\examples{ +on1 <- on(target="select *", from="tab1", hash="c1", local_order="c2") +query <- td.ExecR(selectPhrase="select distinct * from TD_SYSGPL.ExecR", ons=on1, contract="~/Documents/contract.txt", operator="~/Documents/operator.txt") +res <- tdQuery(query) +print(res) +} +% Add one or more standard keywords, see file 'KEYWORDS' in the +% R documentation directory. +\keyword{ ~kwd1 }% use one of RShowDoc("KEYWORDS") +\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line diff --git a/test/.DS_Store b/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..abba6a82d47a1091441e6820f678ab72abbea5ad GIT binary patch literal 6148 zcmeHK%TB{E5FA4V<*CAnV~(7V_=6N$pi-d_;7$uYAXOAWk;*Nf!AJ1{T)6WO9Lnt4 zN)zI8Ly#y-{_9+=gbeI&&UO!AGtl;a;EDKjKzGtT9_nlTz^ zGHM5crAT0=1>Q==YcjJwGxbC>Z;~H1i6`2=R{Q$W5C z5nV8Lm|E0N2Mav{5G$-!xFE^TXZ!(i{yeBJ4`LIh8BJVREAIl1%6e5FRfn)AOHXW literal 0 HcmV?d00001 diff --git a/test/basicContract.txt b/test/basicContract.txt new file mode 100755 index 0000000..3fd0f1c --- /dev/null +++ b/test/basicContract.txt @@ -0,0 +1 @@ +library(tdr); \ No newline at end of file diff --git a/test/basicOperator.txt b/test/basicOperator.txt new file mode 100755 index 0000000..3fd0f1c --- /dev/null +++ b/test/basicOperator.txt @@ -0,0 +1 @@ +library(tdr); \ No newline at end of file diff --git a/test/testCHR.R b/test/testCHR.R new file mode 100644 index 0000000..0e416a8 --- /dev/null +++ b/test/testCHR.R @@ -0,0 +1,22 @@ +# Below is the table used for the test, called "test" +# c1 c2 c5 c6 c7 +# ----------- -------- ---------- ---------- -- +# 5 Emily cat dog +# 4 Daisy fork spoon +# 3 Hank ball bat +# 2 Amy robot human + +tdf <- td.data.frame("test") +tdf["c7"] <- CHR(tdf["c1"]) +as.td.data.frame(tdf, "test2") + +# the resulting table is below, called "test2" +# c1 c2 c5 c6 c7 +# ----------- -------- ---------- ---------- -- +# 5 Emily cat dog +# 4 Daisy fork spoon +# 3 Hank ball bat +# 2 Amy robot human + +#Although the resulting table does not seem to give the expected output, the same output occurs in bteq and in RStudio. +#Further testing is recommended \ No newline at end of file diff --git a/test/testCalcMatrix.R b/test/testCalcMatrix.R new file mode 100755 index 0000000..465deea --- /dev/null +++ b/test/testCalcMatrix.R @@ -0,0 +1,66 @@ +#on1 <- on(target="select var1, var2, var3, var4, var5", from="testCM") +#res1 <- td.CalcMatrix(selectPhrase='select * from TD_SYSFNLIB.calcmatrix', ons=on1, phase="local", as= "D1") +#query1 <- tdQuery(res1) +#print(query1) + +#on2 <- on(target= "select * from numbers") +#res2 <- td.CalcMatrix(selectPhrase="select session as ampkey, D1.* from TD_SYSFNLIB.calcmatrix", ons=on2, phase="LOCAL", as="D1") +#query2 <- tdQuery(res2) +#print(query2) + +#on3 <- on(target="select var1, var2, var3, var4, var5 from TestCM2") +#res4 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on3, phase="local", as="D1") +#query4 <- tdQuery(res4) +#print(query4) + +#on4 <- on(target ="select * from TestCMLocal", hash="p") +#res5 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on4, phase="combine", calctype="sscp", output="columns", as="D1") +#query5 <- tdQuery(res5) +#print(query5) + +#on5 <- on(target ="select * from TestCMLocal", hash="p") +#res6 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on5, phase="combine", calctype="CSSCP", output="columns", as="D1") +#query6 <- tdQuery(res6) +#print(query6) + +#on6 <-on(target="select * from TestCMLocal", hash="p") +#res7 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on6, phase="combine", calctype="COV", output="columns", as="D1") +#query7 <- tdQuery(res7) +#print(query7) + +#on7 <- on(target="select * from TestCMLocal", hash="p") +#res8 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on7, phase="combine", calctype="COR", output="varbyte", as="D1") +#query8 <- tdQuery(res8) +#print(query8) + +#on8 <- on(target="select * from TestCMLocal", hash="p") +#res9 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on8, phase="combine", calctype="SSCP", output="varbyte", as="D1") +#query9 <- tdQuery(res9) +#print(query9) + +#on9 <- on(target="select var1, var2, var3, var4, var5 from TestCMNull") +#res10 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on9, phase="local", null_handling="ignore", as="D1") +#query10 <- tdQuery(res10) +#print(query10) + +#on10 <- on(target="select var1, var2, var3, var4, var5", from="TestCMNull") +#res11 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on10, phase="local", null_handling="zero", as="D1") +#query11 <- tdQuery(res11) +#print(query11) + +#on11 <- on(target="select p, var1, var2, var3, var4, var5 from TestCM_Mult", local_order="p") +#res12 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on11, phase="local", as="D1") +#query12 <- tdQuery(res12) +#print(query12) + +#on12 <- on(target="select p, var1, var2, var3, var4, var5 from TestCM_Mult", local_order="p") +#res13 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on12, phase="local", as="D1") +#query13 <- tdQuery(res13) +#print(query13) + +#on14 <- on(target="select p, var1, var2, var3, var4,var5", from="TESTCM_Mult", local_order = "p") +#sub1 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on14, phase="local", as="D1") +#on15 <- on(target=sub1, hash="p", local_order="p") +#res14 <- td.CalcMatrix(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on15, phase="combine", calctype="esscp", as="D2") +#query14 <- tdQuery(res14) +#print(query14) diff --git a/test/testDECODE.R b/test/testDECODE.R new file mode 100644 index 0000000..1f8589c --- /dev/null +++ b/test/testDECODE.R @@ -0,0 +1,3 @@ +tdf <- td.data.frame("test") +tdf["c10"] <- DECODE(tdf["c1"], default=NULL, 1, 'Alpha', 2, 'Bravo', 3, 'Charlie', 4, 'Delta') +as.td.data.frame(tdf, tableName="test47") \ No newline at end of file diff --git a/test/testExecR.R b/test/testExecR.R new file mode 100755 index 0000000..ffedda6 --- /dev/null +++ b/test/testExecR.R @@ -0,0 +1,75 @@ +source("~/Documents/RRR/Code/ExecR.R") + +#on1 <- on(target= "select * from test", hash="c1", local_order="c2") +#onList <- list(on1) +#res1 <- td.ExecR(selectPhrase="select distinct * from TD_SYSGPL.ExecR", ons=onList, contract="~/Documents/RRR/contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators="keeplog(1)\nlogdebug(1)") +#query1 <- tdQuery(res1) +#print(query1) + +#on2 <- on(target="test", dimension="") +#onList2 <-list( on3) +#print(onList2) +#res2 <- td.ExecR(selectPhrase="select distinct * from TD_SYSGPL.ExecR", ons=onList2, contract="~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators="keeplog(1)\nlogdebug(1)") +#query2 <- tdQuery(res2) +#print(query2) + +#on4 <- on(target="numbers", partition="1") +#on5 <- on(target="numbers", dimension="") +#onList3 <- list(on4, on5) +#res3 <- td.ExecR(selectPhrase="select distinct * from TD_SYSGPL.ExecR", ons=onList3, contract="~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators=NULL) +#query3 <- tdQuery(res3) +#print(query3) + +#on6 <- on(target="select 1", partition="1") +#on7 <- on(target="select * from test", dimension = "") +#onList4 <- list(on6, on7) +#res4 <- td.ExecR(selectPhrase = "select * from TD_SYSGPL.ExecR", ons=onList4, contract="~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators = "keeolog(1)\nlogdebug(1)") +#query4 <- tdQuery(res4) +#print(query4) + +#on8 <- on(target="select * from test", as="test") +#res5 <- td.ExecR(selectPhrase = "select * from TD_SYSGPL.ExecR", ons=on8, contract= "~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators="keeplog(1)\nlogdebug(1)") +#query5 <- tdQuery(res5) +#print(query5) + +#on9 <- on(target="test", as="test1", partition="c1") +#on10 <- on(target ="test", as="test2", dimension="") +#onList5 <- list(on9, on10) +#res6 <- td.ExecR(selectPhrase="select distinct * from TD_SYSGPL.ExecR", ons=onList5, contract= "~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators="keeplog(1)\nlogdebug(1)") +#query6 <- tdQuery(res6) +#print(query6) + +#on11 <- on(target="test", as="test1", partition="c1") +#on12 <- on(target="test", as="test2", dimension=" ") +#on13 <- on(target="test", as="test3", dimension=" ") +#onList6 <- list(on11, on12, on13) +#res7 <- td.ExecR(selectPhrase="select distinct * from TD_SYSGPL.ExecR", ons=onList6, contract="~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators = "keeplog(1)\nlogdebug(1)") +#query7 <- tdQuery(res7) +#print(query7) + +#on14 <- on(target="select *", from ="test", hash="c1", local_order="c1") +#res8 <- td.ExecR(selectPhrase="select distinct * from TD_SYSGPL.ExecR", ons=on14, contract="~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt") +#query8 <- tdQuery(res8) +#print(query8) + +#on15 <- on(target= "select * from test", partition="c1") +#res9 <- td.ExecR(selectPhrase="select * from TD_SYSGPL.ExecR", ons=on15, contract="~/Documents/RRR/Contract.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators="keeplog(1)\nlogdebug(1)") +#query9 <- tdQuery(res9) +#print(query9) + +#on16 <- on(target="twm_customer_analysis", partition="marital_status") +#res10 <- td.ExecR(selectPhrase="select * from TD_SYSGPL.ExecR", ons=on16, returns="~/Documents/RRR/returns.txt", operator="~/Documents/RRR/Test/basicOperator.txt", optional_operators="keeplog(1)\nlogdebug(1)") +#query10 <- tdQuery(res10) +#print(query10) + +#test case does not work +#on17 <- on(target="select * from test") +#res11 <- td.ExecR(selectPhrase="select * from TD_SYSGPL.ExecR", ons=on17, returns="testout", operator="~/Documents/RRR/Test/basicOperator.txt") +#query11 <- tdQuery(res11) +#print(query11) + +#test case missing contract clause. Should get an error +#on18 <- on(target="select *", from="test") +#res12 <- td.ExecR(selectPhrase="select * from TD_SYSGPL.ExecR", ons=on18, operator="~/Documents/RRR/Test/basicOperator.txt") +#query12 <- tdQuery(res12) +#print(query12) \ No newline at end of file diff --git a/test/testINITCAP.R b/test/testINITCAP.R new file mode 100644 index 0000000..6dc8b1a --- /dev/null +++ b/test/testINITCAP.R @@ -0,0 +1,20 @@ +# Below is the table used for the test, called "test" +# c1 c2 c3 c4 c5 c6 +#----------- -------- -- -- ---------- ---------- +# 5 Emily ? cat dog +# 4 Daisy ? ? fork spoon +# 3 Hank ? ? ball bat +# 2 Amy ? ? robot human +# +# the R code is below: +tdf <- td.data.frame("test") +tdf["c7"] <- INITCAP(tdf["c5"]) +as.td.data.frame(tdf, tableName="testZ") + +# Below are the results of the table, when you type "select * from testZ" +# c1 c2 c3 c4 c5 c6 c7 +# ----------- -------- -- -- ---------- ---------- +# 5 Emily ? cat dog Cat +# 4 Daisy ? ? fork spoon Fork +# 3 Hank ? ? ball bat Ball +# 2 Amy ? ? robot human Robot diff --git a/test/testINSTR.R b/test/testINSTR.R new file mode 100644 index 0000000..0d74bba --- /dev/null +++ b/test/testINSTR.R @@ -0,0 +1,24 @@ +# Below is the table used for the test, called "tab1" +# c1 c2 +# ---------- ---- +# explore lo +# interrupt ter +# disappear ar +# factor ac +# appreciate pp + +tdf <- td.data.frame("tab1") +tdf["c3"] <- INSTR(tdf["c1"], tdf["c2"]) +as.td.data.frame(tdf, tableName="tab2") + +# This is the resulting table, called "tab2" +# c1 c2 c3 +# ---------- ---- ---------------------------------------- +# explore lo 0 +# interrupt ter 0 +# disappear ar 0 +# factor ac 0 +# appreciate pp 0 + +# While running the equivalent code in bteq produces the same table, this test does not seem to give the expected output +# I recommend further testing. \ No newline at end of file diff --git a/test/testLPAD.R b/test/testLPAD.R new file mode 100644 index 0000000..22e6009 --- /dev/null +++ b/test/testLPAD.R @@ -0,0 +1,20 @@ +# Below is the table used for the test, called "test" +# c1 c2 c3 c4 c5 c6 +#----------- -------- -- -- ---------- ---------- +# 5 Emily ? cat dog +# 4 Daisy ? ? fork spoon +# 3 Hank ? ? ball bat +# 2 Amy ? ? robot human +# +# the R code is below: +tdf <- td.data.frame("test") +tdf["c7"] <- LPAD(tdf["c5"], 15, " ") +as.td.data.frame(tdf, tableName="testYY") + +# Below are the results of the table, when you type "select * from testY" +# c1 c2 c3 c4 c5 c6 c7 +#----------- -------- -- -- ---------- ------------------------------------ +# 5 Emily ? cat dog cat +# 4 Daisy ? ? fork spoon fork +# 3 Hank ? ? ball bat ball +# 2 Amy ? ? robot human robot \ No newline at end of file diff --git a/test/testLTRIM.R b/test/testLTRIM.R new file mode 100644 index 0000000..089384f --- /dev/null +++ b/test/testLTRIM.R @@ -0,0 +1,19 @@ +# Below is the table used for the test, called "tab1" +#c1 c2 c3 +#---------- ---------- ---------- +# horse horse ? +# mouse mouse ? +# dog dog ? +# cat cat ? + +tdf <- td.data.frame("tab1") +tdf["c3"] <- LTRIM(tdf["c1"]) +as.td.data.frame(tdf, tableName="tab2") + +#this is the resulting table +#c1 c2 c3 +#---------- ---------- ---------- +# horse horse horse +# mouse mouse mouse +# dog dog dog +# cat cat cat \ No newline at end of file diff --git a/test/testNGRAM.R b/test/testNGRAM.R new file mode 100644 index 0000000..6d7b3e2 --- /dev/null +++ b/test/testNGRAM.R @@ -0,0 +1,19 @@ +# Below is the table used for the test, called "tab2" +# c1 c2 c3 +# ---------- ---------- ---------- +# mouse house ? +# wagon wagon ? +# cart heart ? +# horse force ? + +tdf <- td.data.frame("tab2") +tdf["c3"] <- NGRAM(tdf["c1"], tdf["c2"], 2) +as.td.data.frame(tdf, tableName="tab3") + +#this is the resulting table +# c1 c2 c3 +# ---------- ---------- ----------- +# mouse house 8 +# wagon wagon 9 +# cart heart 8 +# horse force 6 \ No newline at end of file diff --git a/test/testOREPLACE.R b/test/testOREPLACE.R new file mode 100644 index 0000000..4936532 --- /dev/null +++ b/test/testOREPLACE.R @@ -0,0 +1,24 @@ +# Below is the table used for the test, called "tab2" +# c1 c2 c3 +# ---------- ---- ---------- +# explore lo ? +# interrupt ter xyz +# disappear ar xy +# factor ac xy +# appreciate pp xy + +tdf <- td.data.frame("tab2") +tdf["c4"] <- OREPLACE(tdf["c1"], tdf["c2"], tdf["c3"]) +as.td.data.frame(tdf, tableName="tab3") + +#this is the resulting table, tab3 +# c1 c2 c3 c4 +# ---------- ---- ---------- ------------------------------------------------ +# explore lo ? explore +# interrupt ter xyz interrupt +# disappear ar xy disappear +# factor ac xy factor +# appreciate pp xy appreciate + +#although this test did produce the same table/dataframe in both bteq and +#RStudio, further testing on how to get the expected output is suggested \ No newline at end of file diff --git a/test/testOTRANSLATE.R b/test/testOTRANSLATE.R new file mode 100644 index 0000000..e67a2a5 --- /dev/null +++ b/test/testOTRANSLATE.R @@ -0,0 +1,20 @@ +# Below is the table used for the test, called "tab1" +# c1 c2 c3 c4 +# ---------- -- -- ---------- +# outstanding s x ? +# shrewd r x ? +# amicable i x ? +# introverted t x ? + +tdf <- td.data.frame("tab1") +tdf["c4"] <- OTRANSLATE(tdf["c1"], tdf["c2"], tdf["c3"]) +as.td.data.frame(tdf, tableName="tab2") + +#this is the resulting table, tab2 + +# c1 c2 c3 c4 +# ---------- -- -- ---------------------------------------------------------- +# outstanding s x outxtanding +# shrewd r x shxewd +# amicable i x amxcable +# introverted t x inxroverxed \ No newline at end of file diff --git a/test/testOn.R b/test/testOn.R new file mode 100644 index 0000000..006cc43 --- /dev/null +++ b/test/testOn.R @@ -0,0 +1,31 @@ +#test On() +#res1 = on(target="select *", from="tab1", partition = "any", hash = "col1") == "on (select * from tab1)\npartition by any\nhash by col1" +#print(res1) +#stopifnot(res1) + +#res2 = on(target="select *", from="tab1", hash="col1", local_order="col2") == "on (select * from tab1)\nhash by col1\nlocal order by col2" +#stopifnot(res2) + +#res3 = on(target="tab1", partition="col1") == "on tab1\npartition by col1" +#print(res3) +#stopifnot(res3) + +#res4 = on(target="tab1", dimension= " ") == "on tab1\ndimension" +#stopifnot(res4) + +#res5 = on(target="select 1", partition="1") == "on (select 1)\npartition by 1" +#print(res5) +#stopifnot(res5) + +#res6 = on(target="select *", from="tab1", hash="col1", local_order="col1, col2") == "on (select * from tab1)\nhash by col1\nlocal order by col1, col2" +#print(res6) +#stopifnot(res6) + +#res7 = on(target="select *", from="tab1", as="test") == "on (select * from tab1)\nas test" +#print(res7) +#stopifnot(res7) + +#on1 = on(target="select p, var1, var2, var3, var4, var5", from="TestCM_Mult", local_order="p") +#littleOnClause= toQuery(selectPhrase="select * from TD_SYSFNLIB.calcmatrix", ons=on1, phase="local", as="D1") +#ons2 = on(target="select *", from="TD_SYSFNLIB.calcmatrix", subQuery=on1, hash="p", local_order="p") +#print(ons2) \ No newline at end of file diff --git a/test/testRPAD.R b/test/testRPAD.R new file mode 100644 index 0000000..54b836d --- /dev/null +++ b/test/testRPAD.R @@ -0,0 +1,20 @@ +# Below is the table used for the test, called "test" +# c1 c2 c3 c4 c5 c6 +#----------- -------- -- -- ---------- ---------- +# 5 Emily ? cat dog +# 4 Daisy ? ? fork spoon +# 3 Hank ? ? ball bat +# 2 Amy ? ? robot human +# +# the R code is below: +tdf <- td.data.frame("test") +tdf["c7"] <- RPAD(tdf["c5"], 15, " ") +as.td.data.frame(tdf, tableName="testY") + +# Below are the results of the table, when you type "select * from testY" +# c1 c2 c3 c4 c5 c6 c7 +#----------- -------- -- -- ---------- ------------------------------------ +# 5 Emily ? cat dog cat +# 4 Daisy ? ? fork spoon fork +# 3 Hank ? ? ball bat ball +# 2 Amy ? ? robot human robot \ No newline at end of file diff --git a/test/testRTRIM.R b/test/testRTRIM.R new file mode 100644 index 0000000..fc59b8c --- /dev/null +++ b/test/testRTRIM.R @@ -0,0 +1,17 @@ +# Below is the table used for the test, called "tab1" +#c1 c2 c3 +#---------- ---------- ---------- +# horse horse ? +# mouse mouse ? +# dog dog ? +# cat cat ? + +tdf <- td.data.frame("tab1") +tdf["c3"] <- LTRIM(tdf["c2"]) +as.td.data.frame(tdf, tableName="tab2") +#c1 c2 c3 +#---------- ---------- ----- +# horse horse horse +# mouse mouse mouse +# dog dog dog +# cat cat cat \ No newline at end of file diff --git a/test/testUtil.R b/test/testUtil.R new file mode 100755 index 0000000..baeec57 --- /dev/null +++ b/test/testUtil.R @@ -0,0 +1,25 @@ +#test makePartition() +#res= .td.makePartition("col1, col2") == "partition by col1, col2" +#print(res) +#stopifnot(res) + +#res = .td.makePartition(partition = "any") == "partition by any" +#stopifnot(res) + +#test makeHash() +#res = .td.makeHash("col1") == "hash by col1" +#stopifnot(res) + +#res = .td.makeHash("col1") == "nope" +#stopifnot(res) + +#test makeOrder() +#res = .td.makeOrder("col1, col2") == "order by col1, col2" +#stopifnot(res) + +#test makeDimension() +#res = .td.makeDimension() == "dimension" +#stopifnot(res) + +#test makeLocalOrder() +#res = .td.makeLocalOrder("col1") diff --git a/test/testtoQuery.R b/test/testtoQuery.R new file mode 100644 index 0000000..5a4bdef --- /dev/null +++ b/test/testtoQuery.R @@ -0,0 +1 @@ +query1 <- toQuery(selectPhrase=string, ons=string, phase="local", as="D2") \ No newline at end of file From d4925724c4f304378dfc19a0cbf903b5330870a4 Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 15:49:11 -0700 Subject: [PATCH 08/28] fixed and tested DECODE() --- test/testDECODE.R | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test/testDECODE.R b/test/testDECODE.R index 1f8589c..de20c61 100644 --- a/test/testDECODE.R +++ b/test/testDECODE.R @@ -1,3 +1,20 @@ +# Below is the table used for the test, called "tab1" +# +# c1 +# ---- +# 5 +# 4 +# 3 +# 2 + tdf <- td.data.frame("test") -tdf["c10"] <- DECODE(tdf["c1"], default=NULL, 1, 'Alpha', 2, 'Bravo', 3, 'Charlie', 4, 'Delta') -as.td.data.frame(tdf, tableName="test47") \ No newline at end of file +tdf["c10"] <- DECODE(tdf["c1"], default='none', 1, 'Alpha', 2, 'Bravo', 3, 'Charlie', 4, 'Delta') +as.td.data.frame(tdf, tableName="tab2") + +#this is the resulting table, called "tab2" +# c1 c10 +# ---- ------- +# 5 none +# 4 Delta +# 3 Charlie +# 2 Bravo From 7d4768d8cee41ad01e6b404d467c3c31b5e8f684 Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 16:42:02 -0700 Subject: [PATCH 09/28] finished testing DECODE() --- R/DECODE.R | 28 +++++----------------------- test/testDECODE.R | 2 +- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/R/DECODE.R b/R/DECODE.R index 506e255..9498adb 100755 --- a/R/DECODE.R +++ b/R/DECODE.R @@ -4,45 +4,27 @@ DECODE <- function(x, default=NULL, ...) { res <- as.numeric(paste(i)) } else { - res <- paste("'",i,"'", collapse=none) - print(nchar(res, type="chars")) + res <- paste("'",i,"'", sep="") } return(res) } params <- list(...) - #print(parms[[2]]) - #plist <- unlist(parms) - #return("DECODE(c1, 1, \'A\', 2,\'B\')" ) res <- lapply(params, simplePaste) res <- paste(res, collapse=",") - print(res) if (inherits(x, "td.data.frame")) { if (length(x) > 1) { message("DECODE warning: td.data.frame 'x' has length > 1 using first element") } - - - #print(res) - val <- paste("DECODE(", .td.gencolumnexpr(x[1]), ",", res, ")", sep = "") + val <- paste("DECODE(", .td.gencolumnexpr(x[1]), ",", res, ",'", default, "')", sep = "") } else if (inherits(x, "td.expression") || inherits(x, "numeric")) { - val <- paste("DECODE(", x, ",", res, ")", sep = "") + val <- paste("DECODE(", x, ",", res, ",'", default, "')", sep = "") } else if (inherits(x, "character")) { - val <- paste("DECODE('", x, "'", ",", lapply(params, simplePaste), ")", sep = "") + val <- paste("DECODE('", x, "'", ",", res, ",'", default, "')", sep = "") } else stop("Invalid data type for 'x' in DECODE function") class(val) <- "td.expression" return(val) -} - -# DECODE <- function(x, ...) { parms <- list(...) for(i in 1:length(parms)) { if(is.character(parms[[i]])) parms[[i]] -# <- paste(''', parms[[i]], ''', sep='') } plist <- paste(parms, collapse=',') if(inherits(x, 'td.data.frame')) { -# if(length(x) == 1) { if(!is.null(attr(x, 'expressions')) && names(x) %in% names(attr(x,'expressions'))) { val <- -# paste('DECODE(', attr(x, 'expressions')[[names(x)]], ',', plist, ')', sep='') class(val) <- 'td.expression' -# return(val) } else { val <- paste('DECODE(\'', names(x), '\',', plist, ')', sep='') class(val) <- 'td.expression' -# return(val) } } else { message('DECODE warning: td.data.frame 'x' has length > 1 using first element') val <- -# paste('DECODE(\'', names(x)[1], ',', plist, '\')', sep='') class(val) <- 'td.expression' return(val) } } -# if(inherits(x, 'character') || inherits(x,'td.expression')) { val <- paste('DECODE(', x, ',', plist, ')', sep='') -# class(val) <- 'td.expression' return(val) } } +} \ No newline at end of file diff --git a/test/testDECODE.R b/test/testDECODE.R index de20c61..329994d 100644 --- a/test/testDECODE.R +++ b/test/testDECODE.R @@ -7,7 +7,7 @@ # 3 # 2 -tdf <- td.data.frame("test") +tdf <- td.data.frame("tab1") tdf["c10"] <- DECODE(tdf["c1"], default='none', 1, 'Alpha', 2, 'Bravo', 3, 'Charlie', 4, 'Delta') as.td.data.frame(tdf, tableName="tab2") From ea84d32e14e51a43e73ed06acb0153e47252af57 Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 16:42:38 -0700 Subject: [PATCH 10/28] fixed and tested POWER() --- R/POWER.R | 31 +++++++++++++++++++++---------- test/testPOWER.R | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 test/testPOWER.R diff --git a/R/POWER.R b/R/POWER.R index 861c888..bbd4b55 100755 --- a/R/POWER.R +++ b/R/POWER.R @@ -4,22 +4,33 @@ POWER <- function(x, exponent = 1) { return(x) } - pfmt <- "POWER(CAST(%s AS FLOAT),%d)" + pfmt <- "POWER(%s, %s)" if (inherits(x, "td.data.frame")) { - if (length(x) == 1) { - if (!is.null(attr(x, "expressions"))) - val <- attr(x, "expressions")[[names(x)]] else val <- names(x) - - } else { - message("POWER warning: td.data.frame 'x' has length > 1 using first element") - val <- names(x)[1] + if (length(x) == 1 || length(exponent0) == 1) { + if (!is.null(attr(x, "expressions"))) { + val1 <- attr(x, "expressions")[[names(x)]] + } + else { + val1 <- names(x) + } + if (!is.null(attr(exponent, "expressions"))) { + val2 <- attr(exponent, "expressions")[[names(x)]] + } + else { + val2 <- names(exponent) + } + } + else { + message("POWER warning: td.data.frame 'x' or 'exponent' has length > 1 using first element") + val1 <- names(x)[1] + val2 <- names(exponent)[1] } - return(asTdExpr(gettextf(pfmt, val, exponent))) + return(asTdExpr(gettextf(pfmt, val1, val2))) } if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("POWER(CAST(", x, " AS FLOAT),", exponent, ")", sep = ""))) + return(asTdExpr(paste("POWER(", x, exponent, ")", sep = ""))) } } diff --git a/test/testPOWER.R b/test/testPOWER.R new file mode 100644 index 0000000..4b79c0b --- /dev/null +++ b/test/testPOWER.R @@ -0,0 +1,21 @@ +# Below is the table used for the test, called "tab1" +# c1 c2 +# ----------- ----------- +# 5 6 +# 4 8 +# 3 9 +# 1 2 +# 2 7 + +tdf <- td.data.frame("tab") +tdf['c3'] <- POWER(tdf['c1'], tdf['c2']) +as.td.data.frame(tdf, tableName="tab2") + +#this is the resulting table, called "tab2" +# c1 c2 c3 c +# ----------- ----------- ---------- +# 5 6 156 +# 4 8 655 +# 3 9 196 +# 1 2 +# 2 7 1 From c166a30074ac4113c6d7426f6b8ef8832f0d4b2c Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 16:52:32 -0700 Subject: [PATCH 11/28] tested SIGN() --- test/testSIGN.R | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test/testSIGN.R diff --git a/test/testSIGN.R b/test/testSIGN.R new file mode 100644 index 0000000..7f314a2 --- /dev/null +++ b/test/testSIGN.R @@ -0,0 +1,20 @@ +# Below is the table used for the test, called "tab1" +# +# c1 +# ---- +# 5 +# 4 +# 3 +# 2 + +tdf <- td.data.frame("tab") +tdf["c2"] <- SIGN(tdf["c1"]) +as.td.data.frame(tdf, tableName="tab2") + +#this is the resulting table, called "tab2" +# c1 c2 +# ---- ------- +# 5 1 +# 4 1 +# 3 1 +# 2 1 \ No newline at end of file From b5c2b8ab8f1191c6a479f2c51c8eb8cd9b5f9343 Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 17:47:10 -0700 Subject: [PATCH 12/28] fixed and tested TO_CHAR() --- R/TO_CHAR.R | 35 +++++++++++++++++++++++------------ test/testTO_CHAR.R | 19 +++++++++++++++++++ 2 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 test/testTO_CHAR.R diff --git a/R/TO_CHAR.R b/R/TO_CHAR.R index 4e583e3..9acf2ce 100755 --- a/R/TO_CHAR.R +++ b/R/TO_CHAR.R @@ -1,25 +1,36 @@ -TO_CHAR <- function(x, format = " ") { +TO_CHAR <- function(x, format) { asTdExpr <- function(x) { class(x) <- "td.expression" return(x) } - tfmt <- "TO_CHAR(%s,%s)" - if (inherits(x, "td.data.frame")) { - if (length(x) == 1) { - if (!is.null(attr(x, "expressions"))) - val <- attr(x, "expressions")[[names(x)]] else val <- names(x) - - } else { - message("TO_CHAR warning: td.data.frame 'x' has length > 1 using first element") - val <- names(x)[1] + tfmt <- "TO_CHAR(%s, %s)" + if (inherits(x, "td.data.frame") || inherits(format, "td.data.frame")) { + if (length(x) == 1 || length(format) == 1) { + if (!is.null(attr(x, "expressions"))) { + val1 <- attr(x, "expressions")[[names(x)]] + } + else { + val1 <- names(x) + } + if (!is.null(attr(format, "expressions"))) { + val2 <- attr(format, "expressions")[[names(format)]] + } + else { + val2 <- names(format) + } + } + else { + message("TO_CHAR warning: td.data.frame 'x' or 'format' has length > 1 using first element") + val1 <- names(x)[1] + val2 <- names(format)[1] } - return(asTdExpr(gettextf(tfmt, val, format))) + return(asTdExpr(gettextf(tfmt, val1, val2))) } if (inherits(x, "character") || inherits(x, "td.expression")) { - return(asTdExpr(paste("TO_CHAR(", x, ",", format, ")", sep = ""))) + return(asTdExpr(paste("TO_CHAR(", x, format, ")", sep = ""))) } } diff --git a/test/testTO_CHAR.R b/test/testTO_CHAR.R new file mode 100644 index 0000000..ef39bb6 --- /dev/null +++ b/test/testTO_CHAR.R @@ -0,0 +1,19 @@ +# Below is the table used for the test, called "tab1" +# c1 c2 c3 +# ------- -- +# 3. 9 ? +# 9. 9 ? +# 6. 9 ? +# 1. 9 ? + +tdf <- td.data.frame("tab1") +tdf["c3"] <- TO_CHAR(tdf["c1"], tdf["c2"]) +as.td.data.frame(tdf, tableName="tab2") + +# this is the resulting table, called "tab2" +# c1 c2 c3 +# --- ---- -- +# 3. 9 ? +# 9. 9 ? +# 6. 9 ? +# 1. 9 ? \ No newline at end of file From de284f32aab72e03445f95f423bc2d905d8b5d7d Mon Sep 17 00:00:00 2001 From: erindcole Date: Mon, 12 Sep 2016 17:48:00 -0700 Subject: [PATCH 13/28] fixed some errors in POWER() --- R/POWER.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/POWER.R b/R/POWER.R index bbd4b55..2cdbc28 100755 --- a/R/POWER.R +++ b/R/POWER.R @@ -6,7 +6,7 @@ POWER <- function(x, exponent = 1) { pfmt <- "POWER(%s, %s)" if (inherits(x, "td.data.frame")) { - if (length(x) == 1 || length(exponent0) == 1) { + if (length(x) == 1 || length(exponent) == 1) { if (!is.null(attr(x, "expressions"))) { val1 <- attr(x, "expressions")[[names(x)]] } @@ -14,7 +14,7 @@ POWER <- function(x, exponent = 1) { val1 <- names(x) } if (!is.null(attr(exponent, "expressions"))) { - val2 <- attr(exponent, "expressions")[[names(x)]] + val2 <- attr(exponent, "expressions")[[names(exponent)]] } else { val2 <- names(exponent) From accb573af534fc3fee060b75358a92d65e54fbe7 Mon Sep 17 00:00:00 2001 From: erindcole Date: Tue, 13 Sep 2016 17:17:08 -0700 Subject: [PATCH 14/28] deleted test file that is not needed --- test/testtoQuery.R | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test/testtoQuery.R diff --git a/test/testtoQuery.R b/test/testtoQuery.R deleted file mode 100644 index 5a4bdef..0000000 --- a/test/testtoQuery.R +++ /dev/null @@ -1 +0,0 @@ -query1 <- toQuery(selectPhrase=string, ons=string, phase="local", as="D2") \ No newline at end of file From 9a20c67ef4254d19da872ca26a627f35d3e2a82d Mon Sep 17 00:00:00 2001 From: erindcole Date: Tue, 13 Sep 2016 17:18:47 -0700 Subject: [PATCH 15/28] made test cases more usable --- test/testCHR.R | 28 +++++++++++----------- test/testDECODE.R | 52 +++++++++++++++++++++++++++------------- test/testINITCAP.R | 43 +++++++++++++++++++++------------ test/testPOWER.R | 55 +++++++++++++++++++++++++++--------------- test/testSIGN.R | 59 ++++++++++++++++++++++++++++++++-------------- test/testTO_CHAR.R | 55 +++++++++++++++++++++++++++++------------- 6 files changed, 192 insertions(+), 100 deletions(-) diff --git a/test/testCHR.R b/test/testCHR.R index 0e416a8..44d47a1 100644 --- a/test/testCHR.R +++ b/test/testCHR.R @@ -1,22 +1,22 @@ # Below is the table used for the test, called "test" -# c1 c2 c5 c6 c7 -# ----------- -------- ---------- ---------- -- -# 5 Emily cat dog -# 4 Daisy fork spoon -# 3 Hank ball bat -# 2 Amy robot human +# c1 c2 c3 +# ---------- ----------- ---------- +# 3 ball bat +# 4 robot human +# 1 cat dog +# 2 fork spoon tdf <- td.data.frame("test") -tdf["c7"] <- CHR(tdf["c1"]) -as.td.data.frame(tdf, "test2") +tdf["c4"] <- CHR(tdf["c1"]) +as.td.data.frame(tdf, tableName="test2") # the resulting table is below, called "test2" -# c1 c2 c5 c6 c7 -# ----------- -------- ---------- ---------- -- -# 5 Emily cat dog -# 4 Daisy fork spoon -# 3 Hank ball bat -# 2 Amy robot human +# c1 c2 c3 c4 +# ---------- ----------- ---------- -------- +# 3 ball bat +# 4 robot human +# 1 cat dog +# 2 fork spoon #Although the resulting table does not seem to give the expected output, the same output occurs in bteq and in RStudio. #Further testing is recommended \ No newline at end of file diff --git a/test/testDECODE.R b/test/testDECODE.R index 329994d..ecca1f6 100644 --- a/test/testDECODE.R +++ b/test/testDECODE.R @@ -1,20 +1,38 @@ -# Below is the table used for the test, called "tab1" +# Below is the table used for the test, called "numTab" # -# c1 -# ---- -# 5 -# 4 -# 3 -# 2 +# c1 c2 c3 +# ----------- ----------- -- +# 5 2 9 +# 6 3 9 +# 3 2 9 +# 8 3 9 +# 2 4 9 -tdf <- td.data.frame("tab1") -tdf["c10"] <- DECODE(tdf["c1"], default='none', 1, 'Alpha', 2, 'Bravo', 3, 'Charlie', 4, 'Delta') -as.td.data.frame(tdf, tableName="tab2") +tdf <- td.data.frame("numTab") +tdf["c4"] <- DECODE(tdf["c1"], default='none', 1, 'Alpha', 2, 'Bravo', 3, 'Charlie', 4, 'Delta', 5, 'Echo') +as.td.data.frame(tdf, tableName="numTab2") -#this is the resulting table, called "tab2" -# c1 c10 -# ---- ------- -# 5 none -# 4 Delta -# 3 Charlie -# 2 Bravo +# This is the resulting table, called "numTab2" +# c1 c2 c3 c4 +# ----------- ----------- -- ------- +# 5 2 9 Echo +# 6 3 9 none +# 3 2 9 Charlie +# 8 3 9 none +# 2 4 9 Bravo + +# To verify each entry of c4: +res1 = tdQuery("select c4 from numTab2 where c1=5") == "Echo" +stopifnot(res1) + +res2 = tdQuery("select c4 from numTab2 where c1=6") == "none" +stopifnot(res2) + +res3 = tdQuery("select c4 from numTab2 where c1=3") == "Charlie" +stopifnot(res3) + +res4 = tdQuery("select c4 from numTab2 where c1=8") == "none" +stopifnot(res4) + +res5 = tdQuery("select c4 from numTab2 where c1=2") == "Bravo" +stopifnot(res5) \ No newline at end of file diff --git a/test/testINITCAP.R b/test/testINITCAP.R index 6dc8b1a..8b8bad2 100644 --- a/test/testINITCAP.R +++ b/test/testINITCAP.R @@ -1,20 +1,33 @@ # Below is the table used for the test, called "test" -# c1 c2 c3 c4 c5 c6 -#----------- -------- -- -- ---------- ---------- -# 5 Emily ? cat dog -# 4 Daisy ? ? fork spoon -# 3 Hank ? ? ball bat -# 2 Amy ? ? robot human +# c1 c2 c3 +# ---------- ----------- ---------- +# 3 ball bat +# 4 robot human +# 1 cat dog +# 2 fork spoon # # the R code is below: tdf <- td.data.frame("test") -tdf["c7"] <- INITCAP(tdf["c5"]) -as.td.data.frame(tdf, tableName="testZ") +tdf["c4"] <- INITCAP(tdf["c2"]) +as.td.data.frame(tdf, tableName="test2") -# Below are the results of the table, when you type "select * from testZ" -# c1 c2 c3 c4 c5 c6 c7 -# ----------- -------- -- -- ---------- ---------- -# 5 Emily ? cat dog Cat -# 4 Daisy ? ? fork spoon Fork -# 3 Hank ? ? ball bat Ball -# 2 Amy ? ? robot human Robot +# Below are the results of the table, when you type "select * from test2" +# c1 c2 c3 c4 +# ---------- ----------- ---------- --------- +# 3 ball bat Ball +# 4 robot human Robot +# 1 cat dog Cat +# 2 fork spoon Fork +# +# To verify each entry of test2 +res1 = tdQuery("select c4 from test2 where c1=3") == "Ball" +stopifnot(res1) + +res2 = tdQuery("select c4 from test2 where c1=4") == "Robot" +stopifnot(res2) + +res3 = tdQuery("select c4 from test2 where c1=1") == "Cat" +stopifnot(res3) + +res4 = tdQuery("select c4 from test2 where c1=2") == "Fork" +stopifnot(res4) \ No newline at end of file diff --git a/test/testPOWER.R b/test/testPOWER.R index 4b79c0b..0f73292 100644 --- a/test/testPOWER.R +++ b/test/testPOWER.R @@ -1,21 +1,38 @@ -# Below is the table used for the test, called "tab1" -# c1 c2 -# ----------- ----------- -# 5 6 -# 4 8 -# 3 9 -# 1 2 -# 2 7 +# Below is the table used for the test, called "numTab" +# +# c1 c2 c3 +# ----------- ----------- -- +# 5 2 9 +# 6 3 9 +# 3 2 9 +# 8 3 9 +# 2 4 9 -tdf <- td.data.frame("tab") -tdf['c3'] <- POWER(tdf['c1'], tdf['c2']) -as.td.data.frame(tdf, tableName="tab2") +tdf <- td.data.frame("numTab") +tdf['c4'] <- POWER(tdf['c1'], tdf['c2']) +as.td.data.frame(tdf, tableName="numTab2") -#this is the resulting table, called "tab2" -# c1 c2 c3 c -# ----------- ----------- ---------- -# 5 6 156 -# 4 8 655 -# 3 9 196 -# 1 2 -# 2 7 1 +# this is the resulting table, called "numTab2" +# c1 c2 c3 c4 +# ----------- ----------- -- ---------------------------------------- +# 5 2 9 25 +# 6 3 9 216 +# 3 2 9 9 +# 8 3 9 512 +# 2 4 9 16 + +# To verify each entry of c4: +res1 = tdQuery("select c4 from numTab2 where c1=5") == 25 +stopifnot(res1) + +res2 = tdQuery("select c4 from numTab2 where c1=6") == 216 +stopifnot(res2) + +res3 = tdQuery("select c4 from numTab2 where c1=3") == 9 +stopifnot(res3) + +res4 = tdQuery("select c4 from numTab2 where c1=8") == 512 +stopifnot(res4) + +res5 = tdQuery("select c4 from numTab2 where c1=2") == 16 +stopifnot(res5) \ No newline at end of file diff --git a/test/testSIGN.R b/test/testSIGN.R index 7f314a2..3a8b9e0 100644 --- a/test/testSIGN.R +++ b/test/testSIGN.R @@ -1,20 +1,43 @@ -# Below is the table used for the test, called "tab1" +# Below is the table used for the test, called "negNums" # -# c1 -# ---- -# 5 -# 4 -# 3 -# 2 - -tdf <- td.data.frame("tab") +# c1 +# ----------- +# 3 +# -11 +# 0 +# 4 +# -2 +# 555 + +tdf <- td.data.frame("negNums") tdf["c2"] <- SIGN(tdf["c1"]) -as.td.data.frame(tdf, tableName="tab2") - -#this is the resulting table, called "tab2" -# c1 c2 -# ---- ------- -# 5 1 -# 4 1 -# 3 1 -# 2 1 \ No newline at end of file +as.td.data.frame(tdf, tableName="negNums2") + +#this is the resulting table, called "negNums2" +# c1 c2 +# ----------- ---------------------------------------- +# 3 1 +# -11 -1 +# 0 0 +# 4 1 +# -2 -1 +# 555 1 + +# To verify each entry of c2: +res1 = tdQuery("select c2 from negNums2 where c1=3") ==1 +stopifnot(res1) + +res2 = tdQuery("select c2 from negNums2 where c1=-11") == -1 +stopifnot(res2) + +res3 = tdQuery("select c2 from negNums2 where c1=0") == 0 +stopifnot(res3) + +res4 = tdQuery("select c2 from negNums2 where c1=4") == 1 +stopifnot(res4) + +res5 = tdQuery("select c2 from negNums2 where c1=-2") == -1 +stopifnot(res5) + +res6 = tdQuery("select c2 from negNums2 where c1=555") == 1 +stopifnot(res6) \ No newline at end of file diff --git a/test/testTO_CHAR.R b/test/testTO_CHAR.R index ef39bb6..89af1e3 100644 --- a/test/testTO_CHAR.R +++ b/test/testTO_CHAR.R @@ -1,19 +1,40 @@ -# Below is the table used for the test, called "tab1" -# c1 c2 c3 -# ------- -- -# 3. 9 ? -# 9. 9 ? -# 6. 9 ? -# 1. 9 ? +# Below is the table used for the test, called "numTab" +# c1 c2 c3 +# ----------- ----------- -- +# 5 2 9 +# 6 3 9 +# 3 2 9 +# 8 3 9 +# 2 4 9 -tdf <- td.data.frame("tab1") -tdf["c3"] <- TO_CHAR(tdf["c1"], tdf["c2"]) -as.td.data.frame(tdf, tableName="tab2") +tdf <- td.data.frame("numTab") +tdf["c4"] <- TO_CHAR(tdf["c1"], tdf["c3"]) +as.td.data.frame(tdf, tableName="numTab2") -# this is the resulting table, called "tab2" -# c1 c2 c3 -# --- ---- -- -# 3. 9 ? -# 9. 9 ? -# 6. 9 ? -# 1. 9 ? \ No newline at end of file +# this is the resulting table, called "numTab2" Although the values look +# unchanged, the type of 'c4' is a varchar, while the type of 'c1' is an +# integer. This can be verified by typing "show table numTab2" into bteq or +# "tdQuery("show table numTab2")" into RStudio. +# c1 c2 c3 c4 +# ----------- ----------- -- ------------------------------------------------ +# 5 2 9 5 +# 6 3 9 6 +# 3 2 9 3 +# 8 3 9 8 +# 2 4 9 2 + +# To verify each entry of c4: +res1 = tdQuery("select c4 from numTab2 where c1=5") == '5' +stopifnot(res1) + +res2 = tdQuery("select c4 from numTab2 where c1=6") == '6' +stopifnot(res2) + +res3 = tdQuery("select c4 from numTab2 where c1=3") == '3' +stopifnot(res3) + +res4 = tdQuery("select c4 from numTab2 where c1=8") == '8' +stopifnot(res4) + +res5 = tdQuery("select c4 from numTab2 where c1=2") == '2' +stopifnot(res5) \ No newline at end of file From 73203552a3d23186e980350789329526729401e1 Mon Sep 17 00:00:00 2001 From: erindcole Date: Tue, 13 Sep 2016 17:19:50 -0700 Subject: [PATCH 16/28] made a file that contains code to make tables for my tests --- test/setup.R | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test/setup.R diff --git a/test/setup.R b/test/setup.R new file mode 100644 index 0000000..c5ceb27 --- /dev/null +++ b/test/setup.R @@ -0,0 +1,69 @@ +# Although this file is an R file, for the sake of consistency with the other +# files, the code is in SQL. It is all commented out so that the file does not +# produce compile errors. Please copy and past the desired code into bteq in +# order to make the needed tables + +# Table Name: numTab +# This table is used for testing numeric functions. It works with the tests for +# DECODE(), POWER(), and TO_CHAR(). +# +# drop table numTab; +# drop table numTab2; +# create table numTab ( +# c1 integer, +# c2 integer, +# c3 character(1)); +# +# insert into numTab (c1, c2, c3) values (5, 2, '9'); +# insert into numTab (c1, c2, c3) values (8, 3, '9'); +# insert into numTab (c1, c2, c3) values (2, 4, '9'); +# insert into numTab (c1, c2, c3) values (6, 3, '9'); +# insert into numTab (c1, c2, c3) values (3, 2, '9'); +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Table Name: negNums +# This table is used for testing the SIGN() function +# +# drop table negNums; +# drop table negNums2; +# create table negNums ( +# c1 integer); +# +# insert into negNums values(-11); +# insert into negNums values(3); +# insert into negNums values(-2); +# insert into negNums values(4); +# insert into negNums values(555); +# insert into negNums values(0); +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Table Name: test +# This table is used for testing functions for character manipulation. It +# works with the tests for CHR() and INITCAP(). +# +# drop table test; +# drop table test2; +# create table test ( +# c1 integer, +# c2 varchar(256), +# c3 varchar(256)); +# +# insert into test (c1, c2, c3) values (1, 'cat', 'dog'); +# insert into test (c1, c2, c3) values (2, 'fork', 'spoon'); +# insert into test (c1, c2, c3) values (3, 'ball', 'bat'); +# insert into test (c1, c2, c3) values (4, 'robot', 'human'); +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Table Name: charTab +# This table is used for testing functions that search characters under +# certain conditions. It works with tests for INSTR(), +# +# drop table charTab; +# drop table charTab2; +# create table charTab ( +# c1 varchar(50), +# c2 varchar(50)); +# +# insert into charTab (c1, c2) values ('explore', 'lo'); +# insert into charTab (c1, c2) values ('interrupt', 'ter'); +# insert into charTab (c1, c2) values ('disappear', 'ar'); +# insert into charTab (c1, c2) values ('factor', 'ac'); +# insert into charTab (c1, c2) values ('appreciate', 'pp'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file From 87440c46605224ecf02f4819dd2f9066e15bc706 Mon Sep 17 00:00:00 2001 From: erindcole Date: Tue, 13 Sep 2016 17:33:37 -0700 Subject: [PATCH 17/28] final fixes to a test and modifications to setup.R --- test/setup.R | 15 ++++++++------- test/testINSTR.R | 36 ++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/test/setup.R b/test/setup.R index c5ceb27..2b58cf8 100644 --- a/test/setup.R +++ b/test/setup.R @@ -59,11 +59,12 @@ # drop table charTab2; # create table charTab ( # c1 varchar(50), -# c2 varchar(50)); +# c2 varchar(50), +# c3 varchar(50)); # -# insert into charTab (c1, c2) values ('explore', 'lo'); -# insert into charTab (c1, c2) values ('interrupt', 'ter'); -# insert into charTab (c1, c2) values ('disappear', 'ar'); -# insert into charTab (c1, c2) values ('factor', 'ac'); -# insert into charTab (c1, c2) values ('appreciate', 'pp'); -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file +# insert into charTab (c1, c2) values ('explore', 'lo', 'xx'); +# insert into charTab (c1, c2) values ('interrupt', 'ter', 'xyz'); +# insert into charTab (c1, c2) values ('disappear', 'ar', 'yy'); +# insert into charTab (c1, c2) values ('factor', 'ac', 'xy'); +# insert into charTab (c1, c2) values ('appreciate', 'pp', 'xx'); +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/test/testINSTR.R b/test/testINSTR.R index 0d74bba..ff972d8 100644 --- a/test/testINSTR.R +++ b/test/testINSTR.R @@ -1,24 +1,24 @@ -# Below is the table used for the test, called "tab1" -# c1 c2 -# ---------- ---- -# explore lo -# interrupt ter -# disappear ar -# factor ac -# appreciate pp +# Below is the table used for the test, called "charTab" +# c1 c2 c3 +# ---------- ---- ------- +# explore lo xx +# interrupt ter xyz +# disappear ar yy +# factor ac xy +# appreciate pp xx -tdf <- td.data.frame("tab1") +tdf <- td.data.frame("charTab") tdf["c3"] <- INSTR(tdf["c1"], tdf["c2"]) -as.td.data.frame(tdf, tableName="tab2") +as.td.data.frame(tdf, tableName="charTab2") -# This is the resulting table, called "tab2" -# c1 c2 c3 -# ---------- ---- ---------------------------------------- -# explore lo 0 -# interrupt ter 0 -# disappear ar 0 -# factor ac 0 -# appreciate pp 0 +# This is the resulting table, called "charTab2" +# c1 c2 c3 +# ---------- ---- ------- +# explore lo xx +# interrupt ter xyz +# disappear ar yy +# factor ac xy +# appreciate pp xx # While running the equivalent code in bteq produces the same table, this test does not seem to give the expected output # I recommend further testing. \ No newline at end of file From 6e08a197ba6b784c6696bdcc268fe06dbc48b127 Mon Sep 17 00:00:00 2001 From: erindcole Date: Wed, 14 Sep 2016 13:16:50 -0700 Subject: [PATCH 18/28] made tests more usable --- test/testCHR.R | 25 ++++++++++--------- test/testINITCAP.R | 37 +++++++++++++++++----------- test/testNGRAM.R | 56 ++++++++++++++++++++++++++++++------------- test/testOREPLACE.R | 55 ++++++++++++++++++++++++++---------------- test/testOTRANSLATE.R | 52 +++++++++++++++++++++++++++------------- test/testRPAD.R | 47 +++++++++++++++++++++++------------- test/testRTRIM.R | 43 ++++++++++++++++++++------------- 7 files changed, 202 insertions(+), 113 deletions(-) diff --git a/test/testCHR.R b/test/testCHR.R index 44d47a1..7e2a445 100644 --- a/test/testCHR.R +++ b/test/testCHR.R @@ -1,22 +1,25 @@ # Below is the table used for the test, called "test" # c1 c2 c3 # ---------- ----------- ---------- -# 3 ball bat -# 4 robot human -# 1 cat dog -# 2 fork spoon - +# 5 cat dog +# 4 robot human +# 6 horse force +# 3 ball bat +# 1 mouse house +# 2 fork spoon tdf <- td.data.frame("test") tdf["c4"] <- CHR(tdf["c1"]) as.td.data.frame(tdf, tableName="test2") # the resulting table is below, called "test2" -# c1 c2 c3 c4 -# ---------- ----------- ---------- -------- -# 3 ball bat -# 4 robot human -# 1 cat dog -# 2 fork spoon +# c1 c2 c3 c4 +# ---------- ----------- ---------- --------- +# 5 cat dog +# 4 robot human +# 6 horse force +# 3 ball bat +# 1 mouse house +# 2 fork spoon #Although the resulting table does not seem to give the expected output, the same output occurs in bteq and in RStudio. #Further testing is recommended \ No newline at end of file diff --git a/test/testINITCAP.R b/test/testINITCAP.R index 8b8bad2..4560285 100644 --- a/test/testINITCAP.R +++ b/test/testINITCAP.R @@ -1,33 +1,42 @@ # Below is the table used for the test, called "test" # c1 c2 c3 # ---------- ----------- ---------- -# 3 ball bat -# 4 robot human -# 1 cat dog -# 2 fork spoon -# +# 5 cat dog +# 4 robot human +# 6 horse force +# 3 ball bat +# 1 mouse house +# 2 fork spoon # the R code is below: tdf <- td.data.frame("test") tdf["c4"] <- INITCAP(tdf["c2"]) as.td.data.frame(tdf, tableName="test2") # Below are the results of the table, when you type "select * from test2" -# c1 c2 c3 c4 +# c1 c2 c3 c4 # ---------- ----------- ---------- --------- -# 3 ball bat Ball -# 4 robot human Robot -# 1 cat dog Cat -# 2 fork spoon Fork +# 5 cat dog Cat +# 4 robot human Robot +# 6 horse force Horse +# 3 ball bat Ball +# 1 mouse house Mouse +# 2 fork spoon Fork # # To verify each entry of test2 -res1 = tdQuery("select c4 from test2 where c1=3") == "Ball" +res1 = tdQuery("select c4 from test2 where c1=5") == "Cat" stopifnot(res1) res2 = tdQuery("select c4 from test2 where c1=4") == "Robot" stopifnot(res2) -res3 = tdQuery("select c4 from test2 where c1=1") == "Cat" +res3 = tdQuery("select c4 from test2 where c1=6") == "Horse" stopifnot(res3) -res4 = tdQuery("select c4 from test2 where c1=2") == "Fork" -stopifnot(res4) \ No newline at end of file +res4 = tdQuery("select c4 from test2 where c1=3") == "Ball" +stopifnot(res4) + +res5 = tdQuery("select c4 from test2 where c1=1") == "Mouse" +stopifnot(res5) + +res6 = tdQuery("select c4 from test2 where c1=2") == "Fork" +stopifnot(res6) \ No newline at end of file diff --git a/test/testNGRAM.R b/test/testNGRAM.R index 6d7b3e2..da911ae 100644 --- a/test/testNGRAM.R +++ b/test/testNGRAM.R @@ -1,19 +1,41 @@ -# Below is the table used for the test, called "tab2" -# c1 c2 c3 -# ---------- ---------- ---------- -# mouse house ? -# wagon wagon ? -# cart heart ? -# horse force ? +# Below is the table used for the test, called "test" +# c1 c2 c3 +# ---------- ----------- ---------- +# 5 cat dog +# 4 robot human +# 6 horse force +# 3 ball bat +# 1 mouse house +# 2 fork spoon -tdf <- td.data.frame("tab2") -tdf["c3"] <- NGRAM(tdf["c1"], tdf["c2"], 2) -as.td.data.frame(tdf, tableName="tab3") +tdf <- td.data.frame("test") +tdf["c4"] <- NGRAM(tdf["c2"], tdf["c3"], 2) +as.td.data.frame(tdf, tableName="test2") -#this is the resulting table -# c1 c2 c3 -# ---------- ---------- ----------- -# mouse house 8 -# wagon wagon 9 -# cart heart 8 -# horse force 6 \ No newline at end of file +#this is the resulting table, called "test2" +# c1 c2 c3 c4 +# ---------- ----------- ---------- --------- +# 5 cat dog 0 +# 4 robot human 0 +# 6 horse force 1 +# 3 ball bat 1 +# 1 mouse house 3 +# 2 fork spoon 0 +# +res1 = tdQuery("select c4 from test2 where c1=5") == 0 +stopifnot(res1) + +res2 = tdQuery("select c4 from test2 where c1=4") == 0 +stopifnot(res2) + +res3 = tdQuery("select c4 from test2 where c1=6") == 1 +stopifnot(res3) + +res4 = tdQuery("select c4 from test2 where c1=3") == 1 +stopifnot(res4) + +res5 = tdQuery("select c4 from test2 where c1=1") == 3 +stopifnot(res5) + +res6 = tdQuery("select c4 from test2 where c1=2") == 0 +stopifnot(res6) \ No newline at end of file diff --git a/test/testOREPLACE.R b/test/testOREPLACE.R index 4936532..3b20a50 100644 --- a/test/testOREPLACE.R +++ b/test/testOREPLACE.R @@ -1,24 +1,37 @@ -# Below is the table used for the test, called "tab2" -# c1 c2 c3 -# ---------- ---- ---------- -# explore lo ? -# interrupt ter xyz -# disappear ar xy -# factor ac xy -# appreciate pp xy +# Below is the table used for the test, called "charTab" +# c1 c2 c3 c4 c5 +# ---------- ---- ------- --------- --------- +# explore lo xx e z +# interrupt ter xyz u z +# disappear ar yy s z +# factor ac xy c z +# appreciate pp xx r z -tdf <- td.data.frame("tab2") -tdf["c4"] <- OREPLACE(tdf["c1"], tdf["c2"], tdf["c3"]) -as.td.data.frame(tdf, tableName="tab3") +tdf <- td.data.frame("charTab") +tdf["c6"] <- OREPLACE(tdf["c1"], tdf["c2"], tdf["c3"]) +as.td.data.frame(tdf, tableName="charTab2") -#this is the resulting table, tab3 -# c1 c2 c3 c4 -# ---------- ---- ---------- ------------------------------------------------ -# explore lo ? explore -# interrupt ter xyz interrupt -# disappear ar xy disappear -# factor ac xy factor -# appreciate pp xy appreciate +#this is the resulting table, charTab2 +# c1 c2 c3 c4 c5 c6 +# ---------- ---- ------- --------- --------- ---------- +# explore lo xx e z expxxre +# interrupt ter xyz u z inxyzrupt +# disappear ar yy s z disappeyy +# factor ac xy c z fxytor +# appreciate pp xx r z axxreciate +# +# To verify each entry of c6: +res1 = tdQuery("select c6 from charTab2 where c1='explore'") == "expxxre" +stopifnot(res1) -#although this test did produce the same table/dataframe in both bteq and -#RStudio, further testing on how to get the expected output is suggested \ No newline at end of file +res2 = tdQuery("select c6 from charTab2 where c1='interrupt'") == "inxyzrupt" +stopifnot(res2) + +res3 = tdQuery("select c6 from charTab2 where c1='disappear'") == "disappeyy" +stopifnot(res3) + +res4 = tdQuery("select c6 from charTab2 where c1='factor'") == "fxytor" +stopifnot(res4) + +res5 = tdQuery("select c6 from charTab2 where c1='appreciate'") == "axxreciate" +stopifnot(res5) \ No newline at end of file diff --git a/test/testOTRANSLATE.R b/test/testOTRANSLATE.R index e67a2a5..0a98f2a 100644 --- a/test/testOTRANSLATE.R +++ b/test/testOTRANSLATE.R @@ -1,20 +1,38 @@ -# Below is the table used for the test, called "tab1" -# c1 c2 c3 c4 -# ---------- -- -- ---------- -# outstanding s x ? -# shrewd r x ? -# amicable i x ? -# introverted t x ? +# Below is the table used for the test, called "charTab" +# c1 c2 c3 c4 c5 +# ---------- ---- ------- --------- --------- +# explore lo xx e z +# interrupt ter xyz u z +# disappear ar yy s z +# factor ac xy c z +# appreciate pp xx r z -tdf <- td.data.frame("tab1") -tdf["c4"] <- OTRANSLATE(tdf["c1"], tdf["c2"], tdf["c3"]) -as.td.data.frame(tdf, tableName="tab2") +tdf <- td.data.frame("charTab") +tdf["c6"] <- OTRANSLATE(tdf["c1"], tdf["c4"], tdf["c5"]) +as.td.data.frame(tdf, tableName="charTab2") -#this is the resulting table, tab2 +#this is the resulting table, charTab2 +# +# c1 c2 c3 c4 c5 c6 +# ---------- ---- ------- --------- --------- ---------- +# explore lo xx e z zxplorz +# interrupt ter xyz u z interrzpt +# disappear ar yy s z dizappear +# factor ac xy c z faztor +# appreciate pp xx r z appzeciate -# c1 c2 c3 c4 -# ---------- -- -- ---------------------------------------------------------- -# outstanding s x outxtanding -# shrewd r x shxewd -# amicable i x amxcable -# introverted t x inxroverxed \ No newline at end of file +# To verify each entry of c6: +res1 = tdQuery("select c6 from charTab2 where c1='explore'") == "zxplorz" +stopifnot(res1) + +res2 = tdQuery("select c6 from charTab2 where c1='interrupt'") == "interrzpt" +stopifnot(res2) + +res3 = tdQuery("select c6 from charTab2 where c1='disappear'") == "dizappear" +stopifnot(res3) + +res4 = tdQuery("select c6 from charTab2 where c1='factor'") == "faztor" +stopifnot(res4) + +res5 = tdQuery("select c6 from charTab2 where c1='appreciate'") == "appzeciate" +stopifnot(res5) \ No newline at end of file diff --git a/test/testRPAD.R b/test/testRPAD.R index 54b836d..8761d80 100644 --- a/test/testRPAD.R +++ b/test/testRPAD.R @@ -1,20 +1,33 @@ -# Below is the table used for the test, called "test" -# c1 c2 c3 c4 c5 c6 -#----------- -------- -- -- ---------- ---------- -# 5 Emily ? cat dog -# 4 Daisy ? ? fork spoon -# 3 Hank ? ? ball bat -# 2 Amy ? ? robot human +# Below is the table used for the test, called "padTab" +# c1 c2 c3 +# --------------- --------------- --------------- +# Emily Emily Emily +# Daisy Daisy Daisy +# Hank Hank Hank +# Amy Amy Amy # # the R code is below: -tdf <- td.data.frame("test") -tdf["c7"] <- RPAD(tdf["c5"], 15, " ") -as.td.data.frame(tdf, tableName="testY") +tdf <- td.data.frame("padTab") +tdf["c4"] <- RPAD(tdf["c3"], 15, "x") +as.td.data.frame(tdf, tableName="padTab2") -# Below are the results of the table, when you type "select * from testY" -# c1 c2 c3 c4 c5 c6 c7 -#----------- -------- -- -- ---------- ------------------------------------ -# 5 Emily ? cat dog cat -# 4 Daisy ? ? fork spoon fork -# 3 Hank ? ? ball bat ball -# 2 Amy ? ? robot human robot \ No newline at end of file +# Below are the results of the table, when you type "select * from padTab2" +# into bteq +# c1 c2 c3 c4 +# ---------- ---------- ---------- ------------------------------------------ +# Emily Emily Emily Emilyxxxxxxxxxx +# Daisy Daisy Daisy Daisyxxxxxxxxxx +# Hank Hank Hank Hankxxxxxxxxxxx +# Amy Amy Amy Amyxxxxxxxxxxxx +# +res1 = tdQuery("select c4 from padTab2 where c3='Emily'") == "Emilyxxxxxxxxxx" +stopifnot(res1) + +res2 = tdQuery("select c4 from padTab2 where c3='Daisy'") == "Daisyxxxxxxxxxx" +stopifnot(res2) + +res3 = tdQuery("select c4 from padTab2 where c3='Hank'") == "Hankxxxxxxxxxxx" +stopifnot(res3) + +res4 = tdQuery("select c4 from padTab2 where c3='Amy'") == "Amyxxxxxxxxxxxx" +stopifnot(res4) \ No newline at end of file diff --git a/test/testRTRIM.R b/test/testRTRIM.R index fc59b8c..793c5a1 100644 --- a/test/testRTRIM.R +++ b/test/testRTRIM.R @@ -1,17 +1,28 @@ -# Below is the table used for the test, called "tab1" -#c1 c2 c3 -#---------- ---------- ---------- -# horse horse ? -# mouse mouse ? -# dog dog ? -# cat cat ? +# Below is the table used for the test, called "padTab" +# c1 c2 c3 +# --------------- --------------- --------------- +# Emily Emily Emily +# Daisy Daisy Daisy +# Hank Hank Hank +# Amy Amy Amy -tdf <- td.data.frame("tab1") -tdf["c3"] <- LTRIM(tdf["c2"]) -as.td.data.frame(tdf, tableName="tab2") -#c1 c2 c3 -#---------- ---------- ----- -# horse horse horse -# mouse mouse mouse -# dog dog dog -# cat cat cat \ No newline at end of file +tdf <- td.data.frame("padTab") +tdf["c4"] <- RTRIM(tdf["c1"]) +as.td.data.frame(tdf, tableName="padTab2") +# c1 c2 c3 c4 +# ---------- ---------- ---------- ---------- +# Emily Emily Emily Emily +# Daisy Daisy Daisy Daisy +# Hank Hank Hank Hank +# Amy Amy Amy Amy +res1 = tdQuery("select c4 from padTab2 where c3='Emily'") == "Emily" +stopifnot(res1) + +res2 = tdQuery("select c4 from padTab2 where c3='Daisy'") == "Daisy" +stopifnot(res2) + +res3 = tdQuery("select c4 from padTab2 where c3='Hank'") == "Hank" +stopifnot(res3) + +res4 = tdQuery("select c4 from padTab2 where c3='Amy'") == "Amy" +stopifnot(res4) \ No newline at end of file From 88133f91dbd2a6f88855e9acce1edf61ab3102e3 Mon Sep 17 00:00:00 2001 From: erindcole Date: Wed, 14 Sep 2016 13:17:18 -0700 Subject: [PATCH 19/28] finished writing code to make tables for test cases --- test/setup.R | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/test/setup.R b/test/setup.R index 2b58cf8..d11ee87 100644 --- a/test/setup.R +++ b/test/setup.R @@ -37,34 +37,54 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Table Name: test # This table is used for testing functions for character manipulation. It -# works with the tests for CHR() and INITCAP(). +# works with the tests for CHR(), INITCAP(), and NGRAM(). # # drop table test; # drop table test2; # create table test ( # c1 integer, -# c2 varchar(256), -# c3 varchar(256)); +# c2 varchar(100), +# c3 varchar(100)); # -# insert into test (c1, c2, c3) values (1, 'cat', 'dog'); +# insert into test (c1, c2, c3) values (1, 'mouse', 'house'); # insert into test (c1, c2, c3) values (2, 'fork', 'spoon'); # insert into test (c1, c2, c3) values (3, 'ball', 'bat'); # insert into test (c1, c2, c3) values (4, 'robot', 'human'); -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# insert into test (c1, c2, c3) values (5, 'cat', 'dog'); +# insert into test (c1, c2, c3) values (6, 'horse', 'force'); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Table Name: charTab # This table is used for testing functions that search characters under -# certain conditions. It works with tests for INSTR(), +# certain conditions. It works with tests for INSTR(), OREPLACE(), OTRANSLATE(). # # drop table charTab; # drop table charTab2; # create table charTab ( # c1 varchar(50), # c2 varchar(50), -# c3 varchar(50)); +# c3 varchar(50), +# c4 varchar(50), +# c5 varchar(50)); +# +# insert into charTab (c1, c2, c3, c4, c5) values ('explore', 'lo', 'xx', 'e', 'z'); +# insert into charTab (c1, c2, c3, c4, c5) values ('interrupt', 'ter', 'xyz', 'u', 'z'); +# insert into charTab (c1, c2, c3, c4, c5) values ('disappear', 'ar', 'yy', 's', 'z'); +# insert into charTab (c1, c2, c3, c4, c5) values ('factor', 'ac', 'xy', 'c', 'z'); +# insert into charTab (c1, c2, c3, c4, c5) values ('appreciate', 'pp', 'xx', 'r', 'z'); +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Table Name: padTab +# This table is used for testing functions that manipulate white space. It +# works with tests for LPAD(), LTRIM(), RPAD(), and RTRIM(). +# +# drop table padTab; +# drop table padTab2; +# create table padTab ( +# c1 varchar(10), +# c2 varchar(10), +# c3 varchar(10)); # -# insert into charTab (c1, c2) values ('explore', 'lo', 'xx'); -# insert into charTab (c1, c2) values ('interrupt', 'ter', 'xyz'); -# insert into charTab (c1, c2) values ('disappear', 'ar', 'yy'); -# insert into charTab (c1, c2) values ('factor', 'ac', 'xy'); -# insert into charTab (c1, c2) values ('appreciate', 'pp', 'xx'); -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file +# insert into padTab (c1, c2, c3) values ('Emily ',' Emily', 'Emily'); +# insert into padTab (c1, c2, c3) values ('Daisy ', ' Daisy', 'Daisy'); +# insert into padTab (c1, c2, c3) values ('Hank ', ' Hank', 'Hank'); +# insert into padTab (c1, c2, c3) values ('Amy ', ' Amy', 'Amy'); +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file From 9b11b9667d6a2316ca7d195b94d30bf7bf3c87e5 Mon Sep 17 00:00:00 2001 From: erindcole Date: Wed, 14 Sep 2016 14:40:00 -0700 Subject: [PATCH 20/28] updated tests --- test/testINSTR.R | 30 +++++++++++++++--------------- test/testLPAD.R | 47 ++++++++++++++++++++++++++++++----------------- test/testLTRIM.R | 46 +++++++++++++++++++++++++++++----------------- 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/test/testINSTR.R b/test/testINSTR.R index ff972d8..acc23e5 100644 --- a/test/testINSTR.R +++ b/test/testINSTR.R @@ -1,24 +1,24 @@ # Below is the table used for the test, called "charTab" -# c1 c2 c3 -# ---------- ---- ------- -# explore lo xx -# interrupt ter xyz -# disappear ar yy -# factor ac xy -# appreciate pp xx +# c1 c2 c3 c4 c5 +# ---------- ---- ------- --------- --------- +# explore lo xx e z +# interrupt ter xyz u z +# disappear ar yy s z +# factor ac xy c z +# appreciate pp xx r z tdf <- td.data.frame("charTab") -tdf["c3"] <- INSTR(tdf["c1"], tdf["c2"]) +tdf["c6"] <- INSTR(tdf["c1"], tdf["c2"]) as.td.data.frame(tdf, tableName="charTab2") # This is the resulting table, called "charTab2" -# c1 c2 c3 -# ---------- ---- ------- -# explore lo xx -# interrupt ter xyz -# disappear ar yy -# factor ac xy -# appreciate pp xx +# c1 c2 c3 c4 c5 c6 +# ---------- ---- ------- --------- --------- --------- +# explore lo xx e z 4 +# interrupt ter xyz u z 3 +# disappear ar yy s z 8 +# factor ac xy c z 2 +# appreciate pp xx r z 2 # While running the equivalent code in bteq produces the same table, this test does not seem to give the expected output # I recommend further testing. \ No newline at end of file diff --git a/test/testLPAD.R b/test/testLPAD.R index 22e6009..b8feb86 100644 --- a/test/testLPAD.R +++ b/test/testLPAD.R @@ -1,20 +1,33 @@ -# Below is the table used for the test, called "test" -# c1 c2 c3 c4 c5 c6 -#----------- -------- -- -- ---------- ---------- -# 5 Emily ? cat dog -# 4 Daisy ? ? fork spoon -# 3 Hank ? ? ball bat -# 2 Amy ? ? robot human +# Below is the table used for the test, called "padTab" +# c1 c2 c3 +# --------------- --------------- --------------- +# Emily Emily Emily +# Daisy Daisy Daisy +# Hank Hank Hank +# Amy Amy Amy # # the R code is below: -tdf <- td.data.frame("test") -tdf["c7"] <- LPAD(tdf["c5"], 15, " ") -as.td.data.frame(tdf, tableName="testYY") +tdf <- td.data.frame("padTab") +tdf["c4"] <- LPAD(tdf["c3"], 15, "x") +as.td.data.frame(tdf, tableName="padTab2") -# Below are the results of the table, when you type "select * from testY" -# c1 c2 c3 c4 c5 c6 c7 -#----------- -------- -- -- ---------- ------------------------------------ -# 5 Emily ? cat dog cat -# 4 Daisy ? ? fork spoon fork -# 3 Hank ? ? ball bat ball -# 2 Amy ? ? robot human robot \ No newline at end of file +# Below are the results of the table, when you type "select * from padTab2" +# c1 c2 c3 c4 +# --------------- --------------- --------------- --------------------------- +# Emily Emily Emily xxxxxxxxxxEmily +# Daisy Daisy Daisy xxxxxxxxxxDaisy +# Hank Hank Hank xxxxxxxxxxxHank +# Amy Amy Amy xxxxxxxxxxxxAmy + +# To verify each entry of c4: +res1 = tdQuery("select c4 from padTab2 where c3='Emily'") == "xxxxxxxxxxEmily" +stopifnot(res1) + +res2 = tdQuery("select c4 from padTab2 where c3='Daisy'") == "xxxxxxxxxxDaisy" +stopifnot(res2) + +res3 = tdQuery("select c4 from padTab2 where c3='Hank'") == "xxxxxxxxxxxHank" +stopifnot(res3) + +res4 = tdQuery("select c4 from padTab2 where c3='Amy'") == "xxxxxxxxxxxxAmy" +stopifnot(res4) \ No newline at end of file diff --git a/test/testLTRIM.R b/test/testLTRIM.R index 089384f..c680571 100644 --- a/test/testLTRIM.R +++ b/test/testLTRIM.R @@ -1,19 +1,31 @@ -# Below is the table used for the test, called "tab1" -#c1 c2 c3 -#---------- ---------- ---------- -# horse horse ? -# mouse mouse ? -# dog dog ? -# cat cat ? +# Below is the table used for the test, called "padTab" +# c1 c2 c3 +# --------------- --------------- --------------- +# Emily Emily Emily +# Daisy Daisy Daisy +# Hank Hank Hank +# Amy Amy Amy -tdf <- td.data.frame("tab1") -tdf["c3"] <- LTRIM(tdf["c1"]) -as.td.data.frame(tdf, tableName="tab2") +tdf <- td.data.frame("padTab") +tdf["c4"] <- LTRIM(tdf["c2"]) +as.td.data.frame(tdf, tableName="padTab2") -#this is the resulting table -#c1 c2 c3 -#---------- ---------- ---------- -# horse horse horse -# mouse mouse mouse -# dog dog dog -# cat cat cat \ No newline at end of file +#this is the resulting table caled "padTab2" +# c1 c2 c3 c4 +# ---------- ---------- ---------- ---------- +# Emily Emily Emily Emily +# Daisy Daisy Daisy Daisy +# Hank Hank Hank Hank +# Amy Amy Amy Amy + +res1 = tdQuery("select c4 from padTab2 where c3='Emily'") == "Emily" +stopifnot(res1) + +res2 = tdQuery("select c4 from padTab2 where c3='Daisy'") == "Daisy" +stopifnot(res2) + +res3 = tdQuery("select c4 from padTab2 where c3='Hank'") == "Hank" +stopifnot(res3) + +res4 = tdQuery("select c4 from padTab2 where c3='Amy'") == "Amy" +stopifnot(res4) \ No newline at end of file From 7e7617095a281e64bcdad6adc2dc758ccf4626b3 Mon Sep 17 00:00:00 2001 From: erindcole Date: Wed, 14 Sep 2016 14:41:00 -0700 Subject: [PATCH 21/28] wrote tests for TRUNC() and TO_NUMBER() --- test/testTO_NUMBER.R | 50 ++++++++++++++++++++++++++++++++++++++++++++ test/testTRUNC.R | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 test/testTO_NUMBER.R create mode 100644 test/testTRUNC.R diff --git a/test/testTO_NUMBER.R b/test/testTO_NUMBER.R new file mode 100644 index 0000000..6c12cf9 --- /dev/null +++ b/test/testTO_NUMBER.R @@ -0,0 +1,50 @@ +# Below is the table used for the test, called "numManip" +# c1 c2 +# ----- ---------------------------------------- +# 2 8.289 +# 5 13.99 +# 4 17.06 +# 3 48.1 +# 1 555.3 +# +# the R code is below: +tdf <- td.data.frame("numManip") +tdf["c3"] <- TO_NUMBER(tdf['c1']) +as.td.data.frame(tdf, tableName="numManip2") +# +# Below are the results of the table, when you type "select * from numManip2" +# c1 c2 c3 +# ----- ---------------------------------------- ---------------------------- +# 2 8.289 2 +# 5 13.99 5 +# 4 17.06 4 +# 3 48.1 3 +# 1 555.3 1 +# +# To verify the data type of c3, type 'show table numManip2' into bteq: +# CREATE SET TABLE ECOLE.numManip2 ,NO FALLBACK , +# NO BEFORE JOURNAL, +# NO AFTER JOURNAL, +# CHECKSUM = DEFAULT, +# DEFAULT MERGEBLOCKRATIO +# ( +# c1 CHAR(5) CHARACTER SET LATIN NOT CASESPECIFIC, +# c2 NUMBER, +# c3 NUMBER) +# PRIMARY INDEX ( c1 ); +# +# To verify each entry of c3: +res1 = tdQuery("select c3 from numManip2 where c1='2'") == 2 +stopifnot(res1) + +res2 = tdQuery("select c3 from numManip2 where c1='5'") == 5 +stopifnot(res2) + +res3 = tdQuery("select c3 from numManip2 where c1='4'") == 4 +stopifnot(res3) + +res4 = tdQuery("select c3 from numManip2 where c1='3'") == 3 +stopifnot(res4) + +res5 = tdQuery("select c3 from numManip2 where c3='1'") == 1 +stopifnot(res5) \ No newline at end of file diff --git a/test/testTRUNC.R b/test/testTRUNC.R new file mode 100644 index 0000000..52a5d13 --- /dev/null +++ b/test/testTRUNC.R @@ -0,0 +1,37 @@ +# Below is the table used for the test, called "numManip" +# c1 c2 +# ----- ---------------------------------------- +# 2 8.289 +# 5 13.99 +# 4 17.06 +# 3 48.1 +# 1 555.3 +# +# the R code is below: +tdf <- td.data.frame("numManip") +tdf["c3"] <- TRUNC(tdf["c2"], 1) +as.td.data.frame(tdf, tableName="numManip2") +# Below are the results of the table, when you type "select * from numManip2" +# c1 c2 c3 +# ----- ---------------------------------------- ------------------------- +# 2 8.289 8.2 +# 5 13.99 13.9 +# 4 17.06 17 +# 3 48.1 48.1 +# 1 555.3 555.3 +# +# To verify each entry of c3: +res1 = tdQuery("select c3 from numManip2 where c1='2'") == 8.2 +stopifnot(res1) + +res2 = tdQuery("select c3 from numManip2 where c1='5'") == 13.9 +stopifnot(res2) + +res3 = tdQuery("select c3 from numManip2 where c1='4'") == 17 +stopifnot(res3) + +res4 = tdQuery("select c3 from numManip2 where c1='3'") == 48.1 +stopifnot(res4) + +res5 = tdQuery("select c3 from numManip2 where c1='1'") == 555.3 +stopifnot(res5) \ No newline at end of file From cec97911ff185dcc4682b8c3ca59369b9fb952f3 Mon Sep 17 00:00:00 2001 From: erindcole Date: Wed, 14 Sep 2016 14:41:36 -0700 Subject: [PATCH 22/28] added new tables for new tests --- test/setup.R | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/setup.R b/test/setup.R index d11ee87..6b46e03 100644 --- a/test/setup.R +++ b/test/setup.R @@ -87,4 +87,20 @@ # insert into padTab (c1, c2, c3) values ('Daisy ', ' Daisy', 'Daisy'); # insert into padTab (c1, c2, c3) values ('Hank ', ' Hank', 'Hank'); # insert into padTab (c1, c2, c3) values ('Amy ', ' Amy', 'Amy'); -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Table Name: numManip +# This table is used for testing functions that manupulate numbers. It works +# with tests for TO_NUMBER() and TRUNC(). +# +# +# drop table numManip; +# drop table numManip2; +# create table numManip ( +# c1 character(5), +# c2 number); +# +# insert into numManip (c1, c2) values ('1', 555.3); +# insert into numManip (c1, c2) values ('2', 8.289); +# insert into numManip (c1, c2) values ('3', 48.1); +# insert into numManip (c1, c2) values ('4', 17.06); +# insert into numManip (c1, c2) values ('5', 13.99); \ No newline at end of file From 124a494b344d0807b5639c0334db256c71051353 Mon Sep 17 00:00:00 2001 From: erindcole Date: Fri, 16 Sep 2016 09:19:18 -0700 Subject: [PATCH 23/28] finished writing needed code for setting up tables --- test/setup.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/setup.R b/test/setup.R index 6b46e03..a29e594 100644 --- a/test/setup.R +++ b/test/setup.R @@ -5,7 +5,7 @@ # Table Name: numTab # This table is used for testing numeric functions. It works with the tests for -# DECODE(), POWER(), and TO_CHAR(). +# AVG(), DECODE(), POWER(), and TO_CHAR(). # # drop table numTab; # drop table numTab2; From 2aa4926274227b42cbcad2fc3c571424e0fd17f7 Mon Sep 17 00:00:00 2001 From: Adam Edgley Date: Wed, 15 Feb 2017 10:38:50 +1100 Subject: [PATCH 24/28] Corrected behaviour with td.sample to return a dataframe --- R/td.sample.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/td.sample.R b/R/td.sample.R index 5ecbb6e..646e5fb 100755 --- a/R/td.sample.R +++ b/R/td.sample.R @@ -15,8 +15,11 @@ td.sample <- function(tdf, sizes = missing, oTable = "", oDatabase = "") { if (.td.objectExists(oObj)) stop(gettextf("Table %s already exists.", oObj)) query <- gettextf("CREATE TABLE %s AS (%s) WITH DATA", oObj, query) + df <- try(tdQueryUpdate(query)) + } else { + df <- try(tdQuery(query)) } - df <- try(tdQueryUpdate(query)) + if (is.data.frame(df)) return(df) if (length(df) == 1L && df == "No Data") From 71547d9a02762fd68c029246bf78181b6a3d9ea6 Mon Sep 17 00:00:00 2001 From: Stuart Horsman Date: Mon, 9 Oct 2017 17:28:31 +1100 Subject: [PATCH 25/28] fix markdown errors --- man/LPAD.Rd | 7 ++++--- man/RPAD.Rd | 4 ++-- man/on.Rd | 20 ++++++++++---------- man/td.CalcMatrix.Rd | 16 ++++++++-------- man/td.ExecR.Rd | 10 +++++----- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/man/LPAD.Rd b/man/LPAD.Rd index b667f1d..0e86e96 100644 --- a/man/LPAD.Rd +++ b/man/LPAD.Rd @@ -4,6 +4,7 @@ \title{ Wrapper Function LPAD } +\description{ Makes a wrapper around the fastpath function LPAD } \usage{ @@ -11,13 +12,13 @@ LPAD(x, ilength, fill_string = " ") } %- maybe also 'usage' for other objects documented here. \arguments{ - \item{x}{ +\item{x}{ a teradata dataframe that contains column(s) of characters that will be padded } - \item{ilength} { +\item{ilength}{ the amount of padding to append to the beginning of the character } - \item{fill_string} { +\item{fill_string}{ the character used to pad the the column(s) of characters that are passed into the function. Default character is the empty character } } diff --git a/man/RPAD.Rd b/man/RPAD.Rd index 9d1e621..a1070c7 100644 --- a/man/RPAD.Rd +++ b/man/RPAD.Rd @@ -15,10 +15,10 @@ RPAD(x, ilength, fill_string = " ") \item{x}{ a teradata dataframe that contains column(s) of characters that will be padded } - \item{ilength} { +\item{ilength}{ the amount of padding to append to the beginning of the character } - \item{fill_string} { +\item{fill_string}{ the character used to pad the the column(s) of characters that are passed into the function. Default character is the empty character } } diff --git a/man/on.Rd b/man/on.Rd index 9169d12..6065246 100644 --- a/man/on.Rd +++ b/man/on.Rd @@ -12,34 +12,34 @@ on(target=NULL, from=NULL, subQuery=NULL, partition=NULL, hash=NULL, order=NULL, } %- maybe also 'usage' for other objects documented here. \arguments{ - \item{target}{ +\item{target}{ a character that represents a name of a table or a query expression } - \item{from} { +\item{from}{ a character that represents a name of the origin of a query expression } - \item{subQuery}{ +\item{subQuery}{ a character that represents a nested ON Clause or nested query expression that is part of an ON Clause } - \item{partition} { +\item{partition}{ the parallel option, partition by , or partition by } - \item{hash} { +\item{hash}{ the parallel option, hash by } - \item{order}{ +\item{order}{ the parallel option, order by } - \item{local_order}{ +\item{local_order}{ the parallel option, local order by } - \item{null_order}{ +\item{null_order}{ specification for the parallel option local_order } - \item{dimension} { +\item{dimension}{ the parallel option, dimension } - \item{as} { +\item{as}{ creates and alias } } diff --git a/man/td.CalcMatrix.Rd b/man/td.CalcMatrix.Rd index c576da5..ba98517 100644 --- a/man/td.CalcMatrix.Rd +++ b/man/td.CalcMatrix.Rd @@ -12,28 +12,28 @@ td.CalcMatrix(selectPhrase=string, ons=string, phase=NULL, calctype=NULL, output } %- maybe also 'usage' for other objects documented here. \arguments{ - \item{selectPhrase}{ +\item{selectPhrase}{ a character that represents the select clause for a query expression } - \item{ons} { +\item{ons}{ a character or list representation of the needed ON Clauses } - \item{phase} { +\item{phase}{ the character representation of the input of the optional PHASE clause } - \item{calctype} { +\item{calctype}{ the character representation of the input of the optional CALCTYPE clause } - \item{output} { +\item{output}{ the character representation of the input of the optional OUTPUT clause } - \item{null_handling} { +\item{null_handling}{ the character representation of the input of the optional specfication for null handling } - \item{optional_operators} { +\item{optional_operators}{ the character representation of the other operators that can be specified } - \item{as} { +\item{as}{ creates and alias } } diff --git a/man/td.ExecR.Rd b/man/td.ExecR.Rd index eeecd93..cdc1e35 100644 --- a/man/td.ExecR.Rd +++ b/man/td.ExecR.Rd @@ -15,19 +15,19 @@ td.ExecR(selectPhrase=string, ons=list(), returns=NULL, contract=NULL, operator= \item{selectPhrase}{ a character that represents a select phrase } - \item{ons} { + \item{ons}{ a list or character representation of on clauses } - \item{returns} { + \item{returns}{ a file or character representation of a returns clause } - \item{contract} { + \item{contract}{ a file or character representation of a contract clause } - \item{operator} { + \item{operator}{ a file or character representation of an operator clause } - \item{optional_operators} { + \item{optional_operators}{ a character representation of any other needed operators } } From 49b34551566e7d1d3fd3f7da167cee1b48da4686 Mon Sep 17 00:00:00 2001 From: Stuart Horsman Date: Mon, 9 Oct 2017 17:32:46 +1100 Subject: [PATCH 26/28] type in NAMESPACE --- NAMESPACE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 7486800..a225638 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,7 +11,7 @@ td.sample, td.shapiro.wilk, td.sigmoid, td.smirnov, td.solve, td.stats, td.t.paired, td.t.unpaired, td.t.unpairedi, td.values, td.wilcoxon, td.zscore, tdClose, tdConnect, tdMetadataDB, tdQuery, tdSave, td.kmeans, predict.kmeans, ASCII, CEIL, CHR, DECODE, EDITDISTANCE, -FLOOR, INSTR, INTCAP, LENGTH, LPAD, LTRIM, NGRAM, OREPLACE,OTRANSLATE, +FLOOR, INSTR, INITCAP, LENGTH, LPAD, LTRIM, NGRAM, OREPLACE,OTRANSLATE, RPAD, RTRIM, Ops.td.data.frame, Ops.td.expression, is.td.expression, GREATEST, LEAST, td.tapply, subset.td.data.frame, tdQueryUpdate) S3method("[", td.data.frame) From fec4c5e0d4e67d7d67b4389dab0a4be4bbf8509d Mon Sep 17 00:00:00 2001 From: Mark Sandan Date: Wed, 18 Oct 2017 14:30:08 -0700 Subject: [PATCH 27/28] Fix some ExecR related things --- NAMESPACE | 98 +++++++++++++++++++++++++++++++++++------- R/td.ExecR.R | 4 +- R/teradataR-internal.R | 52 ++++++++++++++++++++++ man/td.ExecR.Rd | 6 +-- 4 files changed, 138 insertions(+), 22 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index a225638..eb62367 100755 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,18 +1,84 @@ -export(as.data.frame.td.data.frame, as.td.data.frame, -dim.td.data.frame, hist.td.data.frame, is.td.data.frame, -max.td.data.frame, mean.td.data.frame, median.td.data.frame, -min.td.data.frame, print.td.data.frame, sum.td.data.frame, -summary.td.data.frame, td.bincode, td.binomial, td.binomialsign, -td.call.sp, td.cor, td.cov, td.dagostino.pearson, td.data.frame, -td.f.oneway, td.factanal, td.freq, td.hist, td.join, td.ks, -td.lilliefors, td.merge, td.mode, td.mwnkw, td.nullreplace, -td.overlap, td.quantiles, td.rank, td.recode, td.rescale, -td.sample, td.shapiro.wilk, td.sigmoid, td.smirnov, td.solve, -td.stats, td.t.paired, td.t.unpaired, td.t.unpairedi, td.values, -td.wilcoxon, td.zscore, tdClose, tdConnect, tdMetadataDB, tdQuery, -tdSave, td.kmeans, predict.kmeans, ASCII, CEIL, CHR, DECODE, EDITDISTANCE, -FLOOR, INSTR, INITCAP, LENGTH, LPAD, LTRIM, NGRAM, OREPLACE,OTRANSLATE, -RPAD, RTRIM, Ops.td.data.frame, Ops.td.expression, is.td.expression, -GREATEST, LEAST, td.tapply, subset.td.data.frame, tdQueryUpdate) +export( + as.data.frame.td.data.frame, + as.td.data.frame, + dim.td.data.frame, + hist.td.data.frame, + is.td.data.frame, + max.td.data.frame, + mean.td.data.frame, + median.td.data.frame, + min.td.data.frame, + print.td.data.frame, + sum.td.data.frame, + summary.td.data.frame, + td.bincode, + td.binomial, + td.binomialsign, + td.call.sp, + td.cor, + td.cov, + td.dagostino.pearson, + td.data.frame, + td.f.oneway, + td.factanal, + td.freq, + td.hist, + td.join, + td.ks, + td.lilliefors, + td.merge, + td.mode, + td.mwnkw, + td.nullreplace, + td.overlap, + td.quantiles, + td.rank, + td.recode, + td.rescale, + td.sample, + td.shapiro.wilk, + td.sigmoid, + td.smirnov, + td.solve, + td.stats, + td.t.paired, + td.t.unpaired, + td.t.unpairedi, + td.values, + td.wilcoxon, + td.zscore, + tdClose, + tdConnect, + tdMetadataDB, + tdQuery, + tdSave, + td.kmeans, + predict.kmeans, + ASCII, + CEIL, + CHR, + DECODE, + EDITDISTANCE, + FLOOR, + INSTR, + INITCAP, + LENGTH, + LPAD, + LTRIM, + NGRAM, + OREPLACE, + OTRANSLATE, + RPAD, + RTRIM, + Ops.td.data.frame, + Ops.td.expression, + is.td.expression, + GREATEST, + LEAST, + td.tapply, + subset.td.data.frame, + tdQueryUpdate, + td.ExecR, + on) S3method("[", td.data.frame) S3method("[<-", td.data.frame) diff --git a/R/td.ExecR.R b/R/td.ExecR.R index 3671ea7..606ed9e 100755 --- a/R/td.ExecR.R +++ b/R/td.ExecR.R @@ -2,9 +2,7 @@ td.ExecR <- function(selectPhrase=string, ons=list(), returns=NULL, contract=NUL ons<- unlist(ons) ons <- paste(ons, sep="", collapse="\n") using <- .td.usingClause(returns=returns, contract=contract, operator=operator) - queryText <- paste(selectPhrase, "(\n", ons, using, ") ", optional_operators, ") as db;") - print(queryText) + queryText <- paste(selectPhrase, "(\n", ons, "\n", using, optional_operators, "\n) as db;") return(queryText) - } \ No newline at end of file diff --git a/R/teradataR-internal.R b/R/teradataR-internal.R index cdfd08a..8903cf0 100755 --- a/R/teradataR-internal.R +++ b/R/teradataR-internal.R @@ -926,4 +926,56 @@ baseText = "as %s" dependents = paste(...) return(gettextf(baseText, dependents)) +} + +.td.getOperator <- function(operator){ + if (!is.character(operator) || nchar(operator) == 0){ + stop("operator argument must be a character vector") + } + + if (file.exists(operator)){ + return (readChar(operator, file.info(operator)$size)) + } else { + return (operator) + } +} + +.td.getContract <- function(contract){ + if (!is.character(contract) || nchar(contract) == 0){ + stop("contract argument must be a character vector") + } + + if (file.exists(contract)){ + return (readChar(contract, file.info(contract)$size)) + } else { + return (contract) + } +} + +# Currently only supporting Returns/Operator/Contract USING clauses +.td.usingClause <- function(operator, returns=NULL, contract=NULL){ + + if (is.null(returns) && is.null(contract)){ + stop("ExecR must have either returns or contract arguments but not both") + } + + if (nchar(operator) == 0){ + stop("Operator for ExecR must be provided") + } + + if (is.null(contract)){ + + if (!is.atomic(returns) && !is.character(returns)){ + stop("returns argument must be a character vector") + } + + baseText = "RETURNS (%s) USING \n Operator(%s)" + return (res <- gettextf(baseText, paste(returns, collapse = ', '), .td.getOperator(operator))) + + } else{ + + baseText = "USING \n Contract(%s) \n Operator(%s)" + return(gettextf(baseText, .td.getContract(contract), .td.getOperator(operator))) + + } } \ No newline at end of file diff --git a/man/td.ExecR.Rd b/man/td.ExecR.Rd index cdc1e35..06a3138 100644 --- a/man/td.ExecR.Rd +++ b/man/td.ExecR.Rd @@ -5,7 +5,7 @@ ExecR Wrapper Function } \description{ -This function is a wrapper function around the table operator ExecR. It generates a string that can be passed into the function tdQuery to make a query that uses ExecR. +This function is a wrapper function around the table operator ExecR. It generates a string that can be passed into the function tdQuery to make a query that uses ExecR. The Contract and Operator can be given as character vectors or read from files. In the latter case, the path to the file is given for Contract or Operator. The file(s) must include only R code, the contents of the files essentially get copied. Files paths can be specified by using relative paths from getwd() or the absolute path. } \usage{ td.ExecR(selectPhrase=string, ons=list(), returns=NULL, contract=NULL, operator=string, optional_operators=NULL) @@ -19,10 +19,10 @@ a character that represents a select phrase a list or character representation of on clauses } \item{returns}{ -a file or character representation of a returns clause +a character vector of a returns clause (e.g. returns <- c("col1 int", "col2 real")) } \item{contract}{ -a file or character representation of a contract clause +a file or character representation of a contract clause. } \item{operator}{ a file or character representation of an operator clause From 453518bf036d9edeee24779a62d14a0033adc6f6 Mon Sep 17 00:00:00 2001 From: Mark Sandan Date: Wed, 18 Oct 2017 16:34:11 -0700 Subject: [PATCH 28/28] Add quotes around Contract and Operator --- R/teradataR-internal.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/teradataR-internal.R b/R/teradataR-internal.R index 8903cf0..a50770d 100755 --- a/R/teradataR-internal.R +++ b/R/teradataR-internal.R @@ -969,12 +969,12 @@ stop("returns argument must be a character vector") } - baseText = "RETURNS (%s) USING \n Operator(%s)" + baseText = "RETURNS (%s) USING \n Operator('%s')" return (res <- gettextf(baseText, paste(returns, collapse = ', '), .td.getOperator(operator))) } else{ - baseText = "USING \n Contract(%s) \n Operator(%s)" + baseText = "USING \n Contract('\n%s') \n Operator('\n%s')" return(gettextf(baseText, .td.getContract(contract), .td.getOperator(operator))) }