OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
import_export::QueryExporterGDAL Class Reference

#include <QueryExporterGDAL.h>

+ Inheritance diagram for import_export::QueryExporterGDAL:
+ Collaboration diagram for import_export::QueryExporterGDAL:

Public Member Functions

 QueryExporterGDAL (const FileType file_type)
 
 QueryExporterGDAL ()=delete
 
 ~QueryExporterGDAL () override
 
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
 
void exportResults (const std::vector< AggregatedResult > &query_results) final
 
void endExport () final
 
- Public Member Functions inherited from import_export::QueryExporter
 QueryExporter (const FileType file_type)
 
 QueryExporter ()=delete
 
virtual ~QueryExporter ()
 
virtual void beginExport (const std::string &file_path, const std::string &layer_name, const CopyParams &copy_params, const std::vector< TargetMetaInfo > &column_info, const FileCompression file_compression, const ArrayNullHandling array_null_handling)=0
 

Private Member Functions

void cleanUp ()
 

Private Attributes

CopyParams copy_params_
 
GDALDataset * gdal_dataset_
 
OGRLayer * ogr_layer_
 
std::vector< int > field_indices_
 
ArrayNullHandling array_null_handling_
 

Additional Inherited Members

- Public Types inherited from import_export::QueryExporter
enum  FileType {
  FileType::kCSV, FileType::kGeoJSON, FileType::kGeoJSONL, FileType::kShapefile,
  FileType::kFlatGeobuf
}
 
enum  FileCompression { FileCompression::kNone, FileCompression::kGZip, FileCompression::kZip }
 
enum  ArrayNullHandling { ArrayNullHandling::kAbortWithWarning, ArrayNullHandling::kExportSentinels, ArrayNullHandling::kExportZeros, ArrayNullHandling::kNullEntireField }
 
- Static Public Member Functions inherited from import_export::QueryExporter
static std::unique_ptr
< QueryExporter
create (const FileType file_type)
 
- Protected Member Functions inherited from import_export::QueryExporter
void validateFileExtensions (const std::string &file_path, const std::string &file_type, const std::unordered_set< std::string > &valid_extensions) const
 
std::string safeColumnName (const std::string &resname, const int column_index)
 
- Protected Attributes inherited from import_export::QueryExporter
const FileType file_type_
 

Detailed Description

Definition at line 31 of file QueryExporterGDAL.h.

Constructor & Destructor Documentation

import_export::QueryExporterGDAL::QueryExporterGDAL ( const FileType  file_type)
explicit
import_export::QueryExporterGDAL::QueryExporterGDAL ( )
delete
import_export::QueryExporterGDAL::~QueryExporterGDAL ( )
override

Definition at line 42 of file QueryExporterGDAL.cpp.

References cleanUp().

42  {
43  cleanUp();
44 }

+ Here is the call graph for this function:

Member Function Documentation

void import_export::QueryExporterGDAL::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

Definition at line 163 of file QueryExporterGDAL.cpp.

References array_null_handling_, CHECK, cleanUp(), import_export::anonymous_namespace{QueryExporterGDAL.cpp}::compression_implemented, import_export::anonymous_namespace{QueryExporterGDAL.cpp}::compression_prefix, import_export::anonymous_namespace{QueryExporterGDAL.cpp}::compression_suffix, copy_params_, import_export::anonymous_namespace{QueryExporterGDAL.cpp}::driver_names, field_indices_, import_export::QueryExporter::file_type_, import_export::anonymous_namespace{QueryExporterGDAL.cpp}::file_type_names, import_export::anonymous_namespace{QueryExporterGDAL.cpp}::file_type_valid_extensions, nvtx_helpers::anonymous_namespace{nvtx_helpers.cpp}::filename(), gdal_dataset_, logger::INFO, Geospatial::GDAL::init(), kLINESTRING, kMULTILINESTRING, kMULTIPOINT, kMULTIPOLYGON, import_export::QueryExporter::kNone, kPOINT, kPOLYGON, LOG, ogr_layer_, import_export::QueryExporter::safeColumnName(), SCI, import_export::anonymous_namespace{QueryExporterGDAL.cpp}::sql_type_info_to_ogr_field_type(), to_string(), and import_export::QueryExporter::validateFileExtensions().

168  {
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 kMULTIPOINT:
195  ogr_geometry_type = wkbMultiPoint;
196  break;
197  case kLINESTRING:
198  ogr_geometry_type = wkbLineString;
199  break;
200  case kMULTILINESTRING:
201  ogr_geometry_type = wkbMultiLineString;
202  break;
203  case kPOLYGON:
204  ogr_geometry_type = wkbPolygon;
205  break;
206  case kMULTIPOLYGON:
207  ogr_geometry_type = wkbMultiPolygon;
208  break;
209  default:
210  CHECK(false);
211  }
212  geo_column_srid = type_info.get_output_srid();
213  geo_column_name = safeColumnName(column_info.get_resname(), num_columns + 1);
214  num_geo_columns++;
215  } else {
216  auto column_name = safeColumnName(column_info.get_resname(), num_columns + 1);
217  // this will throw if column type is unsupported for this file type
218  sql_type_info_to_ogr_field_type(column_name, type_info, file_type_);
219  }
220  num_columns++;
221  }
222  if (num_geo_columns != 1) {
223  throw std::runtime_error("File type '" +
224  std::string(file_type_names[SCI(file_type_)]) +
225  "' requires exactly one geo column in query results");
226  }
227 
228  // validate SRID
229  if (geo_column_srid <= 0) {
230  throw std::runtime_error("Geo column '" + geo_column_name + "' has invalid SRID (" +
231  std::to_string(geo_column_srid) +
232  "). Use ST_SetSRID() in query to override.");
233  }
234 
235  // get driver
236  auto const& driver_name = driver_names[SCI(file_type_)];
237  auto gdal_driver = GetGDALDriverManager()->GetDriverByName(driver_name);
238  if (gdal_driver == nullptr) {
239  throw std::runtime_error("Failed to find Driver '" + std::string(driver_name) +
240  "'");
241  }
242 
243  // compression?
244  auto gdal_file_path{file_path};
245  auto user_file_path{file_path};
246  if (file_compression != FileCompression::kNone) {
247  auto impl = compression_implemented[SCI(file_type_)][SCI(file_compression)];
248  if (!impl) {
249  // @TODO(se) implement more compression options
250  throw std::runtime_error(
251  "Selected file compression option not yet supported for file type '" +
252  std::string(file_type_names[SCI(file_type_)]) + "'");
253  }
254  gdal_file_path.insert(0, compression_prefix[SCI(file_compression)]);
255  gdal_file_path.append(compression_suffix[SCI(file_compression)]);
256  user_file_path.append(compression_suffix[SCI(file_compression)]);
257  }
258 
259  // delete any existing file(s) (with and without compression suffix)
260  // GeoJSON driver occasionally refuses to overwrite
261  auto remove_file = [](const std::string& filename) {
262  if (boost::filesystem::exists(filename)) {
263  LOG(INFO) << "Deleting existing file '" << filename << "'";
264  boost::filesystem::remove(filename);
265  }
266  };
267  remove_file(file_path);
268  remove_file(user_file_path);
269 
270  LOG(INFO) << "Exporting to file '" << user_file_path << "'";
271 
272  // create dataset
273  gdal_dataset_ =
274  gdal_driver->Create(gdal_file_path.c_str(), 0, 0, 0, GDT_Unknown, NULL);
275  if (gdal_dataset_ == nullptr) {
276  throw std::runtime_error("Failed to create File '" + file_path + "'");
277  }
278 
279  // create spatial reference
280  OGRSpatialReference ogr_spatial_reference;
281  if (ogr_spatial_reference.importFromEPSG(geo_column_srid)) {
282  throw std::runtime_error("Failed to create Spatial Reference for SRID " +
283  std::to_string(geo_column_srid) + "");
284  }
285 #if GDAL_VERSION_MAJOR >= 3
286  ogr_spatial_reference.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
287 #endif
288 
289  // create layer
290  ogr_layer_ = gdal_dataset_->CreateLayer(
291  layer_name.c_str(), &ogr_spatial_reference, ogr_geometry_type, NULL);
292  if (ogr_layer_ == nullptr) {
293  throw std::runtime_error("Failed to create Layer '" + layer_name + "'");
294  }
295 
296  // create fields
297  int column_index = 0;
298  int field_index = 0;
299  field_indices_.resize(num_columns);
300  for (auto const& column_info : column_infos) {
301  auto column_name = safeColumnName(column_info.get_resname(), column_index + 1);
302  // create fields for non-geo columns
303  auto const& type_info = column_info.get_type_info();
304  if (!type_info.is_geometry()) {
305  OGRFieldDefn field_defn(
306  column_name.c_str(),
307  sql_type_info_to_ogr_field_type(column_name, type_info, file_type_));
308  if (ogr_layer_->CreateField(&field_defn) != OGRERR_NONE) {
309  throw std::runtime_error("Failed to create Field '" + column_name + "'");
310  }
311  field_indices_[column_index] = field_index;
312  field_index++;
313  } else {
314  field_indices_[column_index] = -1;
315  }
316  column_index++;
317  }
318  } catch (std::exception& e) {
319  LOG(INFO) << "GDAL Query Export failed to start: " << e.what();
320  cleanUp();
321  throw;
322  }
323 }
static constexpr std::array< const char *, 5 > file_type_names
static constexpr std::array< std::array< bool, 3 >, 5 > compression_implemented
#define LOG(tag)
Definition: Logger.h:285
std::string safeColumnName(const std::string &resname, const int column_index)
static void init()
Definition: GDAL.cpp:67
#define SCI(x)
std::string to_string(char const *&&v)
static std::array< std::unordered_set< std::string >, 5 > file_type_valid_extensions
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)
static constexpr std::array< const char *, 3 > compression_suffix
#define CHECK(condition)
Definition: Logger.h:291
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

+ Here is the call graph for this function:

void import_export::QueryExporterGDAL::cleanUp ( )
private

Definition at line 46 of file QueryExporterGDAL.cpp.

References field_indices_, gdal_dataset_, and ogr_layer_.

Referenced by beginExport(), endExport(), exportResults(), and ~QueryExporterGDAL().

46  {
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 }

+ Here is the caller graph for this function:

void import_export::QueryExporterGDAL::endExport ( )
finalvirtual

Implements import_export::QueryExporter.

Definition at line 728 of file QueryExporterGDAL.cpp.

References cleanUp().

728  {
729  cleanUp();
730 }

+ Here is the call graph for this function:

void import_export::QueryExporterGDAL::exportResults ( const std::vector< AggregatedResult > &  query_results)
finalvirtual

Implements import_export::QueryExporter.

Definition at line 660 of file QueryExporterGDAL.cpp.

References array_null_handling_, CHECK, cleanUp(), field_indices_, ResultSet::GeoTargetValue, logger::INFO, import_export::anonymous_namespace{QueryExporterGDAL.cpp}::insert_array_column(), import_export::anonymous_namespace{QueryExporterGDAL.cpp}::insert_geo_column(), import_export::anonymous_namespace{QueryExporterGDAL.cpp}::insert_scalar_column(), LOG, ogr_layer_, and import_export::QueryExporter::safeColumnName().

661  {
662  try {
663  for (auto const& agg_result : query_results) {
664  auto results = agg_result.rs;
665  auto const& targets = agg_result.targets_meta;
666 
667  // configure ResultSet to return geo as raw data
668  results->setGeoReturnType(ResultSet::GeoReturnType::GeoTargetValue);
669 
670  while (true) {
671  auto const crt_row = results->getNextRow(true, true);
672  if (crt_row.empty()) {
673  break;
674  }
675 
676  // create feature for this row
677  auto ogr_feature = OGRFeature::CreateFeature(ogr_layer_->GetLayerDefn());
678  CHECK(ogr_feature);
679 
680  // destroy feature on exiting this scope
681  ScopeGuard destroy_feature = [ogr_feature] {
682  OGRFeature::DestroyFeature(ogr_feature);
683  };
684 
685  for (size_t i = 0; i < results->colCount(); ++i) {
686  auto const tv = crt_row[i];
687  auto const& ti = targets[i].get_type_info();
688  auto const column_name = safeColumnName(targets[i].get_resname(), i + 1);
689  auto const field_index = field_indices_[i];
690 
691  // insert this column into the feature
692  auto const scalar_tv = boost::get<ScalarTargetValue>(&tv);
693  if (scalar_tv) {
694  insert_scalar_column(scalar_tv, ti, field_index, ogr_feature);
695  } else {
696  auto const array_tv = boost::get<ArrayTargetValue>(&tv);
697  if (array_tv) {
698  insert_array_column(array_tv,
699  ti,
700  field_index,
701  ogr_feature,
702  column_name,
704  } else {
705  auto const geo_tv = boost::get<GeoTargetValue>(&tv);
706  if (geo_tv && geo_tv->is_initialized()) {
707  insert_geo_column(geo_tv, ti, field_index, ogr_feature);
708  } else {
709  ogr_feature->SetGeometry(nullptr);
710  }
711  }
712  }
713  }
714 
715  // add feature to layer
716  if (ogr_layer_->CreateFeature(ogr_feature) != OGRERR_NONE) {
717  throw std::runtime_error("Failed to create Feature");
718  }
719  }
720  }
721  } catch (std::exception& e) {
722  LOG(INFO) << "GDAL Query Export failed: " << e.what();
723  cleanUp();
724  throw;
725  }
726 }
#define LOG(tag)
Definition: Logger.h:285
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)
void insert_geo_column(const GeoTargetValue *geo_tv, const SQLTypeInfo &ti, const int field_index, OGRFeature *ogr_feature)
void insert_scalar_column(const ScalarTargetValue *scalar_tv, const SQLTypeInfo &ti, const int field_index, OGRFeature *ogr_feature)
#define CHECK(condition)
Definition: Logger.h:291

+ Here is the call graph for this function:

Member Data Documentation

ArrayNullHandling import_export::QueryExporterGDAL::array_null_handling_
private

Definition at line 51 of file QueryExporterGDAL.h.

Referenced by beginExport(), and exportResults().

CopyParams import_export::QueryExporterGDAL::copy_params_
private

Definition at line 47 of file QueryExporterGDAL.h.

Referenced by beginExport().

std::vector<int> import_export::QueryExporterGDAL::field_indices_
private

Definition at line 50 of file QueryExporterGDAL.h.

Referenced by beginExport(), cleanUp(), and exportResults().

GDALDataset* import_export::QueryExporterGDAL::gdal_dataset_
private

Definition at line 48 of file QueryExporterGDAL.h.

Referenced by beginExport(), and cleanUp().

OGRLayer* import_export::QueryExporterGDAL::ogr_layer_
private

Definition at line 49 of file QueryExporterGDAL.h.

Referenced by beginExport(), cleanUp(), and exportResults().


The documentation for this class was generated from the following files: