blob: bbff7b9a1b30be0941dd395ac6390c439518c3f0 [file]
# 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.
# RECIPE CATEGORY: driver manager
# RECIPE KEYWORDS: dynamic driver loading
# RECIPE STARTS HERE
#: While the DB-API_ bindings are recommended for general use, the low-level
#: bindings are also available. These mostly mirror the ADBC C API directly.
#: They can be useful to opt out of some behaviors of the DB-API wrapper.
#:
#: .. _DB-API: https://peps.python.org/pep-0249/
import pyarrow
import adbc_driver_manager
import adbc_driver_sqlite
#: The driver packages do still have conveniences to create the root
#: :class:`AdbcDatabase <adbc_driver_manager.AdbcDatabase>` object.
db: adbc_driver_manager.AdbcDatabase = adbc_driver_sqlite.connect()
#: The database must then be wrapped in a :class:`AdbcConnection
#: <adbc_driver_manager.AdbcConnection>`. This is similar in scope to the
#: DB-API :class:`Connection <adbc_driver_manager.dbapi.Connection>` class.
conn = adbc_driver_manager.AdbcConnection(db)
#: Finally, we can wrap the connection in a :class:`AdbcStatement
#: <adbc_driver_manager.AdbcStatement>`, which corresponds roughly to the
#: DB-API :class:`Cursor <adbc_driver_manager.dbapi.Cursor>` class.
stmt = adbc_driver_manager.AdbcStatement(conn)
#: Now we can directly set the query. Unlike the regular DB-API bindings, this
#: will not prepare the statement. (Depending on the driver, this may or may
#: not make a difference, especially if executing the same query multiple
#: times.)
stmt.set_sql_query("SELECT 1 AS THEANSWER")
#: When we execute the query, we get an `Arrow C Stream Interface`_ handle
#: (wrapped as a PyCapsule_) that we need to import using a library like
#: PyArrow_.
#:
#: .. _Arrow C Stream Interface:
#: https://arrow.apache.org/docs/format/CStreamInterface.html
#: .. _PyArrow: https://pypi.org/project/pyarrow/
#: .. _PyCapsule: https://docs.python.org/3/c-api/capsule.html
handle, rowcount = stmt.execute_query()
#: The SQLite driver does not know the row count of the result set up front
#: (other drivers, like the PostgreSQL driver, may know).
assert rowcount == -1
#: We can use the PyArrow APIs to read the result.
reader = pyarrow.RecordBatchReader.from_stream(handle)
assert reader.schema == pyarrow.schema([("THEANSWER", "int64")])
#: Finally, we have to clean up all the objects. (They also support the
#: context manager protocol.)
stmt.close()
conn.close()
db.close()