Skip to content

Commit

Permalink
- fix missing C++ functions for SQL new SQL methods
Browse files Browse the repository at this point in the history
- document all options for new SQL methods
- add more error handling tests for SQL methods
  • Loading branch information
apjoseph committed Jul 25, 2024
1 parent 3584dce commit 6aa253d
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 91 deletions.
33 changes: 33 additions & 0 deletions godal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,39 @@ OGRLayerH godalDatasetExecuteSQL(cctx *ctx, GDALDatasetH ds, char *sql, OGRGeome
return ret;
}

void godalReleaseResultSet(cctx *ctx, GDALDatasetH ds, OGRLayerH rs) {
godalWrap(ctx);
GDALDatasetReleaseResultSet(ds,rs);
godalUnwrap();
}

void godalStartTransaction(cctx *ctx, GDALDatasetH ds, int bForce) {
godalWrap(ctx);
OGRErr gret = GDALDatasetStartTransaction(ds,bForce);
if (gret != OGRERR_NONE) {
forceOGRError(ctx,gret);
}
godalUnwrap();
}

void godalDatasetRollbackTransaction(cctx *ctx, GDALDatasetH ds) {
godalWrap(ctx);
OGRErr gret = GDALDatasetRollbackTransaction(ds);
if (gret != OGRERR_NONE) {
forceOGRError(ctx,gret);
}
godalUnwrap();
}

void godalCommitTransaction(cctx *ctx, GDALDatasetH ds) {
godalWrap(ctx);
OGRErr gret = GDALDatasetCommitTransaction(ds);
if (gret != OGRERR_NONE) {
forceOGRError(ctx,gret);
}
godalUnwrap();
}

void godalLayerGetExtent(cctx *ctx, OGRLayerH layer, OGREnvelope *envelope) {
godalWrap(ctx);
OGRErr gret = OGR_L_GetExtent(layer, envelope, 1);
Expand Down
100 changes: 10 additions & 90 deletions godal.go
Original file line number Diff line number Diff line change
Expand Up @@ -3365,61 +3365,16 @@ func (ds *Dataset) LayerByName(name string) *Layer {
return &Layer{majorObject{C.GDALMajorObjectH(hndl)}}
}

type SpatialFilterOption struct {
geom *Geometry
}

func (sf SpatialFilterOption) setExecuteSQLOpt(eso *executeSQLOpts) {
eso.spatialFilter = sf
}

func SpatialFilter(geom *Geometry) SpatialFilterOption {
return SpatialFilterOption{geom}
}

type executeSQLOpts struct {
dialect SQLDialect
spatialFilter SpatialFilterOption
errorHandler ErrorHandler
}

type SQLDialect string

func (s SQLDialect) setExecuteSQLOpt(eso *executeSQLOpts) {
eso.dialect = s
}

func OGRSQLDialect() SQLDialect {
return "OGRSQL"
}

func SQLiteDialect() SQLDialect {
return "SQLite"
}

func IndirectSQLite() SQLDialect {
return "INDIRECT_SQLITE"
}

type ExecuteSQLOption interface {
setExecuteSQLOpt(eso *executeSQLOpts)
}

// ResultSet is a Layer generated by Dataset.ExecuteSQL
type ResultSet struct {
Layer
ds *Dataset
closed bool
}

type closeResultSetOpts struct {
errorHandler ErrorHandler
}

type CloseResultSetOption interface {
setReleaseResultSetOpt(rrso *closeResultSetOpts)
}

// ExecuteSQL executes an SQL statement against the data store.
// This function may return a nil ResultSet when the SQL statement does not generate any rows to
// return (INSERT/UPDATE/DELETE/CREATE TABLE etc.)
func (ds *Dataset) ExecuteSQL(sql string, opts ...ExecuteSQLOption) (*ResultSet, error) {

eso := executeSQLOpts{}
Expand Down Expand Up @@ -3454,7 +3409,7 @@ func (ds *Dataset) ExecuteSQL(sql string, opts ...ExecuteSQLOption) (*ResultSet,
return &ResultSet{layer, ds, false}, nil
}

// Close Release results of ExecuteSQL().
// Close releases results of Dataset.ExecuteSQL
func (rs *ResultSet) Close(opts ...CloseResultSetOption) error {
if rs.closed {
return nil
Expand All @@ -3465,31 +3420,12 @@ func (rs *ResultSet) Close(opts ...CloseResultSetOption) error {
opt.setReleaseResultSetOpt(&crso)
}
cgc := createCGOContext(nil, crso.errorHandler)
C.GDALDatasetReleaseResultSet(rs.ds.handle(), rs.handle())
C.godalReleaseResultSet(cgc.cPointer(), rs.ds.handle(), rs.handle())
err := cgc.close()
rs.closed = true
return err
}

type ForceTx bool

func EmulatedTx() ForceTx {
return true
}

type startTransactionOpts struct {
bForce ForceTx
errorHandler ErrorHandler
}

func (t ForceTx) setStartTransactionOpt(sto *startTransactionOpts) {
sto.bForce = t
}

type StartTransactionOption interface {
setStartTransactionOpt(sto *startTransactionOpts)
}

// StartTransaction creates a transaction for datasets which support transactions
func (ds *Dataset) StartTransaction(opts ...StartTransactionOption) error {

Expand All @@ -3505,20 +3441,12 @@ func (ds *Dataset) StartTransaction(opts ...StartTransactionOption) error {
}

cgc := createCGOContext(nil, sto.errorHandler)
C.GDALDatasetStartTransaction(ds.handle(), cEff)
C.godalStartTransaction(cgc.cPointer(), ds.handle(), cEff)
err := cgc.close()
return err
}

type rollbackTransactionOpts struct {
errorHandler ErrorHandler
}

type RollbackTransactionOption interface {
setRollbackTransactionOpt(rto *rollbackTransactionOpts)
}

// RollbackTransaction rolls back a dataset to its state before the start of the current transaction
// RollbackTransaction rolls back a Dataset to its state before the start of the current transaction
func (ds *Dataset) RollbackTransaction(opts ...RollbackTransactionOption) error {

rto := rollbackTransactionOpts{}
Expand All @@ -3527,20 +3455,12 @@ func (ds *Dataset) RollbackTransaction(opts ...RollbackTransactionOption) error
}

cgc := createCGOContext(nil, rto.errorHandler)
C.GDALDatasetRollbackTransaction(ds.handle())
C.godalDatasetRollbackTransaction(cgc.cPointer(), ds.handle())
err := cgc.close()
return err
}

type commitTransactionOpts struct {
errorHandler ErrorHandler
}

type CommitTransactionOption interface {
setCommitTransactionOpt(rto *commitTransactionOpts)
}

// CommitTransaction commits a transaction for datasets which support transactions
// CommitTransaction commits a transaction for a Dataset that supports transactions
func (ds *Dataset) CommitTransaction(opts ...CommitTransactionOption) error {

cto := commitTransactionOpts{}
Expand All @@ -3549,7 +3469,7 @@ func (ds *Dataset) CommitTransaction(opts ...CommitTransactionOption) error {
}

cgc := createCGOContext(nil, cto.errorHandler)
C.GDALDatasetCommitTransaction(ds.handle())
C.godalCommitTransaction(cgc.cPointer(), ds.handle())
err := cgc.close()
return err
}
Expand Down
4 changes: 4 additions & 0 deletions godal.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ extern "C" {
OGRLayerH godalCreateLayer(cctx *ctx, GDALDatasetH ds, char *name, OGRSpatialReferenceH sr, OGRwkbGeometryType gtype);
OGRLayerH godalCopyLayer(cctx *ctx, GDALDatasetH ds, OGRLayerH layer, char *name);
OGRLayerH godalDatasetExecuteSQL(cctx *ctx, GDALDatasetH ds, char *sql, OGRGeometryH filter, char *dialect);
void godalReleaseResultSet(cctx *ctx, GDALDatasetH ds, OGRLayerH rs);
void godalStartTransaction(cctx *ctx, GDALDatasetH ds, int bForce);
void godalDatasetRollbackTransaction(cctx *ctx, GDALDatasetH ds);
void godalCommitTransaction(cctx *ctx, GDALDatasetH ds);
void VSIInstallGoHandler(cctx *ctx, const char *pszPrefix, size_t bufferSize, size_t cacheSize);

void godalGetColorTable(GDALRasterBandH bnd, GDALPaletteInterp *interp, int *nEntries, short **entries);
Expand Down
15 changes: 14 additions & 1 deletion godal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2618,7 +2618,7 @@ func TestExecuteSQL(t *testing.T) {
err = rs.Close(el)
assert.NoError(t, err)

rs, err = ds.ExecuteSQL("SELECT * FROM test", IndirectSQLite(), el)
rs, err = ds.ExecuteSQL("SELECT * FROM test", IndirectSQLiteDialect(), el)
assert.NoError(t, err)
fc, _ = rs.FeatureCount()
assert.Equal(t, 2, fc)
Expand All @@ -2628,9 +2628,22 @@ func TestExecuteSQL(t *testing.T) {
err = rs.Close()
assert.NoError(t, err)

// test error handling

rs, err = ds.ExecuteSQL("SELECT * FROM i_do_not_exist", el)
assert.Nil(t, rs)
assert.Error(t, err)

err = ds.RollbackTransaction(el)
assert.Error(t, err)

err = ds.CommitTransaction(el)
assert.Error(t, err)

err = ds.StartTransaction(el)
assert.NoError(t, err)
err = ds.StartTransaction(el)
assert.Error(t, err)
}

func TestVectorLayer(t *testing.T) {
Expand Down
119 changes: 119 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -1528,3 +1528,122 @@ func VSIHandlerCacheSize(s int) VSIHandlerOption {
func VSIHandlerStripPrefix(v bool) VSIHandlerOption {
return stripPrefixOpt{v}
}

type SpatialFilterOption struct {
geom *Geometry
}

func (sf SpatialFilterOption) setExecuteSQLOpt(eso *executeSQLOpts) {
eso.spatialFilter = sf
}

// SpatialFilter filters a ResultSet using the provided Geometry
func SpatialFilter(geom *Geometry) SpatialFilterOption {
return SpatialFilterOption{geom}
}

type executeSQLOpts struct {
dialect SQLDialect
spatialFilter SpatialFilterOption
errorHandler ErrorHandler
}

// SQLDialect is a SQL dialect that be passed to Dataset.ExecuteSQL
//
// Available options are:
// - OGRSQLDialect
// - SQLiteDialect
// - IndirectSQLiteDialect
type SQLDialect string

func (s SQLDialect) setExecuteSQLOpt(eso *executeSQLOpts) {
eso.dialect = s
}

// OGRSQLDialect is GDAL's built-in SQL dialect. This is the default where
// the driver does provide its own native SQLDialect
func OGRSQLDialect() SQLDialect {
return "OGRSQL"
}

// SQLiteDialect is an alternative to the OGRSQLDialect and may be used with any Vector Dataset
// If GDAL was compiled with Spatialite, this dialect will allow the usage of Spatialite functions.
func SQLiteDialect() SQLDialect {
return "SQLite"
}

// IndirectSQLiteDialect forces GDAL to use Virtual Tables when the DataSource uses its native SQLiteDialect
// This should be used sparingly as it is highly likely to degrade performance.
func IndirectSQLiteDialect() SQLDialect {
return "INDIRECT_SQLITE"
}

// ExecuteSQLOption is an option that can be passed to Dataset.ExecuteSQL
//
// Available options are:
// - SQLDialect
// - SpatialFilterOption
type ExecuteSQLOption interface {
setExecuteSQLOpt(eso *executeSQLOpts)
}

type closeResultSetOpts struct {
errorHandler ErrorHandler
}

// CloseResultSetOption is an option that can be passed to ResultSet.Close
//
// There are currently no options available
type CloseResultSetOption interface {
setReleaseResultSetOpt(rrso *closeResultSetOpts)
}

// EmulateTx By default, GDAL only allows transactions deemed by its maintainers to be sufficiently efficienct
// However it is possible to force the driver to use a potentially slow emulated by providing EmulatedTx to
// StartTransaction
type EmulateTx bool

// EmulatedTx forces the driver to allow potentially slow transactions in a Vector Dataset
// if the driver does not have transaction mechanism deemed sufficiently performant by GDAL's maintainers.
func EmulatedTx() EmulateTx {
return true
}

type startTransactionOpts struct {
bForce EmulateTx
errorHandler ErrorHandler
}

func (t EmulateTx) setStartTransactionOpt(sto *startTransactionOpts) {
sto.bForce = t
}

// StartTransactionOption is an option that can be passed to Dataset.StartTransaction
//
// Available options are:
// - EmulateTx
type StartTransactionOption interface {
setStartTransactionOpt(sto *startTransactionOpts)
}

type rollbackTransactionOpts struct {
errorHandler ErrorHandler
}

// RollbackTransactionOption is an option that can be passed to Dataset.RollbackTransaction
//
// There are currently no options available
type RollbackTransactionOption interface {
setRollbackTransactionOpt(rto *rollbackTransactionOpts)
}

type commitTransactionOpts struct {
errorHandler ErrorHandler
}

// CommitTransactionOption is an option that can be passed to Dataset.CommitTransaction
//
// There are currently no options available
type CommitTransactionOption interface {
setCommitTransactionOpt(rto *commitTransactionOpts)
}

0 comments on commit 6aa253d

Please sign in to comment.