.. _openapi-protocol: OpenAPI Protocol **************** Some OpenAPI operations consist of calling a single function, such as :func:`!IIapi_connect` or :func:`IIapi_commit`. Others are quite complex and consist of a succession of function calls. Complex operations require the correct sequence of function calls to move the OpenAPI through a series of states. Sometimes the OpenAPI will be in a state where there is only one permissible function that can be called next. Sometimes there may be a limited choice of functions that can be called next. Sometimes the same function can be called repeatedly. The acceptable sequences of function calls making up a complex operation implement a protocol. There is a protocol for executing an SQL statement. There is a protocol for controlling and fetching from a cursor. There is another protocol for bulk copying data. And another for calling a prepared query, and more. The various protocols are described in `Accessing a DBMS Using SQL `_ in the *OpenAPI User Guide*. .. WARNING:: Making an unexpected OpenAPI function call while a protocol is in progress will at best cause an error that must be detected and recovered. At worst the application will "hang" and it can be very difficult to discover why without good error handling. (Refer to :ref:`debugging` for useful techniques.) .. TIP:: If a protocol must be abandoned use :func:`IIapi_cancel` and :func:`IIapi_close` to terminate it gracefully. When using ``pyngres.asyncio`` to run multiple concurrent tasks with the same connection, take care to ensure complex protocols have sole use of the connection until they complete. This can be accomplished using an :attr:`!asyncio.Lock` as a mutex on the DBMS connection. See :ref:`dbevent-example` for an example. Concurrent tasks can safely use the OpenAPI at the same time if each is using its own DBMS connection.