diff --git a/R/ClickhouseResult.R b/R/ClickhouseResult.R index 9fadef2..f6c2bc6 100644 --- a/R/ClickhouseResult.R +++ b/R/ClickhouseResult.R @@ -27,6 +27,7 @@ setMethod("dbFetch", signature = "ClickhouseResult", definition = function(res, } ret <- fetch(res@ptr, n) ret <- convert_Int64(ret, res@Int64) + ret <- convert_Decimal(ret) if(res@toUTF8 == TRUE) ret <- encode_UTF(ret) @@ -50,6 +51,28 @@ convert_Int64 <- function(df, Int64) { } } +convert_Decimal <- function(df) { +# identify the columns by index that need changing + toConvert <- which(grepl("Decimal", attr(df, 'data.type'))) + +# get the scales + parse_scale <- function(str){ + x <- strsplit(str, ",")[[1]][[2]] + x <- substr(x,1,nchar(x)-1) + x <- as.numeric(x) + return(as.numeric(x)) + } + + for(column_i in toConvert) { + raw_type <- attr(df, 'data.type')[[column_i]] + scale <- parse_scale(raw_type) + # forces String to decimal representation + df[column_i] <- lapply(df[column_i], as.numeric) + df[column_i] <- df[column_i] / (10^scale) + } + return(df) +} + encode_UTF <- function(df){ toConvert <- which(attr(df, "data.type") %in% c("String", "FixedString", "Nullable(String)", "Nullable(FixedString)")) diff --git a/src/connection.cpp b/src/connection.cpp index 33fb408..0d0bdbb 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -10,6 +10,8 @@ using namespace Rcpp; using namespace clickhouse; +ColumnRef convertDecimalColumn(SEXP v); + // [[Rcpp::export]] DataFrame fetch(XPtr res, ssize_t n) { return res->fetchFrame(n); @@ -165,10 +167,10 @@ std::shared_ptr vecToScalar(SEXP v, std::shared_ptr nullCol = n type_of_cor = Rf_inherits(v, "integer64") ? 99 : type_of; switch(type_of_cor) { - case 99: { - toColumnN(v, col, nullCol); - break; - } + case 99: { + toColumnN(v, col, nullCol); + break; + } case INTSXP: { // the lambda could be a default argument of toColumn, but that // appears to trigger a bug in GCC @@ -337,7 +339,12 @@ std::shared_ptr vecToEnum(SEXP v, TypeRef type, std::shared_ptr ColumnRef vecToColumn(TypeRef t, SEXP v, std::shared_ptr nullCol = nullptr) { using TC = Type::Code; + + printf("%i insert THIS !!!\n",t->GetCode()); + switch(t->GetCode()) { + case TC::Decimal: + return convertDecimalColumn(v); case TC::Int8: return vecToScalar(v, nullCol); case TC::Int16: @@ -427,10 +434,27 @@ void insert(XPtr conn, String tableName, DataFrame df) { ColumnRef ccol = vecToColumn(colTypes[i], df[i]); block.AppendColumn(std::string(names[i]), ccol); } - conn->Insert(tableName, block); } +ColumnRef convertDecimalColumn(SEXP v) { +// R_CH-column: Rcpp IntegerVector + IntegerVector cv = Rcpp::as(v); + + + // CH_CPP-column: sharedPtr to ColumnDecimal with (18,1) + std::shared_ptr col = std::make_shared(18, 1); + + + for(typename IntegerVector::stored_type e : cv) { + col->Append(e); + } + + return col; +} + + + // [[Rcpp::export]] bool validPtr(SEXP ptr) { return R_ExternalPtrAddr(ptr); diff --git a/src/result.cpp b/src/result.cpp index e5df40f..22d3247 100644 --- a/src/result.cpp +++ b/src/result.cpp @@ -61,6 +61,19 @@ void convertEntries(std::shared_ptr in, NullCol nullCol, RT &out, } } +template<> +void convertEntries(std::shared_ptr in, NullCol nullCol, Rcpp::StringVector &out, + size_t offset, size_t start, size_t end) { + for(size_t j = start; j < end; j++) { + // can't use the ternary operator here, since that would require explicit + // conversion from the Clickhouse storage type (which is far messier) + if(nullCol && nullCol->IsNull(j)) { + out[offset+j-start] = Rcpp::StringVector::get_na(); + } else { + out[offset+j-start] = (in->At(j).to_string()); + } + } +} template<> void convertEntries(std::shared_ptr in, NullCol nullCol, Rcpp::StringVector &out, @@ -278,6 +291,9 @@ std::unique_ptr Result::buildConverter(std::string name, ch::TypeRef case TC::UInt64: { return std::unique_ptr>(new ScalarConverter); } + case TC::Decimal: { + return std::unique_ptr>(new ScalarConverter); + } case TC::UUID: return std::unique_ptr>(new ScalarConverter); case TC::Float32: