OmniSciDB  2e3a973ef4
QueryExporterCSV.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 OmniSci, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <boost/variant/get.hpp>
20 
22 #include <QueryEngine/ResultSet.h>
23 #include "Shared/misc.h"
24 
25 namespace import_export {
26 
28 
30 
31 void QueryExporterCSV::beginExport(const std::string& file_path,
32  const std::string& layer_name,
33  const CopyParams& copy_params,
34  const std::vector<TargetMetaInfo>& column_infos,
35  const FileCompression file_compression,
36  const ArrayNullHandling array_null_handling) {
37  validateFileExtensions(file_path, "CSV", {".csv", ".tsv"});
38 
39  // compression?
40  auto actual_file_path{file_path};
41  if (file_compression != FileCompression::kNone) {
42  // @TODO(se) implement post-export compression
43  throw std::runtime_error("Compression not yet supported for this file type");
44  }
45 
46  // open file
47  outfile_.open(actual_file_path);
48  if (!outfile_) {
49  throw std::runtime_error("Failed to create file '" + actual_file_path + "'");
50  }
51 
52  // write header?
54  bool not_first{false};
55  int column_index = 0;
56  for (auto const& column_info : column_infos) {
57  // get name or default
58  auto column_name = safeColumnName(column_info.get_resname(), column_index + 1);
59  // output to header line
60  if (not_first) {
61  outfile_ << copy_params.delimiter;
62  } else {
63  not_first = true;
64  }
65  outfile_ << column_name;
66  column_index++;
67  }
68  outfile_ << copy_params.line_delim;
69  }
70 
71  // keep these
72  copy_params_ = copy_params;
73 }
74 
75 void QueryExporterCSV::exportResults(const std::vector<AggregatedResult>& query_results) {
76  for (auto& agg_result : query_results) {
77  auto results = agg_result.rs;
78  auto const& targets = agg_result.targets_meta;
79 
80  while (true) {
81  auto const crt_row = results->getNextRow(true, true);
82  if (crt_row.empty()) {
83  break;
84  }
85  bool not_first = false;
86  for (size_t i = 0; i < results->colCount(); ++i) {
87  bool is_null{false};
88  auto const tv = crt_row[i];
89  auto const scalar_tv = boost::get<ScalarTargetValue>(&tv);
90  if (not_first) {
92  } else {
93  not_first = true;
94  }
95  if (copy_params_.quoted) {
97  }
98  auto const& ti = targets[i].get_type_info();
99  if (!scalar_tv) {
100  outfile_ << datum_to_string(crt_row[i], ti, " | ");
101  if (copy_params_.quoted) {
103  }
104  continue;
105  }
106  if (boost::get<int64_t>(scalar_tv)) {
107  auto int_val = *(boost::get<int64_t>(scalar_tv));
108  switch (ti.get_type()) {
109  case kBOOLEAN:
110  is_null = (int_val == NULL_BOOLEAN);
111  break;
112  case kTINYINT:
113  is_null = (int_val == NULL_TINYINT);
114  break;
115  case kSMALLINT:
116  is_null = (int_val == NULL_SMALLINT);
117  break;
118  case kINT:
119  is_null = (int_val == NULL_INT);
120  break;
121  case kBIGINT:
122  is_null = (int_val == NULL_BIGINT);
123  break;
124  case kTIME:
125  case kTIMESTAMP:
126  case kDATE:
127  is_null = (int_val == NULL_BIGINT);
128  break;
129  default:
130  is_null = false;
131  }
132  if (is_null) {
134  } else if (ti.get_type() == kTIME) {
135  constexpr size_t buf_size = 9;
136  char buf[buf_size];
137  size_t const len = shared::formatHMS(buf, buf_size, int_val);
138  CHECK_EQ(8u, len); // 8 == strlen("HH:MM:SS")
139  outfile_ << buf;
140  } else {
141  outfile_ << int_val;
142  }
143  } else if (boost::get<double>(scalar_tv)) {
144  auto real_val = *(boost::get<double>(scalar_tv));
145  if (ti.get_type() == kFLOAT) {
146  is_null = (real_val == NULL_FLOAT);
147  } else {
148  is_null = (real_val == NULL_DOUBLE);
149  }
150  if (is_null) {
152  } else if (ti.get_type() == kNUMERIC) {
153  outfile_ << std::setprecision(ti.get_precision()) << real_val;
154  } else {
155  outfile_ << std::setprecision(std::numeric_limits<double>::digits10 + 1)
156  << real_val;
157  }
158  } else if (boost::get<float>(scalar_tv)) {
159  CHECK_EQ(kFLOAT, ti.get_type());
160  auto real_val = *(boost::get<float>(scalar_tv));
161  if (real_val == NULL_FLOAT) {
163  } else {
164  outfile_ << std::setprecision(std::numeric_limits<float>::digits10 + 1)
165  << real_val;
166  }
167  } else {
168  auto s = boost::get<NullableString>(scalar_tv);
169  is_null = !s || boost::get<void*>(s);
170  if (is_null) {
172  } else {
173  auto s_notnull = boost::get<std::string>(s);
174  CHECK(s_notnull);
175  if (!copy_params_.quoted) {
176  outfile_ << *s_notnull;
177  } else {
178  size_t q = s_notnull->find(copy_params_.quote);
179  if (q == std::string::npos) {
180  outfile_ << *s_notnull;
181  } else {
182  std::string str(*s_notnull);
183  while (q != std::string::npos) {
184  str.insert(q, 1, copy_params_.escape);
185  q = str.find(copy_params_.quote, q + 2);
186  }
187  outfile_ << str;
188  }
189  }
190  }
191  }
192  if (copy_params_.quoted) {
194  }
195  }
197  }
198  }
199 }
200 
202  // just close the file
203  outfile_.close();
204 }
205 
206 } // namespace import_export
#define CHECK_EQ(x, y)
Definition: Logger.h:205
#define NULL_DOUBLE
Definition: sqltypes.h:186
Definition: sqltypes.h:51
#define NULL_BIGINT
Definition: sqltypes.h:184
std::string datum_to_string(const TargetValue &tv, const SQLTypeInfo &ti, const std::string &delim)
std::string safeColumnName(const std::string &resname, const int column_index)
void exportResults(const std::vector< AggregatedResult > &query_results) final
size_t formatHMS(char *buf, size_t const max, int64_t const unixtime)
Definition: misc.cpp:80
ImportHeaderRow has_header
Definition: CopyParams.h:48
#define NULL_TINYINT
Definition: sqltypes.h:181
#define NULL_FLOAT
Definition: sqltypes.h:185
#define NULL_INT
Definition: sqltypes.h:183
Definition: sqltypes.h:55
bool is_null(const T &v, const SQLTypeInfo &t)
void beginExport(const std::string &file_path, const std::string &layer_name, const CopyParams &copy_params, const std::vector< TargetMetaInfo > &column_infos, const FileCompression file_compression, const ArrayNullHandling array_null_handling) final
#define NULL_SMALLINT
Definition: sqltypes.h:182
#define CHECK(condition)
Definition: Logger.h:197
Basic constructors and methods of the row set interface.
Definition: sqltypes.h:47
#define NULL_BOOLEAN
Definition: sqltypes.h:180
void validateFileExtensions(const std::string &file_path, const std::string &file_type, const std::unordered_set< std::string > &valid_extensions) const