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