Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Dataset::has_capability #585

Merged
merged 1 commit into from
Nov 28, 2024
Merged

Conversation

Atreyagaurav
Copy link
Contributor

  • I agree to follow the project's code of conduct.
  • I added an entry to CHANGES.md if knowledge of this change could be valuable to users.

This is for doing things like Dataset::has_capability(DatasetCaps::ODsCTransactions) to check if dataset supports Transaction.

I added the Capabilities from:

I followed the example of Layer::has_capability for both of them.

This will help use the if {} else {} block for capability based logic like the one mentioned in #582

Basically it'll make it so that @lnicola 's Suggestion given below can work:

let stuffs = |d: &Dataset| -> Result<()> { ... };
if /* transactions are supported */ {
    let txn = d.start_transaction()?;
    stuffs(&txn)?;
    txn.commit()?;
} else {
    stuffs(&d)?;
}

Currently, without this function, we have to wait for the result of Dataset::start_transaction to know if it supports it, in which case we cannot use if () {} else {} block due to Rust's borrow rules as the Dataset::start_transaction will take &mut Dataset.

@Atreyagaurav
Copy link
Contributor Author

About the Enum variants, since clippy warns about the Prefix, should we just remove them? Since these are rust enum, I think we don't need the prefixes like ODrC, ODsC, OLC etc. on the enum itself as the Enum names (LayerCaps, DriverCaps, DatasetCaps etc.) are enough to distinguish them unlike in C.

I just followed what LayerCaps was doing for the other two. Changing that would be breaking change, but at least for the new ones we could not add Prefixes.

src/driver.rs Outdated

pub fn has_capability(&self, capability: DriverCaps) -> bool {
unsafe {
gdal_sys::OGR_Dr_TestCapability(self.c_driver(), capability.into_cstring().as_ptr())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OGR_Dr_ is a legacy API.
The equivalent of ODrCCreateDataSource is testing the presence of GDAL_DCAP_CREATE in the driver metadata. Cf https://gdal.org/en/latest/doxygen/ogr__api_8h.html#a9010219bbc2e32627064ed860048d979
It looks we don't have an equivalent of ODrCDeleteDataSource though

Copy link
Contributor Author

@Atreyagaurav Atreyagaurav Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should remove Driver::has_capability in that case. And we can add the new one later. Or accept the legacy API for now. But considering there are only two capability to check, I think it is fine to not have this method for now.

What do you think?

EDIT:
When I did dir(gdal) on python, I get these, if DCAP_CREATE is checked for create capability, then it makes sense to use others for similar capabilities as well. It is probably already implemented for Metadata check somewhere, though (but I guess we can make a method specific to check DCAP_ metadata).

['DCAP_COORDINATE_EPOCH', 'DCAP_CREATE', 'DCAP_CREATECOPY', 
'DCAP_CREATECOPY_MULTIDIMENSIONAL', 'DCAP_CREATE_FIELD', 'DCAP_CREATE_LAYER', 
'DCAP_CREATE_MULTIDIMENSIONAL', 'DCAP_CURVE_GEOMETRIES', 'DCAP_DEFAULT_FIELDS', 
'DCAP_DELETE_FIELD', 'DCAP_DELETE_LAYER', 'DCAP_FEATURE_STYLES', 'DCAP_FEATURE_STYLES_READ', 
'DCAP_FEATURE_STYLES_WRITE', 'DCAP_FIELD_DOMAINS', 'DCAP_FLUSHCACHE_CONSISTENT_STATE', 
'DCAP_GNM', 'DCAP_MEASURED_GEOMETRIES', 'DCAP_MULTIDIM_RASTER', 
'DCAP_MULTIPLE_VECTOR_LAYERS', 'DCAP_NONSPATIAL', 'DCAP_NOTNULL_FIELDS', 
'DCAP_NOTNULL_GEOMFIELDS', 'DCAP_OPEN', 'DCAP_RASTER', 'DCAP_RELATIONSHIPS', 
'DCAP_RENAME_LAYERS', 'DCAP_REORDER_FIELDS', 'DCAP_SUBCREATECOPY', 'DCAP_UNIQUE_FIELDS', 
'DCAP_VECTOR', 'DCAP_VIRTUALIO', 'DCAP_Z_GEOMETRIES']

@lnicola lnicola mentioned this pull request Nov 23, 2024
2 tasks
@Atreyagaurav
Copy link
Contributor Author

I'm waiting on whether to remove Driver::has_capability since it is based on legacy API, or rewrite it to use the DCAP metadata instead. Or maybe just adding a metadata checking function (if it doesn't exist already) is sufficient.

@lnicola
Copy link
Member

lnicola commented Nov 28, 2024

I think we can do something like below, what do you say?

struct DatasetCapability(&'static CStr); // we could also support non-'static ones, but probably not worth it

impl DatasetCapability {
    pub const CREATE_LAYER: DatasetCapability = DatasetCapability(c"CreateLayer");
    pub const DELETE_LAYER: DatasetCapability = DatasetCapability(c"DeleteLayer");
}

struct Dataset;
impl Dataset {
    pub fn test_capability(&self, cap: DatasetCapability) -> bool {
        _ = cap.0;

        // this is the best dataset
        true
    }
}

This is a little shorter, while still allowing custom caps if the user ever needs one.

@Atreyagaurav
Copy link
Contributor Author

Atreyagaurav commented Nov 28, 2024

@lnicola The DatasetCapability is not deprecated, and there are a fixed list on gdal side so I think it's fine.
https://gdal.org/en/stable/api/gdaldataset_cpp.html#_CPPv4N11GDALDataset14TestCapabilityEPKc

The Driver test capability is the one that is deprecated. So I think we can just remove it for now. I did initially made this to add a test condition to see if database supports transition. I added the Driver capability for completeness, but if it's deprecated it's fine.

Now this only contains Dataset::has_capability.

Edit:
It might be a good idea to make a function that tests using GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE) and similar, but I didn't find GDAL_DCAP_CREATE in gdal_sys, so I'm leaving it for later.

@Atreyagaurav
Copy link
Contributor Author

Github again closed it while I was doing forced updates....

@Atreyagaurav Atreyagaurav reopened this Nov 28, 2024
@Atreyagaurav Atreyagaurav changed the title Add Dataset::has_capability and Driver:has_capability Add Dataset::has_capability ~~ and Driver:has_capability~~ Nov 28, 2024
@Atreyagaurav Atreyagaurav changed the title Add Dataset::has_capability ~~ and Driver:has_capability~~ Add Dataset::has_capability ~~and Driver:has_capability~~ Nov 28, 2024
@Atreyagaurav Atreyagaurav changed the title Add Dataset::has_capability ~~and Driver:has_capability~~ Add Dataset::has_capability Nov 28, 2024
@Atreyagaurav
Copy link
Contributor Author

Is that memory leak my fault? I'm using the same code as the one in Layer::has_capabilities that was already there.

@lnicola
Copy link
Member

lnicola commented Nov 28, 2024

No, it's a bug in Rust 1.83, which was just released. It seems to be already fixed in beta.

@Atreyagaurav
Copy link
Contributor Author

Thank you, can you merge with failed tests? or should I do something?

@lnicola
Copy link
Member

lnicola commented Nov 28, 2024

The DatasetCapability is not deprecated, and there are a fixed list on gdal side so I think it's fine.

My version has much less code, runs slightly faster, and can still be extended if GDAL adds a new capability, so I still think it's an improvement.

Thank you, can you merge with failed tests? or should I do something?

I disabled the test, you can rebase.

@Atreyagaurav Atreyagaurav force-pushed the ds-capabilities branch 2 times, most recently from 2f90f90 to 0e15b00 Compare November 28, 2024 18:28
@lnicola
Copy link
Member

lnicola commented Nov 28, 2024

That wasn't a clean rebase or squash but.. whatever, I guess. Anyway, please capitalize datasource in the doc-comments, and add a . at the end, they're a bit hard to read right now.

Afterwards I think we can merge this and use it in #591?

@Atreyagaurav Atreyagaurav force-pushed the ds-capabilities branch 2 times, most recently from eb9b5a7 to 0418dc1 Compare November 28, 2024 18:32
@Atreyagaurav
Copy link
Contributor Author

Atreyagaurav commented Nov 28, 2024

Sorry, I was struggling with rebase since the Valgrind was in the middle of two commits I made. It should be clean now, I undid everything and made a new commit on top.

@lnicola
Copy link
Member

lnicola commented Nov 28, 2024

Yeah, it's clean now, thanks!

@Atreyagaurav
Copy link
Contributor Author

Afterwards I think we can merge this and use it in #591?

About that, this one is so that we can manually do the "if supports transaction" part by ourselves.

I think the #591 is a bit different because even if starting transaction fails we want to continue writing to database as the transaction is optional and for speedup process only.

@lnicola
Copy link
Member

lnicola commented Nov 28, 2024

If the driver supports transactions (like GPKG) and StartTransaction fails, I think it's fine to propagate that error to the user. It means something is really wrong and we can't do much about it.

src/dataset.rs Outdated Show resolved Hide resolved
@@ -327,6 +354,10 @@ impl Dataset {
}
Ok(transformation)
}

pub fn has_capability(&self, capability: DatasetCapability) -> bool {
unsafe { gdal_sys::GDALDatasetTestCapability(self.c_dataset(), capability.0.as_ptr()) == 1 }
Copy link
Member

@lnicola lnicola Nov 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I do hope that TRUE is 1 and not 0xFFFF_FFFF 😅.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what test cases are for. It's working for now.

@lnicola lnicola merged commit 9692dae into georust:master Nov 28, 2024
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants