Skip to content

Commit 569d5f0

Browse files
author
James William Pye
committed
Add a "DriverError" to pg.exc.
This new exception is conceptually equivalent to DB-API's InterfaceError and is used in the DB-API wrapper. Add DriverWarning as well.
1 parent 80fab63 commit 569d5f0

3 files changed

Lines changed: 53 additions & 24 deletions

File tree

postgresql/driver/dbapi20.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# http://python.projects.postgresql.org
44
##
55
"""
6-
DB-API 2.0 conforming interface using postgresql.driver
6+
DB-API 2.0 conforming interface using postgresql.driver.
77
"""
88
threadsafety = 1
99
paramstyle = 'pyformat'
@@ -19,9 +19,8 @@
1919
ICVError as IntegrityError, \
2020
SEARVError as ProgrammingError, \
2121
IRError as OperationalError, \
22+
DriverError as InterfaceError, \
2223
Warning
23-
class InterfaceError(Error):
24-
pass
2524
DatabaseError = Error
2625
class NotSupportedError(DatabaseError):
2726
pass
@@ -192,8 +191,8 @@ class Connection(object):
192191
ICVError as IntegrityError, \
193192
SEARVError as ProgrammingError, \
194193
IRError as OperationalError, \
194+
DriverError as InterfaceError, \
195195
Warning
196-
InterfaceError = InterfaceError
197196
DatabaseError = DatabaseError
198197
NotSupportedError = NotSupportedError
199198

@@ -218,8 +217,7 @@ def rollback(self):
218217
def connect(**kw):
219218
"""
220219
Create a DB-API connection using the given parameters.
221-
222-
See the `Connecting` section in the documentation for more information about
223-
suitable parameters.
224220
"""
225-
return Connection(pg_driver.connect(**kw))
221+
pgapi = pg_driver.connect(**kw)
222+
dbapi = Connection(pgapi)
223+
return dbapi

postgresql/driver/pq3.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,10 @@ def write(self, copylines : [b'copy_line']):
479479
# scrollable cursors and server declared cursors. (0 is disabled)
480480
##
481481
# Prior, it was suspected that these different cases would indicate the need
482-
# for sub-classing, but the amount of overlapping functionality caused the
483-
# integration. For instance, in the case of '1', if query discovery is
484-
# possible, the restart() method is available and may change how the cursor
485-
# is treated after the restart.
482+
# for sub-classing, but the amount of overlapping functionality and dynamic
483+
# decisions caused the integration. For instance, in the case of '1', if
484+
# query discovery is possible, the restart() method may be available and may
485+
# change how the cursor is treated after the restart.
486486
#
487487
class Cursor(pg_api.Cursor):
488488
"""
@@ -505,10 +505,11 @@ class Cursor(pg_api.Cursor):
505505
with_scroll = None
506506
insensitive = None
507507

508-
_output_io = None
509508
_output = None
509+
_output_io = None
510510
_output_formats = None
511511
_output_attmap = None
512+
512513
_cid = -1
513514
_state = None
514515
_cursor_type = None
@@ -533,6 +534,10 @@ def from_query(
533534
# If the cursor is not scrollable, and fetchcount
534535
# was not supplied, set it as the default fetchcount.
535536
if not with_scroll and fetchcount is None:
537+
# This restriction on scroll was set to insure
538+
# any possible needed consistency with the cursor position
539+
# on the backend.
540+
##
536541
fetchcount = typ.default_fetchcount
537542
c.__init__(ID(c), query.connection, fetchcount = fetchcount)
538543
return c
@@ -1547,9 +1552,9 @@ def __init__(self, connection):
15471552
self.isolation = None
15481553
self.mode = None
15491554
self.gid = None
1550-
1555+
15511556
def ife_snapshot_text(self):
1552-
return "Transaction"
1557+
return "[level: " + str(self._level) + "]"
15531558

15541559
@property
15551560
def failed(self):
@@ -1572,16 +1577,12 @@ def prepared(self):
15721577

15731578
def commit_prepared(self, gid):
15741579
self.connection.execute(
1575-
"COMMIT PREPARED '{1}'".format(
1576-
gid.replace("'", "''")
1577-
)
1580+
"COMMIT PREPARED '" + gid.replace("'", "''") + "'"
15781581
)
15791582

15801583
def rollback_prepared(self, gid):
15811584
self.connection.execute(
1582-
"ROLLBACK PREPARED '{1}'".format(
1583-
gid.replace("'", "''")
1584-
)
1585+
"ROLLBACK PREPARED '" + gid.replace("'", "''") + "'"
15851586
)
15861587

15871588
def _execute(self, qstring, adjustment):
@@ -1637,7 +1638,7 @@ def _commit_string(self, level):
16371638
else:
16381639
return "PREPARE TRANSACTION '" + self.gid.replace("'", "''") + "'"
16391640
else:
1640-
return 'RELEASE "xact(%d)"' %(level - 1,)
1641+
return 'RELEASE "xact(' + str(level - 1) + ')"'
16411642

16421643
def commit(self):
16431644
self._execute(self._commit_string(self._level), -1)
@@ -2455,7 +2456,12 @@ def socket_factory_sequence(self) -> [collections.Callable]:
24552456
def socket_secure(self, socket):
24562457
"""
24572458
Given a socket produced using one of the callables created in the
2458-
`socket_factory_sequence`, secure it using SSL.
2459+
`socket_factory_sequence`, secure it using SSL with the SSL parameters:
2460+
2461+
- sslcrtfile
2462+
- sslkeyfile
2463+
- sslrootcrtfile
2464+
- sslrootcrlfile
24592465
"""
24602466

24612467
def __init__(self,
@@ -2481,6 +2487,12 @@ def __init__(self,
24812487
self.sslrootcrtfile = sslrootcrtfile
24822488
self.sslrootcrlfile = sslrootcrlfile
24832489

2490+
if self.sslrootcrlfile is not None:
2491+
w = pg_exc.IgnoredClientParameterWarning(
2492+
"Certificate Revocation Lists are *not* checked."
2493+
)
2494+
self.ife_descend(w)
2495+
24842496
# Startup message parameters.
24852497
tnkw = {}
24862498
if self.settings:
@@ -2554,7 +2566,6 @@ def socket_secure(self, socket : socket.socket) -> ssl.SSLSocket:
25542566
certfile = self.sslcertfile,
25552567
ca_certs = self.sslrootcertfile,
25562568
)
2557-
# XXX: check revocation list?
25582569

25592570
class IP4(SocketConnector):
25602571
'Connector for establishing IPv4 connections'
@@ -2780,5 +2791,6 @@ def __init__(self):
27802791
def __new__(subtype):
27812792
# There is only one instance of postgresql.driver.pq3.
27822793
return implementation
2794+
# More of a formality than anything.
27832795
implementation = pg_api.Driver.__new__(Driver)
27842796
implementation.__init__()

postgresql/exceptions.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ class Warning(PythonMessage, Warning):
7272
code = '01000'
7373
ife_label = 'WARNING'
7474

75+
class DriverWarning(Warning):
76+
code = ''
77+
source = 'DRIVER'
78+
class IgnoredClientParameterWarning(DriverWarning):
79+
'Warn the user of a valid, but ignored parameter.'
80+
7581
class DeprecationWarning(Warning):
7682
code = '01P01'
7783
class DynamicResultSetsReturnedWarning(Warning):
@@ -109,6 +115,19 @@ def raise_exception(self, raise_from = None):
109115
else:
110116
raise self from raise_from
111117

118+
class DriverError(Error):
119+
"Errors originating in the driver's implementation."
120+
source = 'DRIVER'
121+
class OperationError(DriverError):
122+
"""
123+
An invalid operation on an interface element.
124+
125+
Usually this occurs in dynamically configured instances where the action is
126+
not actually valid for the, actual, finalized type.
127+
128+
For instance, calling the seek() method on a cursor who's query is a COPY.
129+
"""
130+
112131
##
113132
# Exceptions pertinent to cluster initialization and management
114133
##

0 commit comments

Comments
 (0)