feat(format): add generic metadata API - #4544
Conversation
Extracted from apache#3607 with influence by the comments there and apache/arrow-adbc@main...CurtHagenlocher:arrow-adbc:MoreResults, this contains a proposal for handling multi-result set query execution via ADBC by adding a new function for drivers, `AdbcStatementNextResultSet`. This also includes the necessary changes for an ADBC API Revision 1.2.0 (macro defines and so on). The comment above the function includes all the semantic definitions of the behavior.
- Add `constraint_expression` - Add various fields for foreign keys Closes apache#3987. Closes apache#3989.
|
Also CC @iconara I've also been thinking about your request for stateless pagination, and I think it's reasonable enough to define a way to get/pass a pagination token. I think there are enough systems that could use it: Athena, BigQuery, Databricks, Snowflake, Iceberg REST catalog, etc. |
|
And also CC @mullinsms, who kicked all this off by listing all the types of metadata we didn't support 🙂 In particular, Curt's suggestion means we can support database-specific metadata (though, I'm still of the opinion that something truly database-specific is probably better handled by the application; if the application has a very specific metadata query it wants to issue I'm not sure how useful it is to build it into the driver). |
|
At the risk of overcomplicating things: similar to #3623, it might be nice to have a way to request that certain extra fields be included/omitted, e.g. table properties (#3995), where it may be efficient to fetch the data at the same time as the "standard" fields, but where some (many) clients also may not want the field. Maybe it could optionally take an Arrow schema as input for that. Similarly, maybe the application wants to opt in to run-length-encoding certain response columns to save memory. (Or is that not really a concern so long as things are properly streamed/paginated?) |
|
I think I'm leaning towards having all options/filters be set by SetOption. This is perhaps inconvenient for C/C++ users, but language-level bindings can present higher level APIs, and allows us to express better type safety. This would also be consistent with my suggestion in #4317. Either way, the current declaration needs to clarify the lifetime of the filter argument anyways (the driver should copy arguments as it is not allowed to assume filters will be valid during the returned record reader's lifetime). I thought about having a SetOptionStringList. This would be useful if we do want to support Iceberg-style catalogs, as we need a way to pass a list of namespace parts, and I would rather avoid trying to encode strings into a single string (via e.g. JSON). But maybe we can embrace Curt's suggestions and lean on Parquet Variant for encoding these sorts of complex-type arguments. That said, I fear I'm reinventing COM or some sort of intraprocess RPC mechanism... |
This is kind of ugly but I see what you're getting at. GDAL handles this with
It's a hack, but some REST APIs use the unit separator ( I'm guessing you don't want to go this direction, but I can't help but notice there's a large amount of complexity associated with stuffing these concepts into Arrow arrays that are highly nested and very difficult to parse. I'll throw out that you could do something like struct AdbcCatalogNode {
AdbcStatus (*get_property)(struct AdbcCatalogNode* self, const char* what, struct ArrowSchema* out_schema, struct ArrowArray* out_array, AdbcError* err);
AdbcStatus (*get_child)(struct AdbcCatalogNode* self, const char* what, AdbcError* err);
void* private_data;
void* private_driver;
}
AdbcStatus AdbcConnectionGetCatalogs(struct AdbcConnection* connection, const char** options, struct AdbcCatalogNode* out, AdbcError* err);Not perfect, but maybe lets some of this complexity get pushed onto the driver instead of on the consumer since drivers might have abstractions for some of this already. |
| /// | ||
| /// \param[in] connection The database connection. | ||
| /// \param[in] collection The collection to fetch. | ||
| /// \param[out] out The result set. |
There was a problem hiding this comment.
The filters params are missing from the docs here
| ADBC_EXPORT | ||
| AdbcStatusCode AdbcConnectionGetMetadataCollection( | ||
| struct AdbcConnection* connection, const char* collection, size_t num_filters, | ||
| const char** filters, struct ArrowArrayStream* out, struct AdbcError* error); |
There was a problem hiding this comment.
Did I miss it or does the docs not define the semantics of the filters in terms of prefix, a LIKE pattern, regex, etc.?
There was a problem hiding this comment.
Er, the point of this is that each collection can define its own filters...see the collection definitions.
| /// | db_schema_name | utf8 | | | ||
| /// | db_schema_remarks | utf8 | (1) | | ||
| /// | ||
| /// (R) This field is run-length encoded by default; it can be disabled via |
There was a problem hiding this comment.
Why REE instead of dictionary encoded (which is more widely supported among arrow implementations)?
There was a problem hiding this comment.
I suppose I don't like the potential complexity around having to handle replacement/delta dictionaries (which I think are also not quite fully supported in all cases), and the statefulness that dictionaries bring (REE data is always fully decodable from a single batch).
I agree that the scoping of the option feels a bit awkward. @paleolimbot do you mean that it's a flat list of alternating
I suppose the separator works but I dislike this sort of in-band encoding...that said we could also figure out some convention to encode multiple variadic arguments into a parameter list (e.g. terminating a variadic argument with a NULL element)
The new collection definitions don't nest the data anymore, to hopefully avoid this. |
|
Also, I think encoding filter arguments is good enough. At least with current APIs, essentially all filter arguments are strings anyways. |
Yes, like |
|
Another thought: what if we just place this as a statement-level function? Even if it's not associated with a statement per se this lets us get access to existing functions like RequestSchema and lets us scope SetOption without "affecting" the entire connection. |
|
Drafted that at #4694. I don't love that API either but I think it is more consistent than this one. |
|
I'll close this in favor of the reworked proposal at #4694. |
Related:
For consideration:
Closes #4400.