Skip to content

feat(format): add generic metadata API - #4694

Open
lidavidm wants to merge 4 commits into
apache:spec-1.2.0from
lidavidm:gh-4400-sandbox
Open

feat(format): add generic metadata API#4694
lidavidm wants to merge 4 commits into
apache:spec-1.2.0from
lidavidm:gh-4400-sandbox

Conversation

@lidavidm

@lidavidm lidavidm commented Aug 17, 2026

Copy link
Copy Markdown
Member
  • Add a generic API for fetching metadata, modeled on ADO.NET's GetSchema
  • Define the standard metadata collections
  • Revert the current revisions to GetObjects in favor of not changing it

Related:

Closes #4400.

@lidavidm

Copy link
Copy Markdown
Member Author

I'm thinking we don't run-length-encode by default to simplify things further.

@CurtHagenlocher CurtHagenlocher left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Exciting! I've left a few comments and questions resulting from a first, casual review of the code.

/// |--------------------------|------------------------------|----------|
/// | collection_name | utf8 not null | |
/// | collection_description | utf8 | |
/// | collection_schema | extension<arrow.schema_json> | |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The proposal for this type seems to have stalled :(.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm talking to Kent, hopefully we can keep it going. Otherwise, I may propose an arrow.schema_ipc (even if that's a bit ugly)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Having it not be an extension type would probably make it simpler (when there's a JSON option, regular arrow.json I think would suffice, given that the name of the field contains schema). Until then binary is probably fine, and IPC, though sort of gross, at least doesn't require most implementations to write an additional parser.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Sort of off-topic then but I think it's kind of an implementation flaw that extension types are so hard to work with in many Arrow implementations 😅

Hmm, I suppose in practice the extension type is unnecessary for these fields. In theory I'm thinking that databow and other UIs around ADBC could use the extension type to know to render it in a more user-friendly way. In practice hardcoding it may be fine just because there's only a few cases/contexts where you're returning a schema in a table?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The rendering is a good point, although if you use a functional-style matcher you can detect the parent struct based on the field names and print the whole thing nicely (probably better than you'd get by strictly keying on extension name).


/// \brief The "meta" collection returns the available metadata collections.
///
/// | Field Name | Field Type | Comments |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need to say that the field types can be logical vs physical e.g. REE- or dictionary-encoded? Or is that always implicit? EDIT: I just saw that the consumer can explicitly ask for this kind of encoding if that's what they want. This doesn't necessarily imply that the producer is otherwise constrained to provide e.g. utf8 instead of utf8_view so I still think it would be value to express that explicitly if it's the case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think we should require drivers to stick to the declared type unless requested, I can clarify this

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated the text.

Comment thread c/include/arrow-adbc/adbc.h Outdated
Comment thread c/include/arrow-adbc/adbc.h Outdated
///
/// Drivers may add more fields at the end of standard schemas to reflect
/// vendor-specific metadata. Applications must access these using an offset
/// from the end of the schema and cannot assume that the index of the field

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we want to generally discourage access by ordinal?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I updated the text to specify access by name.

/// - ADBC_METADATA_FILTER_PATTERN_COLUMN
#define ADBC_METADATA_COLLECTION_ROUTINE_COLUMNS "routine_columns"

/// \brief The "namespaces" collection returns a level of namespaces defined

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These don't seem to interact much with the other metadata, or at least I'm having trouble seeing how they would. Do you have an example of a scenario where these matter, and how they would impact e.g. the listing of tables?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah, I can take this out...I was trying to explore how things might work for databases that don't follow the catalog-schema-table hierarchy, especially now that Iceberg/Iceberg REST Catalog has introduced arbitrarily-nested namespaces into systems. But as mentioned I think we would basically have to duplicate all the metadata collections to support that and it's not worth trying to make them both fit into the same collections.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Removed.

Comment thread c/include/arrow-adbc/adbc.h Outdated
Comment on lines +1141 to +1143
/// This is intended to replace AdbcConnectionGetObjects, but both APIs will
/// be supported for the time being. AdbcConnectionGetObjects may be
/// deprecated in a future revision.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Kind of burying the lede here. Do you think it would be helpful if this was right at the top of the defgroup doc? And maybe this PR could add a comment on AdbcConnectionGetObjects about the potential future for deprecation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To add: What should I do if I'm starting a new diver project? Implement both GetObjects and this? I'd think that's what we want so we could say it clearly here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think for someone coming in to ADBC, we don't need to draw the connection to GetObjects right away. I don't want to define things in terms of other things that will be deprecated. I'll clarify that we expect both to be implemented going forward for compatibility.

Comment thread c/include/arrow-adbc/adbc.h
Comment thread c/include/arrow-adbc/adbc.h Outdated
/// option wins.
///
/// The type is char*.
#define ADBC_METADATA_FILTER_PATERN_DB_SCHEMA "adbc.metadata.filter_pattern.schema"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Typo:

Suggested change
#define ADBC_METADATA_FILTER_PATERN_DB_SCHEMA "adbc.metadata.filter_pattern.schema"
#define ADBC_METADATA_FILTER_PATTERN_DB_SCHEMA "adbc.metadata.filter_pattern.schema"

Comment on lines +1110 to +1111
/// Drivers may also implement AdbcStatementRequestSchema to (1) request
/// different data types and (2) drop fields from the result. Drivers are not

@amoeba amoeba Aug 31, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hrm. The current doc comment on AdbcStatementRequestSchema says,

column reordering or changing the number of returned columns
is not a goal of this feature.

Could what say here in this PR be confusing given that?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

At the same time, I don't want to define a separate API. I'll clarify that RequestSchema isn't meant to stand in for projection of a database query's result set.

/// defined by the collection. For example, a client may request a list of
/// tables in the database, or a list of supported data types.
///
/// All drivers must implement a collection called "meta" (which is aliased to

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
/// All drivers must implement a collection called "meta" (which is aliased to
/// All drivers that implement this API must implement a collection called "meta" (which is aliased to

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Isn't that kind of implicit?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think so but I'll defer to you on the language.

Comment thread c/include/arrow-adbc/adbc.h Outdated
Comment on lines +1221 to +1222
/// \brief Filter the collection on the literal catalog name of the foreign
/// key.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure this is right but:

Suggested change
/// \brief Filter the collection on the literal catalog name of the foreign
/// key.
/// \brief Filter the collection on the literal schema name of the foreign
/// key.

Comment on lines +1215 to +1216
/// \brief Filter the collection on the literal catalog name of the foreign
/// key.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This was hard to understand for me as written. Does this option let me filter to tables that are referenced by a table whose name I provide?

My confusion goes for this and the other options related to foreign keys. Maybe we mean something more like,

Filter the collection on the literal catalog name of the referencing table.

NB: I didn't catch this on my first read through but gpt-5.6-sol flagged it and I found I wasn't able to explain it one way or the other.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The way I understood it, I thought it was an option to filter by external catalogs that are non-native (i.e foreign) to the platform. For example external Iceberg catalogs in Databricks, reading AWS Glue from Snowflake etc.

Comment thread c/include/arrow-adbc/adbc.h Outdated
/// | Field Name | Field Type | Comments |
/// |--------------------------|------------------------------|----------|
/// | collection_name | utf8 not null | |
/// | collection_description | utf8 | |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minor: As a driver author, I'm not sure I'd know what to put in here.

Comment thread c/include/arrow-adbc/adbc.h Outdated
Comment on lines +1293 to +1294
/// | filter_description | utf8 | |
/// | required | bool not null | |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How can the client act on collection_filters given this schema?

Say I query the meta collection and see it has a tables member and collection_filters is non-zero. Now I know I can list tables with a filter but how does collection_filters help me filter?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah, I should add more fields here now that we're not using positional arguments

@lidavidm lidavidm Sep 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated to be more like DriverGetOptionsList

/// use a vendor-specific prefix (e.g. `postgresql.`) to avoid conflicts with
/// future standardized collections. Drivers must not use the `adbc.` prefix.
///
/// Drivers may not necessarily accept filter options or other options before

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"May not necessarily accept" feels a bit ambiguous. It seems there's an implicit state machine here with regards to ADBC_METADATA_* options relative to ADBC_METADATA_COLLECTION both in the lifecycle and what the valid/invalid states should be. Should the spec make that more explicit?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, there's also bulk-ingest as part of the state machine.

I agree it needs to be made more explicit. If we're broadly OK with this approach to metadata, then I'll document it better.

/// fixed.
///
/// Drivers may implement collections beyond those defined by ADBC, but must
/// use a vendor-specific prefix (e.g. `postgresql.`) to avoid conflicts with

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

prefix field names with the vendor/driver name to differentiate them (e.g. 'POSTGRESQL:owner', not just 'owner').

vendor-specific prefix (e.g. postgresql.)

Could these two suggestions be made consistent? Or is this intentional?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'd say that most of the time we prefer prefix. in ADBC, but for whatever reason when the metadata is in Arrow field/schema metadata we've gone with PREFIX: (a convention started upstream). It does feel arbitrary, though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Comment thread c/include/arrow-adbc/adbc.h Outdated
/// database.
///
/// Some systems may not have the concept of catalogs, in which case this
/// collection should contain a single entry with an empty, non-null name.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

in which case this collection should contain a single entry with an empty, non-null name

This seems in tension with the purpose of the meta collection. It seems more consistent to have this be unimplemented, and to not return catalogs from meta if a database has no concept of a catalog.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I wonder what JDBC/ODBC drivers do in this case. I'll check.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

/// vendor-specific metadata. Applications must access these by name or using
/// an offset from the end of the schema and cannot assume that the index of
/// the field will remain stable. Hence, it is discouraged to access these
/// fields by ordinal as this is brittle. Drivers must add the fields at the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What's the value of mentioning offset-from-the-end here, as opposed to just specifying that field access must be by name?

It seems only stable for a single driver at a single version, since you'd need to know how many fields that driver appends and in what order within its block.

The paragraph also calls ordinal access brittle two sentences later, which seems to agree. Is there a scenario I'm missing?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's to clarify that you can't assume we won't add more fields in the spec, so if you do use an ordinal, then it needs to be from the end.

/// \brief Filter the collection on the literal routine name.
///
/// The type is char*.
#define ADBC_METADATA_FILTER_ROUTINE "adbc.metadata.filter.routine"

@serramatutu serramatutu Sep 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To make sure I understand this right: we're defining anything that can run as user-defined code as a "routine", so for example Snowflake has SQL UDFs, Snowpark UDFS (Python/JS) and Stored Procedures, and all of those would fall under the same "routine" category?

And the way to filter those out if I wanted only Python UDFs for example us by using the routine_types filter, correct? The values of those filters will be platform dependent, so for Snowflake it'd be sql_udf, python_udf, js_udf, stored_procedure. And each driver would need a list of platform-specific supported routine_types.

Is it worth to standardize common routine types, or do you think that's a little too much? For example stored_procedure is a pretty standard thing across a lot of different databases, so maybe it would be nice to have a shared key for all of those?

@serramatutu serramatutu Sep 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Now that I think of it, maybe it's too early to standardize that... Databricks alone has like 3 different kinds of Python UDFs. And the definition of a stored_procedure is fuzzy...

/// | constraint_deferrability | int16 | (4) |
/// | constraint_match_type | int16 | (5) |
///
/// 1. The 1-based index of the column pair within the foreign key (1 => first

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a reason why we're using 1-based indices?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In general, for most of your questions: we are directly copying JDBC/ODBC for these definitions for consistency.

/// Some drivers may support this to allow fetching a large metadata
/// collection in multiple calls. If the pagination token could not be used,
/// the driver should return an error.
#define ADBC_METADATA_OPTION_PAGINATION_TOKEN "adbc.metadata.pagination_token"

@serramatutu serramatutu Sep 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two things:

  1. I assume this is an "internal" key that will be used by the driver manager implementations to return stateful RecordBatchReaders that paginate under the hood when you pull a new batch, right? I think it would be nice if applications didn't need to worry about setting this option and keeping track of cursors across multiple calls. As an application I'd like to just consume record batches and the pagination cursors and state are handled by the driver manager.

  2. Is this intended to be used as both an input option as well as an output metadata key? If my understanding is correct, the lifecycle is:

  • The app (driver manager) would call AdbcConnectionGetInfo without a adbc.metadata.pagination_token (the first call), then the driver returns a record batch with a adbc.metadata.pagination_token in the schema metadata.
  • The next call, the app passes in the same adbc.metadata.pagination_token. I don't understand where, since AdbcConnectionGetInfo has no explicit support for options. Does this get set as a connection-level parameter that is set before the call and unset after it returns? Does this get added together with the filters?
  • This repeats until the last page, where the driver returns no adbc.metadata.pagination_token, signifying it's done listing.

I think it would be nice to document this lifecycle somewhere. Not sure the right place for it is here, though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

You don't need this in normal operation. The driver manager also isn't involved. This is meant to let you resume an operation across different fetches; a regular fetch should already paginate.

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.

6 participants