File: dbapi2.rst

package info (click to toggle)
python-jpype 1.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,984 kB
  • sloc: python: 18,767; cpp: 17,931; java: 8,448; xml: 1,305; makefile: 154; sh: 35
file content (435 lines) | stat: -rw-r--r-- 19,895 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
##################
JPype DBAPI2 Guide
##################

`Introduction`
==============

One common use of JPype is to provide access to databases used JDBC.  The JDBC
API is well established, very capable, and supports most databases.
JPype can be used to access JDBC both directly or through the use of the Python
DBAPI2 as layed (see PEP-0249_).  Unfortunately, the Python API leaves a lot of
behaviors undefined.  

The JPype dbapi2 module provides our implementation of this Python API.
Normally the Python API has to deal with two different type systems, Python
and SQL.  When using JDBC, we have the added complexity that Java types are
used to communicate with the driver.  We have introduced concepts appropriate
to handle this addition complexity.


`Module Interface`
==================

`Constructors`
--------------

Access to the database is made available through connection
objects. The module provides the following constructor for connections:

.. _connect:

.. autofunction:: jpype.dbapi2.connect

Globals
-------

JPype dbapi2 defines several globals that define the module behavior.
These values are constants.

.. _apilevel:

`apilevel`_
    The apilevel for the module is "``2.0``".  


.. _threadsafety:

`threadsafety`_
    The threadsafety level is 2 meaning "Threads may share the module and
    connections".  But the actual threading level depends on the driver
    implementation that JDBC is connected to.  Connections for many databases
    are synchronized so they can be shared, but threads must execute statement
    in series.  Connections in the module are implemented in Python and 
    have per object resources that cannot be shared.  Attempting to use a
    connection with a thread other than the thread that created it will
    raise an ``Error``.

    Sharing in the above context means that two threads may use a resource
    without wrapping it using a mutex semaphore to implement resource locking.
    Note that you cannot always make external resources thread safe by managing
    access using a mutex: the resource may rely on global variables or other
    external sources that are beyond your control.


.. _paramstyle:

`paramstyle`_
    The parameter style for JPype dbapi2 module is ``qmark``

    ============ ==============================================================
    paramstyle   Meaning
    ============ ==============================================================
    ``qmark``    Question mark style, e.g. ``...WHERE name=?``
    ============ ==============================================================


Exceptions
----------

The dbapi2 module exposes error information using the following
exceptions:

.. autoclass:: jpype.dbapi2.Warning
.. autoclass:: jpype.dbapi2.Error
.. autoclass:: jpype.dbapi2.InterfaceError
.. autoclass:: jpype.dbapi2.DatabaseError
.. autoclass:: jpype.dbapi2.DataError
.. autoclass:: jpype.dbapi2.OperationalError
.. autoclass:: jpype.dbapi2.IntegrityError
.. autoclass:: jpype.dbapi2.InternalError
.. autoclass:: jpype.dbapi2.ProgrammingError
.. autoclass:: jpype.dbapi2.NotSupportedError

Python exceptions are more fine grain than JDBC exceptions.  Whereever possible
we have redirected the Java exception to the nearest Python exception.  However,
there are cases in which the Java exception may appear.  Those exceptions
inherit from `:py:class:jpype.dbapi2.Error`.  This is the exception inheritance layout::

    Exception
    |__Warning
    |__Error
       |__InterfaceError
       |__java.sql.SQLError
       |  |__java.sql.BatchUpdateException
       |  |__java.sql.RowSetWarning
       |  |__java.sql.SerialException
       |  |__java.sql.SQLClientInfoException
       |  |__java.sql.SQLNonTransientException
       |  |__java.sql.SQLRecoverableException
       |  |__java.sql.SQLTransientException
       |  |__java.sql.SQLWarning
       |  |__java.sql.SyncFactoryException
       |  |__java.sql.SyncProviderException
       |
       |__DatabaseError
          |__DataError
          |__OperationalError
          |__IntegrityError
          |__InternalError
          |__ProgrammingError
          |__NotSupportedError



Type Access
===========

JPype dbapi2 provides two different maps which serve to convert data
between Python and SQL types.  When setting parameters and fetching 
results, Java types are used.  The connection provides to maps for converting
the types of parameters.  An `adapter <adapters_>`_ is used to translate from a Python
type into a Java type when setting a parameter.  Once a result is produced,
a `converter <converters_>`_ can be used to translate the Java type back into a Python type.

There are two lookup functions that select the behavior to decide how a column or
parameter should be treated.  These are `getters`_ and `setters`_.

.. _adapters:

adapters_
---------

Whenever a Python type is passed to a statement, it must first be converted
to the appropriate Java type.  This can be accomplished in a few ways.  The
user can manually convert to the correct type by constructing a Java object or
applying the JPype casting operator.  Some Java types have built in implicit
conversions from the corresponding type.  For all other conversions, an adapter.
An adapter is defined as a type to convert from and a conversion function which 
takes a single argument that returns a Java object.

The adapter maps are stored in the connection.  The adapter map can be
supplied when calling `connect`_ , or added to the map later
through the `adapters <connection.adapters_>`_ property. 


.. _setters:

setters_
--------

A setter transfers the Java type into a SQL parameter.  There are multiple
types can an individual parameter may accept.  The type of setter is determined
by the JDBC type.  Each individual JDBC type can have its own setter.  Not
every database supports the same setter.  There is a default setter may that
would work for most purposes.  Setters can also be set individually using 
the ``types`` argument to the ``.execute*()`` methods.  The setter is a 
function which processes the database metadata into a type.

Setters can supplied as a map to `connect`_ or by accessing
the `setter <connection.setters_>`_ property on a Connection.

.. autofunction:: jpype.dbapi2.SETTERS_BY_META
.. autofunction:: jpype.dbapi2.SETTERS_BY_TYPE

.. _converters:

converters_
-----------

When a result is fetched the database, it is returned as Jave type.  This Java
type then has a converter applied.  Converters are stored in a map holding the 
type as key and a converter function that takes one argument and returns the desired type.
The default converter map will convert all types to Python.  This can be 
disabled by setting the converters to ``None``.

The converter map can be passed in to the `connect`_ function, or set on the
Connection using the `converters <connection.converters_>`_ property.  It
can be supplied as a list or a map to the ``.fetch*()`` methods.

.. _getters:

getters_
--------

JDBA provides more than one way to access data returned from a result.
In the native JDBC, each executed statement returns a result set which 
acts as a cursor for the statement.  It is possible to access each 
column using a different get method.  The default map will attempt
to fetch according to the most general type.  The getter is a configurable
function that uses the metadata to find the most appropriate type.

.. autofunction:: jpype.dbapi2.GETTERS_BY_TYPE
.. autofunction:: jpype.dbapi2.GETTERS_BY_NAME

.. _Connection:

`Connection Objects`_
=====================

A Connection object can be created using the using `connect`_ function.  Once a
connection is established the resulting Connection contains the following.

.. autoclass:: jpype.dbapi2.Connection
  :members:

.. _Cursor:

`Cursor Objects`_
=================

These objects represent a database cursor, which is used to manage the
context of a fetch operation. Cursors created from the same connection
are not isolated, *i.e.*, any changes done to the database by a cursor
are immediately visible by the other cursors.  Cursors created from
different connections may or may not be isolated, depending on how the
transaction support is implemented (see also the connection's
`rollback <connection.rollback_>`_ and `commit <connection.commit_>`_ methods).

.. autoclass:: jpype.dbapi2.Cursor
  :members:


Cursors can act as an iterator.  So to get the contents of table one
could use code like:

.. code-block:: python

   with connection.cursor() as cur:
       cur.execute("select * from table")
       for row in cur:
          print(row)

`SQL Type Constructors`
=======================

Many databases need to have the input in a particular format for
binding to an operation's input parameters.  For example, if an input
is destined for a ``DATE`` column, then it must be bound to the
database in a particular string format.  Similar problems exist for
"Row ID" columns or large binary items (e.g. blobs or ``RAW``
columns).  This presents problems for Python since the parameters to
the `.execute*()` method are untyped.  When the database module sees
a Python string object, it doesn't know if it should be bound as a
simple `CHAR` column, as a raw `BINARY` item, or as a `DATE`.

This is less of a problem in JPype dbapi2 than in a typically 
dbapi driver as we have strong typing backing the connection,
but we are still required to supply methods to construct individual
SQL types.  These functions are:

.. autofunction::  jpype.dbapi2.Date
.. autofunction::  jpype.dbapi2.Time
.. autofunction::  jpype.dbapi2.Timestamp
.. autofunction::  jpype.dbapi2.DateFromTicks
.. autofunction::  jpype.dbapi2.TimeFromTicks
.. autofunction::  jpype.dbapi2.TimestampFromTicks
.. autofunction::  jpype.dbapi2.Binary

For the most part these constructors are largely redundant as 
adapters can provide the same functionality and Java types
can directly use to communicate type information.

.. `JDBC Types`

`JDBC Types`_
=============

In the Python DBAPI2, the SQL type system is normally reduced to a subset
of the SQL types by mapping multiple types together for example ``STRING``
covers the types `STRING`, `CHAR`, `NCHAR` , `NVARCHAR` , `VARCHAR`, 
and `OTHER`.  JPype dbapi2 supports both the recommended Python types and
the fine grain JDBC types.  Each type is represented by an object 
of type JBDCType.

.. autoclass:: jpype.dbapi2.JDBCType
   :members:

The following types are defined with the correspond Python grouping, the
default setter, getter, and Python type.  For types that support more than
one type of getter, the special getter can be applied as the converter for
the type.  For example, the defaulf configuration has ``getter[BLOB] = BINARY.get``,
to get the Blob type use ``getter[BLOB] = BLOB.get`` or specify it when
calling `use <cursor.use_>`_.


======== ======================== =================== ============== ================= ===============
Group    JDBC Type                Default Getter      Default Setter PyTypes           Special Getter 
======== ======================== =================== ============== ================= ===============
DATE     DATE                     getDate             setDate        datetime.datetime                
DATETIME TIMESTAMP                getTimestamp        setTimestamp   datetime.datetime                
TIME     TIME                     getTime             setTime        datetime.datetime                
-------- ------------------------ ------------------- -------------- ----------------- ---------------
DECIMAL  DECIMAL                  getBigDecimal       setBigDecimal  decimal.Decimal                  
DECIMAL  NUMERIC                  getBigDecimal       setBigDecimal  decimal.Decimal                  
-------- ------------------------ ------------------- -------------- ----------------- ---------------
FLOAT    FLOAT                    getDouble           setDouble      float                            
FLOAT    DOUBLE                   getDouble           getDouble      float                            
FLOAT    REAL                     getFloat            setFloat       float                            
-------- ------------------------ ------------------- -------------- ----------------- ---------------
NUMBER   BOOLEAN                  getBoolean          setBoolean     bool                             
NUMBER   BIT                      getBoolean          setBoolean     bool                             
NUMBER   TINYINT  (0..255)        getShort            setShort       int                              
NUMBER   SMALLINT (-2^15..2^15)   getShort            getShort       int                              
NUMBER   INTEGER  (-2^31..2^31)   getInt              getInt         int                              
NUMBER   BIGINT   (-2^63..2^63)   getLong             getLong        int                              
-------- ------------------------ ------------------- -------------- ----------------- ---------------
BINARY   BINARY                   getBytes            setBytes       bytes                            
BINARY   BLOB                     getBytes            setBytes       bytes             getBlob        
BINARY   LONGVARBINARY            getBytes            setBytes       bytes                            
BINARY   VARBINARY                getBytes            setBytes       bytes                            
-------- ------------------------ ------------------- -------------- ----------------- ---------------
TEXT     CLOB                     getString           setString      str               getClob        
TEXT     LONGNVARCHAR             getString           setString      str                              
TEXT     LONGVARCHAR              getString           setString      str                              
TEXT     NCLOB                    getString           setString      str               getNClob       
TEXT     SQLXML                   getString           setString      str               getSQLXML      
-------- ------------------------ ------------------- -------------- ----------------- ---------------
STRING   NVARCHAR                 getString           setString      str                              
STRING   CHAR                     getString           setString      str                              
STRING   NCHAR                    getString           setString      str                              
STRING   VARCHAR                  getString           setString      str                              
-------- ------------------------ ------------------- -------------- ----------------- ---------------
         ARRAY                    getObject                                            getArray       
         OBJECT                   getObject                                            getObject      
         NULL                     getObject                                            getObject      
         REF                      getObject                                            getRef         
         ROWID                    getObject                                            getRowId       
         RESULTSET                getObject                                            getObject      
         TIME_WITH_TIMEZONE       getObject                                            getTime        
         TIMESTAMP_WITH_TIMEZONE  getObject                                            getTimeStamp   
-------- ------------------------ ------------------- -------------- ----------------- ---------------
   *     ASCII_STREAM             getAsciiStream                                                      
   *     BINARY_STREAM            getBinaryStream                                                     
   *     CHARACTER_STREAM         getCharacterStream                                                  
   *     ASCII_STREAM             getAsciiStream                                                      
   *     BINARY_STREAM            getBinaryStream                                                     
   *     CHARACTER_STREAM         getCharacterStream                                                  
   *     NCHARACTER_STREAM        getNCharacterStream                                                 
   *     URL                      getURL                                                              
======== ======================== =================== ============== ================= ===============

Some of these types never correspond to a SQL type but are used only to specify
getters and setters for a particular parameter or column.

Other
-----

The default getter will attempt to look for the column type by name if the type is OTHER.
This allows for user defined types to be added if supported by the database.

User defined types
------------------

A user can declare a new type using ``JDBCType``.  The arguments are the name of 
new type which must match a SQL typename.  Use ``typeinfo`` on the connection to 
get the list of available types.

It may necessary to define a custom getter function which defining a new type
so that the custom return type accurately reflects the column type.

.. code-block:: python

   class JSONType(dbapi2.JDBCType):
      def get(self, *args):
          rc = JDBCType.get(self, *args)
          # Custom return converter here
          return rc
   JSON = JSONType("JSON")


Interactions with prepared statements
-------------------------------------

Certain calls can be problematic for dbapi2 depending on driver.  In
particular, SQL calls which invalidate the state of the connection will issue
an exception when the connection is used.   In HSQLDB the statement
``cur.execute('shutdown')`` invalidates the connection which when the statement
is then automatically closed will then produce an exception.

This exception is due to a conflict between dbapi2, Java, and HSQLDB
specifications.  Dbapi2 requires that statements be executed as prepared
statements, Java requires that closing a statement yields no action if the
connection is already closed, and HSQLBD sets the ``isValid`` to false but not
``isClosed``.  Thus executing a shutdown through dbapi2 would be expected to
close the prepared statement on an invalid connection resulting in an error.

We can address these sort of driver specific behaviors by applying a customizer
to the Java class to add additional behaviors.

.. code-block:: python

        @jpype.JImplementationFor("java.sql.PreparedStatement")
        class MyStatement(object):
            @jpype.JOverride(sticky=True, rename='_close')
            def close(self):
                if not self.getConnection().isValid(100):
                     return
                return self._close()

Alternatively we can access the ``java.sql.Connection`` directly and call the
shutdown routine using an unprepared statement.  Though that would require
accessing private fields.


Conclusion
==========

This wraps up the JPype dbapi2 module.  Because JDBC supports many different
dataase drivers, not every behavior is defined on every driver.  Consult the
driver specific information to determine what is available.  

The dbapi2 does not fully cover all of the capabilities of the JDBC driver.  To
access functions that are not defined in DBAPI2, the JDBC native objects can 
be accessed on both the connection and the cursor objects.

.. _PEP-0249: https://www.python.org/dev/peps/pep-0249/

.. _connection.rollback: #jpype.dbapi2.Connection.rollback
.. _connection.commit: #jpype.dbapi2.Connection.commit
.. _connection.adapters: #jpype.dbapi2.JDBCType.adapters
.. _connection.setters: #jpype.dbapi2.JDBCType.setters
.. _connection.converters: #jpype.dbapi2.JDBCType.converters
.. _cursor.use: #jpype.dbapi2.Cursor.use
.. _cursor.description: #jpype.dbapi2.Cursor.description
.. _jdbctype.adapters: #jpype.dbapi2.Connection.adapters