OmniSciDB  95562058bd
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
QueryExporterGDAL.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 <array>
20 #include <string>
21 #include <unordered_set>
22 
23 #include <boost/filesystem.hpp>
24 
25 #include <ogrsf_frmts.h>
26 
27 #include "Geospatial/Types.h"
28 #include "ImportExport/GDAL.h"
30 #include "QueryEngine/ResultSet.h"
31 #include "Shared/misc.h"
32 #include "Shared/scope.h"
33 
34 namespace import_export {
35 
37  : QueryExporter(file_type)
38  , gdal_dataset_{nullptr}
39  , ogr_layer_{nullptr}
40  , array_null_handling_{ArrayNullHandling::kAbortWithWarning} {}
41 
43  cleanUp();
44 }
45 
47  // close dataset
48  if (gdal_dataset_) {
49  GDALClose(gdal_dataset_);
50  gdal_dataset_ = nullptr;
51  }
52 
53  // forget layer
54  ogr_layer_ = nullptr;
55 
56  // forget field indices
57  field_indices_.clear();
58 }
59 
60 #define SCI(x) static_cast<int>(x)
61 
62 namespace {
63 
64 static constexpr std::array<const char*, 4> driver_names = {"INVALID",
65  "GeoJSON",
66  "GeoJSONSeq",
67  "ESRI Shapefile"};
68 
69 static constexpr std::array<const char*, 4> file_type_names = {"CSV",
70  "GeoJSON",
71  "GeoJSONL",
72  "Shapefile"};
73 
74 static constexpr std::array<const char*, 3> compression_prefix = {"",
75  "/vsigzip/",
76  "/vsizip/"};
77 
78 static constexpr std::array<const char*, 3> compression_suffix = {"", ".gz", ".zip"};
79 
80 // this table is by file type then by compression type
81 // @TODO(se) implement more compression options
82 static constexpr std::array<std::array<bool, 3>, 4> compression_implemented = {
83  {{true, false, false}, // CSV: none
84  {true, true, false}, // GeoJSON: on-the-fly GZip only
85  {true, true, false}, // GeoJSONL: on-the-fly GZip only
86  {true, false, false}}}; // Shapefile: none
87 
88 static std::array<std::unordered_set<std::string>, 4> file_type_valid_extensions = {
89  {{".csv", ".tsv"}, {".geojson", ".json"}, {".geojson", ".json"}, {".shp"}}};
90 
91 OGRFieldType sql_type_info_to_ogr_field_type(const std::string& name,
92  const SQLTypeInfo& type_info,
93  const QueryExporter::FileType file_type) {
94  // store BOOLEAN as int
95  // store TIME as string (no OFTTimeList and Shapefiles reject OFTTime anyway)
96  // store all other time/date types as int64
97  // Shapefiles cannot store arrays of any type
98  switch (type_info.get_type()) {
99  case kBOOLEAN:
100  case kTINYINT:
101  case kINT:
102  case kSMALLINT:
103  return OFTInteger;
104  case kFLOAT:
105  case kDOUBLE:
106  case kNUMERIC:
107  case kDECIMAL:
108  return OFTReal;
109  case kCHAR:
110  case kVARCHAR:
111  case kTEXT:
112  case kTIME:
113  return OFTString;
114  case kBIGINT:
115  case kTIMESTAMP:
116  case kDATE:
117  case kINTERVAL_DAY_TIME:
119  return OFTInteger64;
120  case kARRAY:
121  if (file_type != QueryExporter::FileType::kShapefile) {
122  switch (type_info.get_subtype()) {
123  case kBOOLEAN:
124  case kTINYINT:
125  case kINT:
126  case kSMALLINT:
127  return OFTIntegerList;
128  case kFLOAT:
129  case kDOUBLE:
130  case kNUMERIC:
131  case kDECIMAL:
132  return OFTRealList;
133  case kCHAR:
134  case kVARCHAR:
135  case kTEXT:
136  case kTIME:
137  return OFTStringList;
138  case kBIGINT:
139  case kTIMESTAMP:
140  case kDATE:
141  case kINTERVAL_DAY_TIME:
143  return OFTInteger64List;
144  default:
145  break;
146  }
147  }
148  break;
149  default:
150  break;
151  }
152  throw std::runtime_error("Column '" + name + "' has unsupported type '" +
153  type_info.get_type_name() + "' for file type '" +
154  file_type_names[SCI(file_type)] + "'");
155 }
156 
157 } // namespace
158 
159 void QueryExporterGDAL::beginExport(const std::string& file_path,
160  const std::string& layer_name,
161  const CopyParams& copy_params,
162  const std::vector<TargetMetaInfo>& column_infos,
163  const FileCompression file_compression,
164  const ArrayNullHandling array_null_handling) {
165  validateFileExtensions(file_path,
168 
169  // lazy init GDAL
170  GDAL::init();
171 
172  // capture these
173  copy_params_ = copy_params;
174  array_null_handling_ = array_null_handling;
175 
176  try {
177  // determine OGR geometry type and SRID and validate other column types
178  OGRwkbGeometryType ogr_geometry_type = wkbUnknown;
179  int num_geo_columns = 0;
180  int geo_column_srid = 0;
181  uint32_t num_columns = 0;
182  std::string geo_column_name;
183  for (auto const& column_info : column_infos) {
184  auto const& type_info = column_info.get_type_info();
185  if (type_info.is_geometry()) {
186  switch (type_info.get_type()) {
187  case kPOINT:
188  ogr_geometry_type = wkbPoint;
189  break;
190  case kLINESTRING:
191  ogr_geometry_type = wkbLineString;
192  break;
193  case kPOLYGON:
194  ogr_geometry_type = wkbPolygon;
195  break;
196  case kMULTIPOLYGON:
197  ogr_geometry_type = wkbMultiPolygon;
198  break;
199  default:
200  CHECK(false);
201  }
202  geo_column_srid = type_info.get_output_srid();
203  geo_column_name = safeColumnName(column_info.get_resname(), num_columns + 1);
204  num_geo_columns++;
205  } else {
206  auto column_name = safeColumnName(column_info.get_resname(), num_columns + 1);
207  // this will throw if column type is unsupported for this file type
208  sql_type_info_to_ogr_field_type(column_name, type_info, file_type_);
209  }
210  num_columns++;
211  }
212  if (num_geo_columns != 1) {
213  throw std::runtime_error("File type '" +
214  std::string(file_type_names[SCI(file_type_)]) +
215  "' requires exactly one geo column in query results");
216  }
217 
218  // validate SRID
219  if (geo_column_srid <= 0) {
220  throw std::runtime_error("Geo column '" + geo_column_name + "' has invalid SRID (" +
221  std::to_string(geo_column_srid) +
222  "). Use ST_SetSRID() in query to override.");
223  }
224 
225  // get driver
226  auto const& driver_name = driver_names[SCI(file_type_)];
227  auto gdal_driver = GetGDALDriverManager()->GetDriverByName(driver_name);
228  if (gdal_driver == nullptr) {
229  throw std::runtime_error("Failed to find Driver '" + std::string(driver_name) +
230  "'");
231  }
232 
233  // compression?
234  auto gdal_file_path{file_path};
235  auto user_file_path{file_path};
236  if (file_compression != FileCompression::kNone) {
237  auto impl = compression_implemented[SCI(file_type_)][SCI(file_compression)];
238  if (!impl) {
239  // @TODO(se) implement more compression options
240  throw std::runtime_error(
241  "Selected file compression option not yet supported for file type '" +
242  std::string(file_type_names[SCI(file_type_)]) + "'");
243  }
244  gdal_file_path.insert(0, compression_prefix[SCI(file_compression)]);
245  gdal_file_path.append(compression_suffix[SCI(file_compression)]);
246  user_file_path.append(compression_suffix[SCI(file_compression)]);
247  }
248 
249  // delete any existing file(s) (with and without compression suffix)
250  // GeoJSON driver occasionally refuses to overwrite
251  auto remove_file = [](const std::string& filename) {
252  if (boost::filesystem::exists(filename)) {
253  LOG(INFO) << "Deleting existing file '" << filename << "'";
254  boost::filesystem::remove(filename);
255  }
256  };
257  remove_file(file_path);
258  remove_file(user_file_path);
259 
260  LOG(INFO) << "Exporting to file '" << user_file_path << "'";
261 
262  // create dataset
263  gdal_dataset_ =
264  gdal_driver->Create(gdal_file_path.c_str(), 0, 0, 0, GDT_Unknown, NULL);
265  if (gdal_dataset_ == nullptr) {
266  throw std::runtime_error("Failed to create File '" + file_path + "'");
267  }
268 
269  // create spatial reference
270  OGRSpatialReference ogr_spatial_reference;
271  if (ogr_spatial_reference.importFromEPSG(geo_column_srid)) {
272  throw std::runtime_error("Failed to create Spatial Reference for SRID " +
273  std::to_string(geo_column_srid) + "");
274  }
275 #if GDAL_VERSION_MAJOR >= 3
276  ogr_spatial_reference.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
277 #endif
278 
279  // create layer
280  ogr_layer_ = gdal_dataset_->CreateLayer(
281  layer_name.c_str(), &ogr_spatial_reference, ogr_geometry_type, NULL);
282  if (ogr_layer_ == nullptr) {
283  throw std::runtime_error("Failed to create Layer '" + layer_name + "'");
284  }
285 
286  // create fields
287  int column_index = 0;
288  int field_index = 0;
289  field_indices_.resize(num_columns);
290  for (auto const& column_info : column_infos) {
291  auto column_name = safeColumnName(column_info.get_resname(), column_index + 1);
292  // create fields for non-geo columns
293  auto const& type_info = column_info.get_type_info();
294  if (!type_info.is_geometry()) {
295  OGRFieldDefn field_defn(
296  column_name.c_str(),
297  sql_type_info_to_ogr_field_type(column_name, type_info, file_type_));
298  if (ogr_layer_->CreateField(&field_defn) != OGRERR_NONE) {
299  throw std::runtime_error("Failed to create Field '" + column_name + "'");
300  }
301  field_indices_[column_index] = field_index;
302  field_index++;
303  } else {
304  field_indices_[column_index] = -1;
305  }
306  column_index++;
307  }
308  } catch (std::exception& e) {
309  LOG(INFO) << "GDAL Query Export failed to start: " << e.what();
310  cleanUp();
311  throw;
312  }
313 }
314 
315 namespace {
316 
318  const SQLTypeInfo& ti,
319  const int field_index,
320  OGRFeature* ogr_feature) {
321  CHECK_EQ(field_index, -1);
322  CHECK(ti.is_geometry());
323 
324  // use Geo classes to convert to OGRGeometry
325  // and destroy when Geo object goes out of scope
326  switch (ti.get_type()) {
327  case kPOINT: {
328  auto const point_tv = boost::get<GeoPointTargetValue>(geo_tv->get());
329  auto* coords = point_tv.coords.get();
330  CHECK(coords);
331  Geospatial::GeoPoint point(*coords);
332  ogr_feature->SetGeometry(point.getOGRGeometry());
333  } break;
334  case kLINESTRING: {
335  auto const linestring_tv = boost::get<GeoLineStringTargetValue>(geo_tv->get());
336  auto* coords = linestring_tv.coords.get();
337  CHECK(coords);
338  Geospatial::GeoLineString linestring(*coords);
339  ogr_feature->SetGeometry(linestring.getOGRGeometry());
340  } break;
341  case kPOLYGON: {
342  auto const polygon_tv = boost::get<GeoPolyTargetValue>(geo_tv->get());
343  auto* coords = polygon_tv.coords.get();
344  CHECK(coords);
345  auto* ring_sizes = polygon_tv.ring_sizes.get();
346  CHECK(ring_sizes);
347  Geospatial::GeoPolygon polygon(*coords, *ring_sizes);
348  ogr_feature->SetGeometry(polygon.getOGRGeometry());
349  } break;
350  case kMULTIPOLYGON: {
351  auto const multipolygon_tv = boost::get<GeoMultiPolyTargetValue>(geo_tv->get());
352  auto* coords = multipolygon_tv.coords.get();
353  CHECK(coords);
354  auto* ring_sizes = multipolygon_tv.ring_sizes.get();
355  CHECK(ring_sizes);
356  auto* poly_rings = multipolygon_tv.poly_rings.get();
357  CHECK(poly_rings);
358  Geospatial::GeoMultiPolygon multipolygon(*coords, *ring_sizes, *poly_rings);
359  ogr_feature->SetGeometry(multipolygon.getOGRGeometry());
360  } break;
361  default:
362  CHECK(false);
363  }
364 }
365 
367  const SQLTypeInfo& ti,
368  const int field_index,
369  OGRFeature* ogr_feature) {
370  CHECK_GE(field_index, 0);
371  CHECK(!ti.is_geometry());
372 
373  auto field_type = ogr_feature->GetFieldDefnRef(field_index)->GetType();
374 
375  bool is_null{false};
376  if (boost::get<int64_t>(scalar_tv)) {
377  auto int_val = *(boost::get<int64_t>(scalar_tv));
378  bool is_int64 = false;
379  switch (ti.get_type()) {
380  case kBOOLEAN:
381  is_null = (int_val == NULL_BOOLEAN);
382  break;
383  case kTINYINT:
384  is_null = (int_val == NULL_TINYINT);
385  break;
386  case kSMALLINT:
387  is_null = (int_val == NULL_SMALLINT);
388  break;
389  case kINT:
390  is_null = (int_val == NULL_INT);
391  break;
392  case kBIGINT:
393  is_null = (int_val == NULL_BIGINT);
394  is_int64 = true;
395  break;
396  case kTIME:
397  case kTIMESTAMP:
398  case kDATE:
399  is_null = (int_val == NULL_BIGINT);
400  is_int64 = true;
401  break;
402  default:
403  is_null = false;
404  }
405  if (is_null) {
406  ogr_feature->SetFieldNull(field_index);
407  } else if (ti.get_type() == kTIME) {
408  CHECK_EQ(field_type, OFTString);
409  constexpr size_t buf_size = 9;
410  char buf[buf_size];
411  size_t const len = shared::formatHMS(buf, buf_size, int_val);
412  CHECK_EQ(8u, len); // 8 == strlen("HH:MM:SS")
413  ogr_feature->SetField(field_index, buf);
414  } else if (is_int64) {
415  CHECK_EQ(field_type, OFTInteger64);
416  ogr_feature->SetField(field_index, static_cast<GIntBig>(int_val));
417  } else {
418  CHECK_EQ(field_type, OFTInteger);
419  ogr_feature->SetField(field_index, SCI(int_val));
420  }
421  } else if (boost::get<double>(scalar_tv)) {
422  auto real_val = *(boost::get<double>(scalar_tv));
423  if (ti.get_type() == kFLOAT) {
424  is_null = (real_val == NULL_FLOAT);
425  } else {
426  is_null = (real_val == NULL_DOUBLE);
427  }
428  if (is_null) {
429  ogr_feature->SetFieldNull(field_index);
430  } else {
431  CHECK_EQ(field_type, OFTReal);
432  ogr_feature->SetField(field_index, real_val);
433  }
434  } else if (boost::get<float>(scalar_tv)) {
435  CHECK_EQ(kFLOAT, ti.get_type());
436  auto real_val = *(boost::get<float>(scalar_tv));
437  if (real_val == NULL_FLOAT) {
438  ogr_feature->SetFieldNull(field_index);
439  } else {
440  CHECK_EQ(field_type, OFTReal);
441  ogr_feature->SetField(field_index, real_val);
442  }
443  } else {
444  auto s = boost::get<NullableString>(scalar_tv);
445  is_null = !s || boost::get<void*>(s);
446  if (is_null) {
447  ogr_feature->SetFieldNull(field_index);
448  } else {
449  CHECK_EQ(field_type, OFTString);
450  auto s_notnull = boost::get<std::string>(s);
451  CHECK(s_notnull);
452  ogr_feature->SetField(field_index, s_notnull->c_str());
453  }
454  }
455 }
456 
458  const SQLTypeInfo& ti,
459  const int field_index,
460  OGRFeature* ogr_feature,
461  const std::string& column_name,
462  QueryExporter::ArrayNullHandling array_null_handling) {
463  CHECK_GE(field_index, 0);
464  CHECK(!ti.is_geometry());
465 
466  if (!array_tv->is_initialized()) {
467  // entire array is null
468  ogr_feature->SetFieldNull(field_index);
469  return;
470  }
471 
472  auto const& scalar_tvs = array_tv->get();
473 
474  auto field_type = ogr_feature->GetFieldDefnRef(field_index)->GetType();
475 
476  // only one of these will get used
477  // could use a std::vector<ScalarTargetValue> but need raw data at the end
478  // so we would have to extract it there anyway, so not sure it's worthwhile
479  // we can, at least, pre-reserve whichever array we're going to use
480  std::vector<int> int_values;
481  std::vector<GIntBig> int64_values;
482  std::vector<std::string> string_values;
483  std::vector<double> real_values;
484  switch (field_type) {
485  case OFTIntegerList:
486  int_values.reserve(scalar_tvs.size());
487  break;
488  case OFTInteger64List:
489  int64_values.reserve(scalar_tvs.size());
490  break;
491  case OFTRealList:
492  real_values.reserve(scalar_tvs.size());
493  break;
494  case OFTStringList:
495  string_values.reserve(scalar_tvs.size());
496  break;
497  default:
498  CHECK(false);
499  }
500 
501  bool force_null_to_zero =
502  (array_null_handling == QueryExporter::ArrayNullHandling::kExportZeros);
503 
504  // now extract the data
505  bool any_null = false;
506  for (uint32_t i = 0; i < scalar_tvs.size(); i++) {
507  bool is_null = false;
508  auto const scalar_tv = &scalar_tvs[i];
509  if (boost::get<int64_t>(scalar_tv)) {
510  auto int_val = *(boost::get<int64_t>(scalar_tv));
511  bool is_int64 = false;
512  switch (ti.get_subtype()) {
513  case kBOOLEAN:
514  is_null = (int_val == NULL_BOOLEAN);
515  break;
516  case kTINYINT:
517  is_null = (int_val == NULL_TINYINT);
518  break;
519  case kSMALLINT:
520  is_null = (int_val == NULL_SMALLINT);
521  break;
522  case kINT:
523  is_null = (int_val == NULL_INT);
524  break;
525  case kBIGINT:
526  is_null = (int_val == NULL_BIGINT);
527  is_int64 = true;
528  break;
529  case kTIME:
530  case kTIMESTAMP:
531  case kDATE:
532  is_null = (int_val == NULL_BIGINT);
533  is_int64 = true;
534  break;
535  default:
536  is_null = false;
537  }
538  if (ti.get_subtype() == kTIME) {
539  if (is_null) {
540  string_values.emplace_back("");
541  } else {
542  constexpr size_t buf_size = 9;
543  char buf[buf_size];
544  size_t const len = shared::formatHMS(buf, buf_size, int_val);
545  CHECK_EQ(8u, len); // 8 == strlen("HH:MM:SS")
546  string_values.emplace_back(buf);
547  }
548  } else if (is_int64) {
549  if (is_null && force_null_to_zero) {
550  int64_values.push_back(0);
551  } else {
552  int64_values.push_back(int_val);
553  }
554  } else {
555  if (is_null && force_null_to_zero) {
556  int_values.push_back(0);
557  } else {
558  int_values.push_back(int_val);
559  }
560  }
561  } else if (boost::get<double>(scalar_tv)) {
562  auto real_val = *(boost::get<double>(scalar_tv));
563  if (ti.get_subtype() == kFLOAT) {
564  is_null = (real_val == NULL_FLOAT);
565  } else {
566  is_null = (real_val == NULL_DOUBLE);
567  }
568  if (is_null && force_null_to_zero) {
569  real_values.push_back(0.0);
570  } else {
571  real_values.push_back(real_val);
572  }
573  } else if (boost::get<float>(scalar_tv)) {
574  CHECK_EQ(kFLOAT, ti.get_subtype());
575  auto real_val = *(boost::get<float>(scalar_tv));
576  is_null = (real_val == NULL_FLOAT);
577  if (is_null && force_null_to_zero) {
578  real_values.push_back(0.0);
579  } else {
580  real_values.push_back(static_cast<double>(real_val));
581  }
582  } else {
583  auto s = boost::get<NullableString>(scalar_tv);
584  is_null = !s || boost::get<void*>(s);
585  if (is_null) {
586  string_values.emplace_back("");
587  } else {
588  auto s_notnull = boost::get<std::string>(s);
589  CHECK(s_notnull);
590  string_values.emplace_back(s_notnull->c_str());
591  }
592  }
593  any_null |= is_null;
594  }
595 
596  // special behaviour if we found any individual nulls?
597  if (any_null) {
598  switch (array_null_handling) {
600  throw std::runtime_error(
601  "Found individual nulls in Array Column '" + column_name + "' of type '" +
602  ti.get_type_name() +
603  "'. Use 'array_null_handling' Export Option to specify behaviour.");
605  ogr_feature->SetFieldNull(field_index);
606  return;
607  default:
608  break;
609  }
610  }
611 
612  // store the captured array in the feature
613  switch (field_type) {
614  case OFTIntegerList:
615  ogr_feature->SetField(field_index, int_values.size(), int_values.data());
616  break;
617  case OFTInteger64List:
618  ogr_feature->SetField(field_index, int64_values.size(), int64_values.data());
619  break;
620  case OFTRealList:
621  ogr_feature->SetField(field_index, real_values.size(), real_values.data());
622  break;
623  case OFTStringList: {
624  std::vector<const char*> raw_strings;
625  raw_strings.reserve(string_values.size() + 1);
626  for (auto const& string_value : string_values) {
627  raw_strings.push_back(string_value.c_str());
628  }
629  raw_strings.push_back(nullptr);
630  ogr_feature->SetField(field_index, raw_strings.data());
631  } break;
632  default:
633  CHECK(false);
634  }
635 }
636 
637 } // namespace
638 
640  const std::vector<AggregatedResult>& query_results) {
641  try {
642  for (auto const& agg_result : query_results) {
643  auto results = agg_result.rs;
644  auto const& targets = agg_result.targets_meta;
645 
646  // configure ResultSet to return geo as raw data
647  results->setGeoReturnType(ResultSet::GeoReturnType::GeoTargetValue);
648 
649  while (true) {
650  auto const crt_row = results->getNextRow(true, true);
651  if (crt_row.empty()) {
652  break;
653  }
654 
655  // create feature for this row
656  auto ogr_feature = OGRFeature::CreateFeature(ogr_layer_->GetLayerDefn());
657  CHECK(ogr_feature);
658 
659  // destroy feature on exiting this scope
660  ScopeGuard destroy_feature = [ogr_feature] {
661  OGRFeature::DestroyFeature(ogr_feature);
662  };
663 
664  for (size_t i = 0; i < results->colCount(); ++i) {
665  auto const tv = crt_row[i];
666  auto const& ti = targets[i].get_type_info();
667  auto const column_name = safeColumnName(targets[i].get_resname(), i + 1);
668  auto const field_index = field_indices_[i];
669 
670  // insert this column into the feature
671  auto const scalar_tv = boost::get<ScalarTargetValue>(&tv);
672  if (scalar_tv) {
673  insert_scalar_column(scalar_tv, ti, field_index, ogr_feature);
674  } else {
675  auto const array_tv = boost::get<ArrayTargetValue>(&tv);
676  if (array_tv) {
677  insert_array_column(array_tv,
678  ti,
679  field_index,
680  ogr_feature,
681  column_name,
683  } else {
684  auto const geo_tv = boost::get<GeoTargetValue>(&tv);
685  if (geo_tv && geo_tv->is_initialized()) {
686  insert_geo_column(geo_tv, ti, field_index, ogr_feature);
687  } else {
688  ogr_feature->SetGeometry(nullptr);
689  }
690  }
691  }
692  }
693 
694  // add feature to layer
695  if (ogr_layer_->CreateFeature(ogr_feature) != OGRERR_NONE) {
696  throw std::runtime_error("Failed to create Feature");
697  }
698  }
699  }
700  } catch (std::exception& e) {
701  LOG(INFO) << "GDAL Query Export failed: " << e.what();
702  cleanUp();
703  throw;
704  }
705 }
706 
708  cleanUp();
709 }
710 
711 } // namespace import_export
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:260
#define CHECK_EQ(x, y)
Definition: Logger.h:205
std::string filename(char const *path)
Definition: Logger.cpp:62
#define NULL_DOUBLE
Definition: sqltypes.h:186
Definition: sqltypes.h:51
const OGRGeometry * getOGRGeometry() const
Definition: Types.h:69
static constexpr std::array< std::array< bool, 3 >, 4 > compression_implemented
#define NULL_BIGINT
Definition: sqltypes.h:184
#define LOG(tag)
Definition: Logger.h:188
void insert_array_column(const ArrayTargetValue *array_tv, const SQLTypeInfo &ti, const int field_index, OGRFeature *ogr_feature, const std::string &column_name, QueryExporter::ArrayNullHandling array_null_handling)
std::string safeColumnName(const std::string &resname, const int column_index)
#define CHECK_GE(x, y)
Definition: Logger.h:210
static void init()
Definition: GDAL.cpp:56
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
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:259
#define SCI(x)
std::string to_string(char const *&&v)
size_t formatHMS(char *buf, size_t const max, int64_t const unixtime)
Definition: misc.cpp:80
static constexpr std::array< const char *, 3 > compression_prefix
OGRFieldType sql_type_info_to_ogr_field_type(const std::string &name, const SQLTypeInfo &type_info, const QueryExporter::FileType file_type)
#define NULL_TINYINT
Definition: sqltypes.h:181
boost::optional< std::vector< ScalarTargetValue >> ArrayTargetValue
Definition: TargetValue.h:157
#define NULL_FLOAT
Definition: sqltypes.h:185
void insert_geo_column(const GeoTargetValue *geo_tv, const SQLTypeInfo &ti, const int field_index, OGRFeature *ogr_feature)
static constexpr std::array< const char *, 4 > driver_names
#define NULL_INT
Definition: sqltypes.h:183
void exportResults(const std::vector< AggregatedResult > &query_results) final
Definition: sqltypes.h:54
Definition: sqltypes.h:55
bool is_null(const T &v, const SQLTypeInfo &t)
boost::optional< boost::variant< GeoPointTargetValue, GeoLineStringTargetValue, GeoPolyTargetValue, GeoMultiPolyTargetValue >> GeoTargetValue
Definition: TargetValue.h:161
static constexpr std::array< const char *, 3 > compression_suffix
void insert_scalar_column(const ScalarTargetValue *scalar_tv, const SQLTypeInfo &ti, const int field_index, OGRFeature *ogr_feature)
std::string get_type_name() const
Definition: sqltypes.h:362
Definition: sqltypes.h:43
static constexpr std::array< const char *, 4 > file_type_names
#define NULL_SMALLINT
Definition: sqltypes.h:182
#define CHECK(condition)
Definition: Logger.h:197
bool is_geometry() const
Definition: sqltypes.h:429
Basic constructors and methods of the row set interface.
Definition: sqltypes.h:47
string name
Definition: setup.py:35
static std::array< std::unordered_set< std::string >, 4 > file_type_valid_extensions
void validateFileExtensions(const std::string &file_path, const std::string &file_type, const std::unordered_set< std::string > &valid_extensions) const
#define NULL_BOOLEAN
Definition: sqltypes.h:180
boost::variant< int64_t, double, float, NullableString > ScalarTargetValue
Definition: TargetValue.h:156