blob: d7cfbae3185cfcb306862b18eb087b5cc4967553 [file] [log] [blame]
.. Licensed to the Apache Software Foundation (ASF) under one
.. or more contributor license agreements. See the NOTICE file
.. distributed with this work for additional information
.. regarding copyright ownership. The ASF licenses this file
.. to you under the Apache License, Version 2.0 (the
.. "License"); you may not use this file except in compliance
.. with the License. You may obtain a copy of the License at
..
.. http://www.apache.org/licenses/LICENSE-2.0
..
.. Unless required by applicable law or agreed to in writing,
.. software distributed under the License is distributed on an
.. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
.. KIND, either express or implied. See the License for the
.. specific language governing permissions and limitations
.. under the License.
=============================
Concurrency and Thread Safety
=============================
In general, objects allow serialized access from multiple threads: one
thread may make a call, and once finished, another thread may make a
call. They do not allow concurrent access from multiple threads.
Somewhat related is the question of overlapping/concurrent execution
of multi-step operations, from a single thread or multiple threads.
For example, two AdbcStatement objects can be created from the same
AdbcConnection:
.. code-block:: c
struct AdbcStatement stmt1;
struct AdbcStatement stmt2;
struct ArrowArrayStream out1;
struct ArrowArrayStream out2;
/* Ignoring error handling for brevity */
AdbcStatementNew(&conn, &stmt1, NULL);
AdbcStatementNew(&conn, &stmt2, NULL);
AdbcStatementSetSqlQuery(&stmt1, "SELECT * FROM a", NULL);
AdbcStatementSetSqlQuery(&stmt2, "SELECT * FROM b", NULL);
AdbcStatementExecuteQuery(&stmt1, &out1, NULL, NULL);
AdbcStatementExecuteQuery(&stmt2, &out2, NULL, NULL);
/* What happens to the result set of stmt1? */
What happens if the client application calls
:cpp:func:`AdbcStatementExecuteQuery` on ``stmt1``, then on ``stmt2``,
without reading the result set of ``stmt1``? Some existing client
libraries/protocols, like libpq, don't support concurrent execution of
queries from a single connection. So the driver would have to
either 1) buffer all results into memory during the first ``Execute``
(or otherwise allow the program to continue reading the first result
set), 2) issue an error on the second ``Execute``, or 3) invalidate
the first statement's result set on the second ``Execute``.
In this case, ADBC allows drivers to choose 1) or 2). If possible and
reasonable, the driver should allow concurrent execution, whether
because the underlying protocol is designed for it or by buffering
result sets. But the driver is allowed to error if it is not possible
to support it.
Another use case is having a single statement, but executing it
multiple times and reading the result sets concurrently. A client
might desire to do this with a prepared statement, for instance:
.. code-block:: c
/* Ignoring error handling for brevity */
struct AdbcStatement stmt;
AdbcStatementNew(&conn, &stmt, NULL);
AdbcStatementSetSqlQuery(&stmt, "SELECT * FROM a WHERE foo > ?", NULL);
AdbcStatementPrepare(&stmt, NULL);
struct ArrowArrayStream stream;
AdbcStatementBind(&stmt, &array1, &schema, NULL);
AdbcStatementExecuteQuery(&stmt, &stream, NULL, NULL);
/* Spawn a thread to process `stream` */
struct ArrowArrayStream stream2;
AdbcStatementBind(&stmt, &array2, &schema, NULL);
AdbcStatementExecuteQuery(&stmt, &stream2, NULL, NULL);
/* What happens to `stream` here? */
ADBC chooses to disallow this (specifically: the second call to
``Execute`` must invalidate the result set of the first call), in line
with existing APIs that generally do not support 'overlapping' usage
of a single prepared statement in this way.