-
Notifications
You must be signed in to change notification settings - Fork 194
feat: Spec multi-result-set API #3871
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
Changes from 6 commits
ed8252a
8ec1d95
6abbf86
133e895
52e646e
d88fccb
81d6a2b
ec8a174
e8173f3
0141a8f
77cf124
b9a6f52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -355,6 +355,15 @@ struct ADBC_EXPORT AdbcError { | |
| /// \since ADBC API revision 1.1.0 | ||
| #define ADBC_ERROR_1_1_0_SIZE (sizeof(struct AdbcError)) | ||
|
|
||
| /// \brief The size of the AdbcError structure in ADBC 1.2.0. | ||
| /// | ||
| /// Drivers written for ADBC 1.2.0 and later should never touch more than this | ||
| /// portion of an AdbcDriver struct when vendor_code is | ||
| /// ADBC_ERROR_VENDOR_CODE_PRIVATE_DATA. | ||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| #define ADBC_ERROR_1_2_0_SIZE (sizeof(struct AdbcError)) | ||
|
|
||
| /// \brief Extra key-value metadata for an error. | ||
| /// | ||
| /// The fields here are owned by the driver and should not be freed. The | ||
|
|
@@ -423,6 +432,14 @@ const struct AdbcError* AdbcErrorFromArrayStream(struct ArrowArrayStream* stream | |
| /// \since ADBC API revision 1.1.0 | ||
| #define ADBC_VERSION_1_1_0 1001000 | ||
|
|
||
| /// \brief ADBC revision 1.2.0 | ||
| /// | ||
| /// When passed to an AdbcDriverInitFunc(), the driver parameter must | ||
| /// point to an AdbcDriver. | ||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| #define ADBC_VERSION_1_2_0 1002000 | ||
|
|
||
| /// \brief Canonical option value for enabling an option. | ||
| /// | ||
| /// For use as the value in SetOption calls. | ||
|
|
@@ -525,6 +542,7 @@ const struct AdbcError* AdbcErrorFromArrayStream(struct ArrowArrayStream* stream | |
| /// \see AdbcConnectionGetInfo | ||
| /// \see ADBC_VERSION_1_0_0 | ||
| /// \see ADBC_VERSION_1_1_0 | ||
| /// \see ADBC_VERSION_1_2_0 | ||
| #define ADBC_INFO_DRIVER_ADBC_VERSION 103 | ||
|
|
||
| /// \brief Return metadata on catalogs, schemas, tables, and columns. | ||
|
|
@@ -973,6 +991,113 @@ struct AdbcPartitions { | |
|
|
||
| /// @} | ||
|
|
||
| /// \defgroup adbc-statement-multi Multiple Result Set Execution | ||
| /// Some databases support executing a statement that returns multiple | ||
| /// result sets. This section defines the API for working with such | ||
| /// statements and result sets. | ||
| /// @{ | ||
|
|
||
| /// \brief A struct for handling a potentially multi-result set execution | ||
| /// | ||
| /// This struct is populated by AdbcStatementExecuteMulti and can be used to iterate | ||
| /// through the result sets of the execution. The caller can use the NextResultSet or | ||
| /// NextResultSetPartitions functions on the AdbcResultSet struct to iterate through the | ||
| /// result sets. The caller is responsible for calling the release function when finished | ||
| /// with the result set. | ||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| struct ADBC_EXPORT AdbcResultSet { | ||
|
zeroshade marked this conversation as resolved.
Outdated
|
||
| /// \brief opaque implementation-defined state | ||
| void* private_data; | ||
|
zeroshade marked this conversation as resolved.
|
||
|
|
||
| /// \brief The associated driver | ||
| struct AdbcDriver* private_driver; | ||
| }; | ||
|
|
||
| /// \brief Release the AdbcResultSet and any associated resources. | ||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| /// | ||
| /// If all the result sets have not been completely consumed, then the driver | ||
| /// should cancel any remaining work if this is called. | ||
|
zeroshade marked this conversation as resolved.
|
||
| /// | ||
| /// \param[in] result_set The result set to release. | ||
| /// \param[out] error An optional location to return an error message if necessary. | ||
| /// | ||
| /// \return ADBC_STATUS_OK on success or an appropriate error code. | ||
| AdbcStatusCode AdbcResultSetRelease(struct AdbcResultSet* result_set, | ||
| struct AdbcError* error); | ||
|
|
||
| /// \brief Get the next result set from a multi-result-set execution. | ||
|
zeroshade marked this conversation as resolved.
Outdated
|
||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| /// | ||
| /// The AdbcResultSet must outlive the returned ArrowArrayStream. | ||
|
zeroshade marked this conversation as resolved.
Outdated
|
||
| /// | ||
| /// The driver can decide whether to allow fetching the next result set | ||
| /// as a single stream or as a set of partitions. If the driver does not | ||
| /// support fetching the next result set as a stream (indicating it should | ||
| /// be fetched as partitions), it should return ADBC_STATUS_NOT_IMPLEMENTED. | ||
| /// | ||
| /// To indicate that no additional result sets are available, this should return | ||
| /// ADBC_STATUS_OK and set the release callback on out to NULL. The expected | ||
| /// pattern is that after calling `StatementExecuteMulti`, the caller would | ||
| /// then call `NextResultSet` repeatedly until it returns ADBC_STATUS_OK and | ||
| /// sets the release callback to NULL, indicating that there are no more result sets. | ||
|
Comment on lines
+1043
to
+1044
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a state we haven't addressed is whether you can call Next while still reading the previous result set or not. I hazard many databases will not support concurrency, especially because the queries may depend on each other...
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we leave it up to a driver to determine whether it's allowed? (i.e. "A driver MAY invalidate the current result set when MultiResultSetNext is called") or should we explicitly state that it is invalidated when calling MultiResultSetNext and thus require that behavior? I personally lean towards the latter rather than the former for consistency, but it would prevent a driver from technically allowing it if it supports it. Thoughts?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can state MAY, and most code will then have to assume it will be invalidated; if you're coding to a specific driver release, then maybe you can make a stronger assumption. |
||
| /// It is not an error to repeatedly call `NextResultSet` after the last result set | ||
| /// has been reached; it should simply continue to return ADBC_STATUS_OK with a | ||
| /// NULL release callback. | ||
| /// | ||
| /// \param[in] result_set The result set struct to fetch the next result from. | ||
| /// \param[out] out The result stream to populate | ||
| /// \param[out] rows_affected The number of rows affected if known, else - | ||
| /// \param[out] error An optional location to return an error message if necessary. | ||
| /// | ||
| /// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver only supports fetching results | ||
| /// as partitions, ADBC_STATUS_INVALID_STATE if called at an inappropriate time, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When is "an inappropriate time"?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. artifact of the previous design. it no longer applies here give that we've decoupled everything by having these standalone functions on the separate MultiResultSet object |
||
| /// and ADBC_STATUS_OK (or an appropriate error code) otherwise. | ||
| AdbcStatusCode AdbcNextResultSet(struct AdbcResultSet* result_set, | ||
| struct ArrowArrayStream* out, int64_t* rows_affected, | ||
| struct AdbcError* error); | ||
|
|
||
| /// \brief Get the next result set from a multi-result-set execution as partitions. | ||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| /// | ||
| /// The AdbcResultSet must outlive the returned partitions. | ||
| /// | ||
| /// The driver can decide whether to allow fetching the next result set | ||
| /// as a single stream or as a set of partitions. If the driver does not | ||
| /// support fetching the next result set as partitions (indicating it should | ||
| /// be fetched as a stream), it should return ADBC_STATUS_NOT_IMPLEMENTED. | ||
| /// | ||
| /// To indicate that no additional result sets are available, this should return | ||
| /// ADBC_STATUS_OK and set the release callback on partitions to NULL. The expected | ||
| /// pattern is that after calling `StatementExecuteMulti`, the caller would | ||
| /// then call `NextResultSetPartitions` repeatedly until it returns ADBC_STATUS_OK and | ||
| /// sets the release callback to NULL, indicating that there are no more result sets. | ||
| /// It is not an error to repeatedly call `NextResultSetPartitions` after the last | ||
| /// result set has been reached; it should simply continue to return ADBC_STATUS_OK with | ||
| /// a NULL release callback. | ||
| /// | ||
| /// \param[in] result_set The result set struct to fetch the next result from. | ||
| /// \param[out] schema The schema of the result set to populate | ||
| /// \param[out] partitions The partitions to populate | ||
| /// \param[out] rows_affected The number of rows affected if known, else -1. Pass NULL | ||
| /// if the client does not want this information. | ||
| /// \param[out] error An optional location to return an error message if necessary. | ||
| /// | ||
| /// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver only supports fetching results | ||
| /// as a stream, ADBC_STATUS_INVALID_STATE if called at an inappropriate time, and | ||
| /// ADBC_STATUS_OK (or an appropriate error code) otherwise. | ||
| AdbcStatusCode AdbcNextResultSetPartitions(struct AdbcResultSet* result_set, | ||
| struct ArrowSchema* schema, | ||
| struct AdbcPartitions* partitions, | ||
| int64_t* rows_affected, | ||
| struct AdbcError* error); | ||
|
|
||
| /// @} | ||
|
|
||
| /// \defgroup adbc-driver Driver Initialization | ||
| /// | ||
| /// These functions are intended to help support integration between a | ||
|
|
@@ -1059,17 +1184,18 @@ struct ADBC_EXPORT AdbcDriver { | |
| /// the AdbcDriverInitFunc is greater than or equal to | ||
| /// ADBC_VERSION_1_1_0. | ||
| /// | ||
| /// For a 1.0.0 driver being loaded by a 1.1.0 driver manager: the | ||
| /// 1.1.0 manager will allocate the new, expanded AdbcDriver struct | ||
| /// and attempt to have the driver initialize it with | ||
| /// ADBC_VERSION_1_1_0. This must return an error, after which the | ||
| /// driver will try again with ADBC_VERSION_1_0_0. The driver must | ||
| /// not access the new fields, which will carry undefined values. | ||
| /// When a driver implementing an older spec is loaded by a newer | ||
| /// driver manager, the newer manager will allocate the new, expanded | ||
| /// AdbcDriver struct and attempt to have the driver initialize it with | ||
| /// the newer version. This must return an error, after which the driver | ||
| /// will try again with successively older versions all the way back to | ||
| /// ADBC_VERSION_1_0_0. The driver must not access the new fields, | ||
| /// which will carry undefined values. | ||
|
zeroshade marked this conversation as resolved.
Outdated
|
||
| /// | ||
| /// For a 1.1.0 driver being loaded by a 1.0.0 driver manager: the | ||
| /// 1.0.0 manager will allocate the old AdbcDriver struct and | ||
| /// attempt to have the driver initialize it with | ||
| /// ADBC_VERSION_1_0_0. The driver must not access the new fields, | ||
| /// When a driver implementing a newer spec is loaded by an older | ||
| /// driver manager, the older manager will allocate the old AdbcDriver | ||
| /// struct and attempt to have the driver initialize it with the | ||
| /// older version. The driver must not access the new fields, | ||
| /// and should initialize the old fields. | ||
| /// | ||
| /// @{ | ||
|
|
@@ -1135,6 +1261,40 @@ struct ADBC_EXPORT AdbcDriver { | |
| struct AdbcError*); | ||
|
|
||
| /// @} | ||
|
|
||
| /// \defgroup adbc-1.2.0 ADBC API Revision 1.2.0 | ||
| /// | ||
| /// Functions added in ADBC 1.2.0. For backwards compatibility, | ||
| /// these members must not be accessed unless the version passed to | ||
| /// the AdbcDriverInitFunc is greater than or equal to | ||
| /// ADBC_VERSION_1_2_0. | ||
| /// | ||
| /// When a driver implementing an older spec is loaded by a newer | ||
| /// driver manager, the newer manager will allocate the new, expanded | ||
| /// AdbcDriver struct and attempt to have the driver initialize it with | ||
| /// the newer version. This must return an error, after which the driver | ||
| /// will try again with successively older versions all the way back to | ||
| /// ADBC_VERSION_1_0_0. The driver must not access the new fields, | ||
| /// which will carry undefined values. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the manager populate them with functions that fail immediately?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not actually sure what this is trying to say, now that you point it out.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this is in line with the current behavior. No attempt is made to pre-populate with functions that fail immediately (likely to avoid having to create separate versions for every callback going forward). We currently leave these members undefined in the struct. If we want to change this behavior, I'd prefer we do it in a different PR, not this one.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably we should describe the user perspective and driver perspective separately. From the user perspective: the manager will return a fully populated struct, but some of the functions may fail with NOT_IMPLEMENTED. From the driver perspective: they should not access members outside of the version specified by the driver manager. (Though this is already required by the contract on the init func, and also you have no other way of knowing the size of the struct, nor do you know whether it's the driver manager or something else calling you.) I don't think we need to specify what exactly the driver manager does here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ping @zeroshade, I think we should at least avoid specifying exactly what the driver manager does here, just that the driver manager expects that if it gives the driver a particular version, it should not try to access any functions defined after that version.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How's the updated version? |
||
| /// | ||
| /// When a driver implementing a newer spec is loaded by an older | ||
| /// driver manager, the older manager will allocate the old AdbcDriver | ||
| /// struct and attempt to have the driver initialize it with the | ||
| /// older version. The driver must not access the new fields, | ||
| /// and should initialize the old fields. | ||
| /// | ||
| /// @{ | ||
|
|
||
| AdbcStatusCode (*NextResultSet)(struct AdbcResultSet*, struct ArrowArrayStream*, | ||
| int64_t*, struct AdbcError*); | ||
| AdbcStatusCode (*NextResultSetPartitions)(struct AdbcResultSet*, struct ArrowSchema*, | ||
| struct AdbcPartitions*, int64_t*, | ||
| struct AdbcError*); | ||
| AdbcStatusCode (*ResultSetRelease)(struct AdbcResultSet*, struct AdbcError*); | ||
| AdbcStatusCode (*StatementExecuteMulti)(struct AdbcStatement*, struct AdbcResultSet*, | ||
| struct AdbcError*); | ||
|
|
||
| /// @} | ||
| }; | ||
|
|
||
| /// \brief The size of the AdbcDriver structure in ADBC 1.0.0. | ||
|
|
@@ -1151,7 +1311,15 @@ struct ADBC_EXPORT AdbcDriver { | |
| /// ADBC_VERSION_1_1_0. | ||
| /// | ||
| /// \since ADBC API revision 1.1.0 | ||
| #define ADBC_DRIVER_1_1_0_SIZE (sizeof(struct AdbcDriver)) | ||
| #define ADBC_DRIVER_1_1_0_SIZE (offsetof(struct AdbcDriver, StatementExecuteMulti)) | ||
|
|
||
| /// \brief The size of the AdbcDriver structure in ADBC 1.2.0. | ||
| /// Drivers written for ADBC 1.2.0 and later should never touch more | ||
| /// than this portion of an AdbcDriver struct when given | ||
| /// ADBC_VERSION_1_2_0. | ||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| #define ADBC_DRIVER_1_2_0_SIZE (sizeof(struct AdbcDriver)) | ||
|
|
||
| /// @} | ||
|
|
||
|
|
@@ -2013,6 +2181,46 @@ AdbcStatusCode AdbcStatementExecuteQuery(struct AdbcStatement* statement, | |
| struct ArrowArrayStream* out, | ||
| int64_t* rows_affected, struct AdbcError* error); | ||
|
|
||
| /// \defgroup adbc-statement-multi Multiple Result Set Execution | ||
| /// Some databases support executing a statement that returns multiple | ||
| /// result sets. This section defines the API for working with such | ||
| /// statements and result sets. | ||
| /// @{ | ||
|
|
||
| /// \brief Execute a statement that potentially returns multiple result sets | ||
| /// | ||
| /// \since ADBC API revision 1.2.0 | ||
| /// | ||
| /// To execute a statement which might potentially return multiple result sets, | ||
| /// this can be called in place of AdbcStatementExecuteQuery if the driver supports it. | ||
| /// If supported, the driver will populate the AdbcResultSet structure with all | ||
| /// necessary information to iterate through the result sets. The caller can then | ||
| /// use the NextResultSet or NextResultSetPartitions functions on the AdbcResultSet | ||
| /// struct to iterate through the result sets. | ||
| /// | ||
| /// A driver MAY support executing this function while the previous result set is | ||
| /// still being consumed (i.e. before the previous ArrowArrayStream is released), but | ||
| /// this is not required. If the driver does not support this, it should return | ||
| /// ADBC_STATUS_INVALID_STATE if the previous result set is still active. | ||
| /// | ||
| /// A driver implementing this function must also implement the AdbcResultSet struct | ||
| /// and its associated functions. | ||
| /// | ||
| /// \param[in] statement The statement to execute. | ||
| /// \param[out] results The result set struct to populate with the results of the | ||
| /// execution. | ||
| /// \param[out] error An optional location to return an error message if necessary. | ||
| /// | ||
| /// \return ADBC_STATUS_NOT_IMPLEMENTED if the driver does not support multi-result set | ||
| /// execution, | ||
| /// and ADBC_STATUS_OK (or an appropriate error code) otherwise. | ||
| ADBC_EXPORT | ||
| AdbcStatusCode AdbcStatementExecuteMulti(struct AdbcStatement* statement, | ||
| struct AdbcResultSet* results, | ||
| struct AdbcError* error); | ||
|
|
||
| /// @} | ||
|
|
||
| /// \brief Get the schema of the result set of a query without | ||
| /// executing it. | ||
| /// | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.