@@ -171,6 +171,40 @@ cdef OGRLayerH get_ogr_layer(GDALDatasetH ogr_dataset, layer) except NULL:
171
171
return ogr_layer
172
172
173
173
174
+ cdef OGRLayerH execute_sql(GDALDatasetH ogr_dataset, str sql, str sql_dialect = None ) except NULL :
175
+ """ Execute an SQL statement on a dataset.
176
+
177
+ Parameters
178
+ ----------
179
+ ogr_dataset : pointer to open OGR dataset
180
+ sql : str
181
+ The sql statement to execute
182
+ sql_dialect : str, optional (default: None)
183
+ The sql dialect the sql statement is written in
184
+
185
+ Returns
186
+ -------
187
+ pointer to OGR layer
188
+ """
189
+
190
+ try :
191
+ sql_b = sql.encode(' utf-8' )
192
+ sql_c = sql_b
193
+ if sql_dialect is None :
194
+ return exc_wrap_pointer(GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL , NULL ))
195
+
196
+ sql_dialect_b = sql_dialect.encode(' utf-8' )
197
+ sql_dialect_c = sql_dialect_b
198
+ return exc_wrap_pointer(GDALDatasetExecuteSQL(ogr_dataset, sql_c, NULL , sql_dialect_c))
199
+
200
+ # GDAL does not always raise exception messages in this case
201
+ except NullPointerError:
202
+ raise DataLayerError(f" Error executing sql '{sql}'" ) from None
203
+
204
+ except CPLE_BaseError as exc:
205
+ raise DataLayerError(str (exc))
206
+
207
+
174
208
cdef str get_crs(OGRLayerH ogr_layer):
175
209
""" Read CRS from layer as EPSG:<code> if available or WKT.
176
210
@@ -586,7 +620,6 @@ cdef get_features(
586
620
except CPLE_BaseError as exc:
587
621
raise FeatureError(str (exc))
588
622
589
-
590
623
if return_fids:
591
624
fid_view[i] = OGR_F_GetFID(ogr_feature)
592
625
@@ -738,6 +771,8 @@ def ogr_read(
738
771
object where = None ,
739
772
tuple bbox = None ,
740
773
object fids = None ,
774
+ str sql = None ,
775
+ str sql_dialect = None ,
741
776
int return_fids = False ,
742
777
**kwargs ):
743
778
@@ -752,90 +787,100 @@ def ogr_read(
752
787
path_b = path.encode(' utf-8' )
753
788
path_c = path_b
754
789
755
- # layer defaults to index 0
756
- if layer is None :
757
- layer = 0
758
-
759
790
if fids is not None :
760
- if where is not None or bbox is not None or skip_features or max_features:
791
+ if where is not None or bbox is not None or sql is not None or skip_features or max_features:
761
792
raise ValueError (
762
- " cannot set both 'fids' and any of 'where', 'bbox', "
793
+ " cannot set both 'fids' and any of 'where', 'bbox', 'sql', "
763
794
" 'skip_features' or 'max_features'"
764
795
)
765
796
fids = np.asarray(fids, dtype = np.intc)
766
797
798
+ if sql is not None and layer is not None :
799
+ raise ValueError (" 'sql' paramater cannot be combined with 'layer'" )
800
+
767
801
ogr_dataset = ogr_open(path_c, 0 , kwargs)
768
- ogr_layer = get_ogr_layer(ogr_dataset, layer)
802
+ try :
803
+ if sql is None :
804
+ # layer defaults to index 0
805
+ if layer is None :
806
+ layer = 0
807
+ ogr_layer = get_ogr_layer(ogr_dataset, layer)
808
+ else :
809
+ ogr_layer = execute_sql(ogr_dataset, sql, sql_dialect)
769
810
770
- crs = get_crs(ogr_layer)
811
+ crs = get_crs(ogr_layer)
771
812
772
- # Encoding is derived from the dataset, from the user, or from the system locale
773
- encoding = (
774
- detect_encoding(ogr_dataset, ogr_layer)
775
- or encoding
776
- or locale.getpreferredencoding()
777
- )
813
+ # Encoding is derived from the dataset, from the user, or from the system locale
814
+ encoding = (
815
+ detect_encoding(ogr_dataset, ogr_layer)
816
+ or encoding
817
+ or locale.getpreferredencoding()
818
+ )
778
819
779
- fields = get_fields(ogr_layer, encoding)
820
+ fields = get_fields(ogr_layer, encoding)
780
821
781
- if columns is not None :
782
- # Fields are matched exactly by name, duplicates are dropped.
783
- # Find index of each field into fields
784
- idx = np.intersect1d(fields[:,2 ], columns, return_indices = True )[1 ]
785
- fields = fields[idx, :]
822
+ if columns is not None :
823
+ # Fields are matched exactly by name, duplicates are dropped.
824
+ # Find index of each field into fields
825
+ idx = np.intersect1d(fields[:,2 ], columns, return_indices = True )[1 ]
826
+ fields = fields[idx, :]
786
827
787
- geometry_type = get_geometry_type(ogr_layer)
828
+ geometry_type = get_geometry_type(ogr_layer)
788
829
789
- if fids is not None :
790
- geometries, field_data = get_features_by_fid(
791
- ogr_layer,
792
- fids,
793
- fields,
794
- encoding,
795
- read_geometry = read_geometry and geometry_type is not None ,
796
- force_2d = force_2d,
797
- )
830
+ if fids is not None :
831
+ geometries, field_data = get_features_by_fid(
832
+ ogr_layer,
833
+ fids,
834
+ fields,
835
+ encoding,
836
+ read_geometry = read_geometry and geometry_type is not None ,
837
+ force_2d = force_2d,
838
+ )
798
839
799
- # bypass reading fids since these should match fids used for read
800
- if return_fids:
801
- fid_data = fids.astype(np.int64)
840
+ # bypass reading fids since these should match fids used for read
841
+ if return_fids:
842
+ fid_data = fids.astype(np.int64)
843
+ else :
844
+ fid_data = None
802
845
else :
803
- fid_data = None
804
- else :
805
- # Apply the attribute filter
806
- if where is not None and where != " " :
807
- apply_where_filter(ogr_layer, where)
846
+ # Apply the attribute filter
847
+ if where is not None and where != " " :
848
+ apply_where_filter(ogr_layer, where)
808
849
809
- # Apply the spatial filter
810
- if bbox is not None :
811
- apply_spatial_filter(ogr_layer, bbox)
850
+ # Apply the spatial filter
851
+ if bbox is not None :
852
+ apply_spatial_filter(ogr_layer, bbox)
812
853
813
- # Limit feature range to available range
814
- skip_features, max_features = validate_feature_range(
815
- ogr_layer, skip_features, max_features
816
- )
854
+ # Limit feature range to available range
855
+ skip_features, max_features = validate_feature_range(
856
+ ogr_layer, skip_features, max_features
857
+ )
817
858
818
- fid_data, geometries, field_data = get_features(
819
- ogr_layer,
820
- fields,
821
- encoding,
822
- read_geometry = read_geometry and geometry_type is not None ,
823
- force_2d = force_2d,
824
- skip_features = skip_features,
825
- max_features = max_features,
826
- return_fids = return_fids
827
- )
859
+ fid_data, geometries, field_data = get_features(
860
+ ogr_layer,
861
+ fields,
862
+ encoding,
863
+ read_geometry = read_geometry and geometry_type is not None ,
864
+ force_2d = force_2d,
865
+ skip_features = skip_features,
866
+ max_features = max_features,
867
+ return_fids = return_fids
868
+ )
828
869
829
- meta = {
830
- ' crs' : crs,
831
- ' encoding' : encoding,
832
- ' fields' : fields[:,2 ], # return only names
833
- ' geometry_type' : geometry_type
834
- }
870
+ meta = {
871
+ ' crs' : crs,
872
+ ' encoding' : encoding,
873
+ ' fields' : fields[:,2 ], # return only names
874
+ ' geometry_type' : geometry_type
875
+ }
835
876
836
- if ogr_dataset != NULL :
837
- GDALClose(ogr_dataset)
838
- ogr_dataset = NULL
877
+ finally :
878
+ if ogr_dataset != NULL :
879
+ if sql is not None :
880
+ GDALDatasetReleaseResultSet(ogr_dataset, ogr_layer)
881
+
882
+ GDALClose(ogr_dataset)
883
+ ogr_dataset = NULL
839
884
840
885
return (
841
886
meta,
@@ -1015,7 +1060,6 @@ cdef void * create_crs(str crs) except NULL:
1015
1060
return ogr_crs
1016
1061
1017
1062
1018
-
1019
1063
cdef infer_field_types(list dtypes):
1020
1064
cdef int field_type = 0
1021
1065
cdef int field_subtype = 0
0 commit comments